Tema 2. A Game of Scrabble

  • Data publicării: 30.11.2020
  • Deadline soft: 20.12.2020
  • Deadline hard: 20.12.2020

Actualizări:

  • 30.11.2020: modificat arhiva astfel incat tema sa poata fi compilata si pe OSX (MacOS);
  • 1.12.2020: reparat testele pt task-urile 5 si bonus;
  • 7.12.2020: reparat testele pt task-urile 5 si bonus v2;
  • 14.12.2020: adaugat flag ”-lm” in Makefile

Scopul temei:

  • utilizarea și lucrul cu șiruri de caractere;
  • înțelegerea unui joc și implementarea acestuia în limbajul de programare C

Introducere

Tema se bazeaza pe o forma a jocului de Scrabble in care va trebui sa folositi in mod special matrici si functii pentru prelucrarea sirurilor de caractere. Scopul final este implementarea completa a jocului astfel incat doi participanti (programul vostru impotriva checker-ului) sa poata sa joace alternativ si sa se determine un castigator.

Descriere

Jocul are la baza doua table de joc pastrate sub forma unor matrici patratice de dimensiune 15 x 15. O tabla (matrice) va pastra cuvintele “jucate” de cei doi jucatori pe parcursul jocului, in timp ce cealalta tabla va fi folosita pentru a marca casute ce ofera punctaj bonus.

Pentru claritate, vom folosi termenul de tabla de joc pentru a ne referi la matricea care stocheaza cuvinte si tabla de bonusuri pentru matricea care va stoca pozitiile ce ofera puncte bonus in joc.

Tabla de joc

Tabla de joc va contine cuvinte atat pe lungime, cat si pe latime. Fiecare casuta din matrice va stoca un singur caracter dintr-un cuvant sau caracterul ‘.’ daca este goala.

Initial veti avea o matrice de caractere cu dimensiunea 15 x 15 in care fiecare element din matrice va contine caracterul ‘.’ (deoarece nu avem niciun cuvant salvat la inceput). In exemplul de mai jos este o matrice in care au fost inserate mai multe cuvinte: “CAT”, “AIRPLANE”, “TRAIN”, “PROGRAM”, “LECTURE”.

Tabla de punctaj bonusuri

Aceasta tabla (bonus_board) este deja data in fisierul header (scrabble.h) ce se afla in arhiva cu checker-ul si va ramane neschimbata pe parcursul intregii teme.

Aceasta tabla va avea aceeasi dimensiune ca si tabla de joc, de 15 X 15. Tabla este populata cu valori de 0, 1 si 2 cu urmatoarea semnificatie:

  • 0 - niciun bonus
  • 1 - punctajul se dubleaza daca pe patratica respectiva se afla o litera apartinand unui cuvant care are substringul “XX” in compozitie, se da substringul la fiecare joc
  • 2 - punctajul se tripleaza daca pe patratica respectiva se afla o litera apartinand unui cuvant care se termina cu substringul “YY”, se da substringul la fiecare joc

Modul in care se calculeaza punctajul va fi detaliat ulterior in cerintele temei. Matricea arata in felul urmator:

Lista de cuvinte

Pe langa table de bonusuri, in fisierul header scrabble.h din arhiva veti mai primi un vector de cuvinte pe care il veti folosi la anumite task-uri din tema. Vectorul se cheama words si contine 100 de string-uri.

Atentie! Pentru fiecare cerinta veti primi datele de intrare la standard input. De fiecare data primul input pe care il va primi programul vostru este numarul taskului (0-5 pentru tema, 6 pentru bonus) urmand ca mai apoi sa cititi restul de date asa cum este descris pentru fiecare cerinta in parte.

Cerinte

Veți avea de rezolvat 6 cerințe obligatorii și o cerință bonus.

Atentie! Pentru citirea input-ului de la tastatura nu aveti voie sa folositi scanf. Nici fscanf! :)

Cerinta 0: (2 Puncte) - 1 test

Pentru rezolvarea task-urilor veti avea nevoie de tabla de joc. Tabla de bonus este data deja in fisierul header, dar tabla de joc va trebui sa o declarati si sa o initializati voi.

Inainte de a incepe rezolvarea exercitiilor declarati o matrice de 15 X 15. Dupa ce o declarati, populati matricea cu valoarea ‘.’ (caracterul punct).

La input veti primi valoarea 0 (pentru task-ul 0). La standart output va trebui sa afisati matricea goala folosind functia print_board.

Cerinta 1: (18 Puncte) - 9 teste

Pentru aceasta cerinta va trebui sa cititi numarul intreg N urmat de N linii continand coordonatele unui cuvant si cuvantul respectiv. Dupa ce faceti citirea unei linii, adaugati-o la coordonatele corespunzatoare in matricea de joc (cea pe care ati declarat-o la cerinta 0). Cuvantul va fi pastrat caracter cu caracter in matrice incepand cu coordonatele date.

Dupa ce ati salvat toate cele N cuvinte puteti sa afisati matricea apeland functia de afisare in felul urmator:

print_board(game_board)

.

Atentie! Matricea in care pastrati cuvintele va trebui sa aiba caracterul ‘.’ pe pozitiile neocupate pentru ca functia de afisare sa functioneze.

Se da un input de forma:

1
N
Y1 X1 D1 WORD1
Y2 X2 D2 WORD2
…
N -> numar de cuvinte primite
Yi -> indicele pe verticala unde va fi plasat cuvantul (linia in matrice)
Xi -> indicele pe orizontala unde va fi plasat cuvantul (coloana in matrice)
Di -> directia in care este scris cuvantul: 
* Daca D == 0: cuvantul e scris pe orizontala, de la (Yi, Xi) spre dreapta
* Daca D == 1: cuvantul e scris pe verticala, de la (Yi, Xi) in jos
Yi - indicele liniei unde este plasata prima litera din cuvant 
Xi - indicele coloanei unde este plasata prima litera din cuvant
(Yi, Xi) - pozitia de unde incepe cuvantul, de la

Atentie! Numerotarea liniilor se face din coltul stanga sus si incepand cu indicele 0!

Atentie! Pentru acest task se garanteaza ca nu vor fi date cuvinte care sa iasa din dimensiunile tablei.

Un exemplu de input este urmatorul:

1
5
4 4 0 CAT
4 6 1 TRAIN
6 6 0 AIRPLANE
6 9 1 PROGRAM
6 10 1 LECTURE

Acest input va produce urmatorul output:

Cerinta 2: (20 Puncte) - 10 teste

Pentru aceasta cerinta va trebui sa calculati punctajul obtinut de doi jucatori fara a tine cont de punctele bonus. Veti primi un input exact ca la task-ul precedent, dar de aceasta data veti afisa punctajul total al celor doi jucatori.

Calcularea scorului unui cuvant se face prin insumarea scorului fiecarei litere din cuvant. Scorurile literelor sunt urmatoarele:

A, E, I, L, N, O, R, S, T, U - 1 Punct
D, G - 2 Puncte
B, C, M, P - 3 Puncte
F, H, V, W, Y - 4 Puncte
K - 5 Puncte
J, X - 8 Puncte
Q, Z - 10 Puncte

Tip! Pentru a tine informatiile pentru scorurile fiecarei litere puteti tine un vector de dimensiune 26 cu toate valorile puse in ordine alfabetica. Pentru a afla la ce index in vector se afla scorul unei litere, substrageti valoarea ‘A’ din litera cautata.

Atentie! Doar pentru acest task nu se va tine cont de tabla de bonusuri!

Se da un input de forma:

2
N
Y1 X1 D1 WORD1
Y2 X2 D2 WORD2
…
Unde:
XX este substringul pentru bonusul primit pentru casutele marcate cu 1. 
YY este substringul pentru bonusurile primite pentru casutele marcate cu 2.
N este numarul de cunvinte
Xi, Yi, WORDi sunt coordonatele pentru cuvantul WORDi
Di este directia in care este scris cuvantul

Output-ul va fi sub forma urmatoare:

Player 1: W Points
Player 2: T Points

W este scorul obtinut de primul jucator.
T este scorul obtinut de al doilea jucator.
Textul pentru fiecare jucator va fi afisat pe o linie separata.

Un exemplu de input este urmatorul:

2
5
4 4 0 CAT
4 6 1 TRAIN
6 6 0 AIRPLANE
6 9 1 PROGRAM
6 10 1 LECTURE 

Pentru acest input se obtine outputul urmator:

Player 1: 24 Points
Player 2: 17 Points

Explicatie:

Jucatorului 1 ii revin urmatoarele cuvinte din input: “CAT”, “AIRPLANE”, “LECTURE”
Scor(Jucator 1) = Scor(“CAT”) + Scor(“AIRPLANE”) + Scor(“LECTURE”)
Scor(Jucator 1) = (3 + 1 + 1) + (1 + 1 + 1 + 3 + 1 + 1 + 1 + 1) + (1 + 1 + 3 + 1 + 1 + 1 + 1) 
Scor(Jucator 1) = 5 + 10 + 9 = 24
Scor(Jucator 2) = Scor(“TRAIN”) + Scor(“PROGRAM”) = 5 + 12 = 17

Cerinta 3: (30 Puncte) - 10 teste

Pentru aceasta cerinta va trebui sa calculati punctajul celor doi jucatori, ca la task-ul precedent, dar de aceasta data va trebui sa verificati daca sunt indeplinite conditiile de bonus.

Se da un input de forma:

3
XX
YY
N
Y1 X1 D1 WORD1
Y2 X2 D2 WORD2
…

Unde:

XX este substringul pentru bonusul primit pentru casutele marcate cu 1. 
YY este substringul pentru bonusurile primite pentru casutele marcate cu 2.
N este numarul de cunvinte
Xi, Yi, WORDi sunt coordonatele pentru cuvantul WORDi
Di este directia in care este scris cuvantul

Output-ul va fi sub forma urmatoare:

Player 1: X Points
Player 2: Y Points

Daca un cuvant are in componenta sa o litera la coordonatele X,Y, iar la aceleasi coordonate pe tabla de bonus casuta respectiva este marcata cu 1, se va verifica daca indeplineste conditia de bonus definita mai sus, iar la final, dupa ce se calculeaza punctajul pentru intregul cuvant, punctajul va fi inmultit cu 2. Acelasi rationament se aplica si pentru patratelele marcate cu 2, dar de data aceasta se va inmulti rezultatul cu 3. Regulile de aplicare a bonusul sunt detaliate la inceputul enuntului la rubrica “Tabla de bonusuri”.

Exemplu: (Vom folosi matricea de bonusuri de mai sus)

3
LA
IN
5
4 4 0 CAT
4 6 1 TRAIN
6 6 0 AIRPLANE
6 9 1 PROGRAM
6 10 1 LECTURE
Scor(“TRAIN”) =  (1 + 1 + 1 + 1 + 1) * 3 = 15
Pentru cuvantul “TRAIN” dupa ce calculam scorul fara bonus vom inmulti cu 3 deoarece cuvantul se termina cu silaba “IN”, iar litera “I” se afla la pozitia (7, 6) - pe aceeasi pozitie in tabla de bonusuri se afla cifra 2 - bonus_board[7][6] == 2.

Scor(“AIRPLANE”) =  (1 + 1 + 1 + 3 + 1 + 1 + 1 + 1) * 2 = 20
Pentru cuvantul “AIRPLANE” dupa ce calculam scorul fara bonus vom inmulti cu 2 deoarece litera “R” se afla pe pozitia (6, 8) (bonus_board[6][8] = 1).

Atentie! Daca cuvant se suprapune cu doua casute de bonus marcate cu 1 si o casuta de bonus marcata cu 2, daca sunt indeplinite conditiile de bonus, atunci scorul va fi inmultit cu * 2 * 2 * 3.

Cerinta 4: (40 Puncte) - 10 teste

Pentru acesta cerinta va trebui sa gasiti urmatorul cuvant pe care Player 2 poate sa il joace. Mai exact, veti primi ca input lista de cuvinte jucate pana in momentul respectiv de cei doi jucatori. Player 1 pune primul cuvant, apoi Player 2, si asa mai departe. Vor fi date un numar impar de mutari, astfel incat voi va trebui sa gasiti urmatorul cuvant pe care Player 2 poate sa il foloseasca.

Gasiti primul cuvant din vectorul de cuvinte (vectorul words din fisierul scrabble.h) care indeplineste conditiile:

  • Face parte din lista de cuvinte (vectorul words din fisierul scrabble.h)
  • Cuvantul nu e deja pus pe tabla de niciunul dintre jucatori
  • Prima litera din cuvant se afla deja pe tabla si cuvantul poate fi pus in continuarea literei respective, fie pe orizontala, fie pe verticala. (Pentru a verifica acest lucru, se cauta pe tabla prima litera din cuvant de la coltul stanga sus, linie cu linie, pana la coltul dreapta jos al tablei de joc.).
  • Cuvantul nu iese din marginile tablei de joc si nu se suprapune cu alte cuvinte (inafara de prima litera)

Sa se adauge cuvantul respectiv pe tabla de joc si sa se afiseze tabla. Daca un cuvant poate fi pus si pe orizontala si pe verticala, cuvantul va fi pus pe orizontala.

Inputul va fi de forma urmatoare:

4
XX
YY
N
Y1 X1 D1 WORD1
Y2 X2 D2 WORD2
…
Yn Xn Dn WORDn

Unde:

XX este substringul pentru bonusul primit pentru casutele marcate cu 1. 
YY este substringul pentru bonusurile primite pentru casutele marcate cu 2.
N este numarul de cunvinte
Xi, Yi, WORDi sunt coordonatele pentru cuvantul WORDi
Di este directia in care este scris cuvantul

Exemplu:

4
LA
IN
5
4 4 0 CAT
4 6 1 TRAIN
6 6 0 AIRPLANE
6 9 1 PROGRAM
6 10 1 LECTURE

Pe baza regulilor definite anterior este ales cuvantul “COMMUNITY”. Output-ul va fi urmatorul:

Cerinta 5: (30 Puncte) - 10 teste

Pentru aceasta cerinta va trebui sa faceti acelasi lucru ca si la task-ul precedent, dar de aceasta data veti alege cuvantul din lista de cuvinte care va aduce castigul (sau remiza) pentru Player 2. La calcularea scorurilor se va tine cont de bonus. Cuvantul selectat trebuie sa incapa pe tabla de joc si sa nu se repete. Daca gasiti un astfel de cuvant atunci la output se va afisa tabla de joc care va contine si cuvantul respectiv, in caz contrar se va afisa mesajul “Fail!”.

Pasi in rezolvarea task-ului:

  • Se calculeaza scorul Player-ului 1.
  • Se calculeaza scorul Player-ului 2.
  • Se cauta cuvantul optim pe care Player 2 poate sa il joace (acel cuvant care adunat la scorul pe care Player 2 il are deja va produce in scor mai mare *sau* egal cu scorul Player-ului 1)
  • Daca se gaseste cuvantul va fi afisata tabla ce va contine noul cuvantul.
  • Daca nu se gaseste cuvantul va fi afisat mesajul “Fail!”.

Un cuvant este optim pentru Player 2 daca:

  • Face parte din lista de cuvinte (vectorul words din fisierul scrabble.h)
  • Cuvantul nu e deja pus pe tabla de niciunul dintre jucatori
  • Prima litera din cuvant se afla deja pe tabla si cuvantul poate fi pus in continuarea literei respective, fie pe orizontala, fie pe verticala. (Pentru a verifica acest lucru, se cauta pe tabla prima litera din cuvant de la coltul stanga sus, linie cu linie, pana la coltul dreapta jos al tablei de joc. Daca un cuvant poate fi pus in mai multe locuri, se alege pozitia cu linia cea mai mic, daca liniile sunt egale, se alege cea care are cea mai mica coloana. Daca un cuvant poate fi pus si pe orizontala si pe verticala, cuvantul va fi pus pe orizontala.).
  • Cuvantul nu iese din marginile tablei de joc si nu se suprapune cu alte cuvinte (inafara de prima litera)
  • Produce cel mai mare scor posibil incluzand bonusurile

Spre deosebire de task-ul 4, cuvantul optim nu trebuie sa fie neaparat primul cuvant gasit in lista.

Inputul va fi de forma urmatoare:

5
XX
YY
N
X1 Y1 D1 WORD1
X2 Y2 D2 WORD2
…
Xn Yn Dn WORDn

Unde:

XX este substringul pentru bonusul primit pentru casutele marcate cu 1. 
YY este substringul pentru bonusurile primite pentru casutele marcate cu 2.
N este numarul de cunvinte
Xi, Yi, WORDi sunt coordonatele pentru cuvantul WORDi
Di este directia in care este scris cuvantul

Exemplu:

5
LA
IN
5
4 4 0 CAT
4 6 1 TRAIN
6 6 0 AIRPLANE
6 9 1 PROGRAM
6 10 1 LECTURE

Player 1 are cuvintele: “CAT”, “AIRPLANE”, “LECTURE”

Player 2 are cuvintele: “TRAIN”, “PROGRAM”

Scor(Player 1) = 34 Points
Scor(Player 2) = 27 Points

Pe baza regulilor definite anterior este ales cuvantul “COMMUNITY”. Output-ul va fi urmatorul:

Cerinta BONUS: (10 Puncte) - 10 teste

Pentru bonus va trebui sa simulati jocul intre cei doi jucatori. Mai exact, daca inainte la input primeati alternativ cuvintele pentru Player 1 si Player 2, de aceasta data veti primi numai cuvintele pentru Player 1, iar cele pentru Player 2 va trebui sa le alegeti voi din vectorul de cuvinte.

Pasi in rezolvarea task-ului:

  • Se citeste numarul task-ului (6), substringurile XX, YY si N
  • Pentru i = 0 la N - 1:
  • Se citeste Yi Xi Di WORDi (Mutarea cu numarul i a Player-ului 1)
  • Se pune (salveaza) pe tabla la coordonatele date cuvant WORDi
  • Se cauta cuvantul optim pe care Player 2 poate sa il joace
  • Se pune (salveaza) pe tabla la coordonatele gasite cuvantul pentru Player 2
  • Dupa ce sunt citite cele N cuvinte ale Player-ului 1 jocul se termina
  • La finalul jocului se afiseaza tabla print_board(board) si pe linia imediat urmatoare
  • “Player X Won!” unde X este 1 daca Player 1 a castigat sau 2 daca Player 2 a castigat.

Un cuvant este optim pentru Player 2 daca:

  • Face parte din lista de cuvinte (vectorul words din fisierul scrabble.h)
  • Cuvantul nu e deja pus pe tabla de niciunul dintre jucatori
  • Prima litera din cuvant se afla deja pe tabla si cuvantul poate fi pus in continuarea literei respective, fie pe orizontala, fie pe verticala. (Pentru a verifica acest lucru, se cauta pe tabla prima litera din cuvant de la coltul stanga sus, linie cu linie, pana la coltul dreapta jos al tablei de joc. Daca un cuvant poate fi pus in mai multe locuri, se alege pozitia cu linia cea mai mic, daca liniile sunt egale, se alege cea care are cea mai mica coloana. Daca un cuvant poate fi pus si pe orizontala si pe verticala, cuvantul va fi pus pe orizontala.).
  • Cuvantul nu iese din marginile tablei de joc si nu se suprapune cu alte cuvinte (inafara de prima litera)
  • Produce cel mai mare scor posibil incluzand bonusurile

Spre deosebire de task-ul 4, cuvantul optim nu trebuie sa fie neaparat primul cuvant gasit in lista.

Inputul va fi de forma urmatoare:

6
XX
YY
N
Y1 X1 D1 WORD1
Y2 X2 D2 WORD2
…
Yn Xn Dn WORDn

Unde:

XX este substringul pentru bonusul primit pentru casutele marcate cu 1. 
YY este substringul pentru bonusurile primite pentru casutele marcate cu 2.
N este numarul de cunvinte
Xi, Yi, WORDi sunt coordonatele pentru cuvantul WORDi

Trimitere tema

Tema va fi trimisa folosind v2.vmchecker, cursul Programarea Calculatoarelor, tema A Game of Scrabble.

Găsiți arhiva cu checker-ul si makefile-ul aici.

Fisierul .c se va numi scrabble.c

Punctajul:

  • 140p - teste
  • 10p - bonus
  • 10p - coding style & README (checker-ul o sa va acorde aceste puncte doar pentru prezenta fisierului README, la corectare acestea vor fi validate)

Restrictii si precizari

  • Nu folositi variabile globale.
  • Fiti consistenti in ceea ce priveste Coding Style-ul.
  • Toate matricile si vectorii folositi se vor aloca static;
  • Tema se va trimite pe vmchecker si se va testa local cu ajutorul checker-ului;
  • Pe vmchecker veti uploada o arhiva in format .zip care sa contina:
    1. sursa voastra, adică scrabble.c
    2. README, în care trebuie să dați detalii despre implementare, de ce ați ales să rezolvați într-un anumit fel, etc.

Listă depunctări

Lista nu este exhaustivă. Se pot aplica chiar depunctări mai mari în cazuri excepționale.

  • o temă care nu compilează și nu a rulat pe vmchecker nu va fi luată în considerare
  • o temă care nu rezolvă cerința și trece testele prin alte mijloace nu va fi luată în considerare
  • [-1.0]: warning-uri la compilare (este obligatorie folosirea în fișierul Makefile a flag-ului de compilare -Wall pentru regula build)
  • [-1.0]: numele variabilelor nu sunt sugestive
  • [-1.0]: linii mai lungi de 80 de caractere in cod / in fișierul README
  • [-1.0]: cod nemodular, funcții prea lungi (inclusiv main)
  • [-2.5]: variabile globale
  • [-5.0]: abordare ineficientă
    • în cadrul cursului de programare nu avem ca obiectiv rezolvarea în cel mai eficient mod posibil a programelor; totuși, ne dorim ca abordarea să nu fie una ineficientă, de genul să nu folosiți instrucțiuni repetitive acolo unde clar nu era cazul, etc.
programare/teme_2020/tema2_2020_cbd.txt · Last modified: 2020/12/14 11:46 by george.muraru
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0