Differences

This shows you the differences between two versions of the page.

Link to this comparison view

poo-ca-cd:arhiva:teme:2024:tema [2025/09/27 10:30] (current)
florian_luis.micu created
Line 1: Line 1:
 +====== Tema 0 - GwentStone Lite ======
 +
 +{{:​poo-ca-cd:​teme:​banner_poo-01.png?​nolink&​800|}}
 +
 +  * Responsabili:​ [[darabantimoteisiceva@gmail.com | Timotei Daraban ]], [[matei_marius.ignat@stud.acs.upb.ro | Ignat Matei-Marius ]], [[ti.dumitrescu@gmail.com | Dumitrescu Toma-Ioan ]]
 +  * Autori: [[miculuis1@gmail.com | Florian-Luis Micu]], [[rebeccastate40@gmail.com | Andreea-Rebecca State]], [[andreiotetea23@gmail.com | Andrei Oțetea]]
 +  * Consultant & Revisor: [[miculuis1@gmail.com | Florian-Luis Micu]]
 +  * Data publicării:​ 25 octombrie, ora 20:00
 +  * Deadline HARD: 24 noiembrie 2024, ora 23:59
 +  * Ultimele modificări:​
 +      * Adăugare deadline hard - 31 octombrie
 +      * Update input/ref pentru a include cazuri de actiuni invalide - 31 octombrie.
 +      * Clarificări responsabili temă.
 +      * Update **barem/​git**,​ sectiunea Evaluare.
 +      * Update **checkstyle** la versiunea 10.20.1.
 +
 +
 +<note important>​Pentru orice neclaritate vă rugăm să folosiți forumul, urmând ca **doar responsabilii** temei să vă răspundă la întrebări. Se preferă folosirea forumului tocmai pentru a evita repetarea întrebărilor.</​note>​
 +===== Obiective =====
 +
 +  * Familiarizarea cu Java și conceptele de bază ale POO.
 +  * Fundamentarea practică a constructorilor și a agregării/​moștenirii.
 +  * Dezvoltarea unor abilități de bază de organizare și design orientat obiect.
 +  * Scrierea unui cod cât mai generic, ce va permite ulterior adăugarea de noi funcționalități.
 +  * Respectarea unui stil de codare și de comentare.
 +  * Dezvoltarea aptitudinilor de depanare a problemelor în cod.
 +
 +===== Introducere =====
 +
 +Tocmai v-ați făcut primul vostru start-up. Fiind foarte pasionați de jocuri și de genul fantasy, ideea voastră de 1M de dolari este crearea unui joc de cărți pe calculator.
 +
 +Norocul vă surâde pentru că studioul CD Projekt Red pare că nu mai este în vogă în materie de jocuri așa că le puteți fura jocul de cărți, mai exact Gwent. Deoarece doriți ca jocul vostru să nu fie o copie care va fi ușor uitată, ați adăugat mecanisme noi care vor fi asemănătoare cu alte jocuri de cărți populare. Drept urmare, jocul vostru preia cele mai bune lucruri din **Hearthstone** și din **Gwent**, fiind mult mai ușor de implementat,​ dar și de jucat. ​
 +
 +De asemenea, ca în orice joc de calitate, o să ne asigurăm că avem și o poveste pe cinste pentru personajele noastre create.
 +
 +===== Date tehnice ale jocului =====
 +
 +Dorim ca jocul nostru să poată fi jucat de doi jucători în sistem amical. Cu toate acestea, pentru că încă suntem în etapa de dezvoltare a jocului în cadrul studioului nostru OOP-Everything,​ vom folosi un AI care va simula cei doi jucători.
 +
 +AI-ul vă va da comenzile de joc în input, împreună cu server-ul care vă va trimite și comenzi de debugging. Comenzile de debugging sunt făcute pentru a verifica statutul jocului în diverse etape, astfel vom putea depana mai ușor problemele care pot apărea în cadrul implementării. De asemenea, server-ul vă solicită și date pe care le va folosi pentru a crea statistici, cum ar fi numărul de câștiguri ale unui jucător și numărul total de jocuri terminate de cei doi jucători. La output dorim să printăm orice informație ne cere server-ul sau orice eroare întâmpinăm în cadrul unei acțiuni invalide. ​
 +
 +===== Prezentare scurtă a gameplay-ului =====
 +
 +Jocul este destinat pentru doi jucători, fiecare având mai multe pachete de cărți, numite **deck**-uri. La începutul jocului, fiecare jucător își alege un **deck** și primește un **erou** care îl va reprezenta. Ordinea de joc este stabilită prin aruncarea unei monede.
 +
 +Jocul este **"​turn-based"​**,​ deci fiecare jucător va avea câte o tură pe care o încheie explicit. Dupa ce fiecare jucător își încheie tura, va începe o nouă rundă. La începutul rundei fiecare jucător primește **"​mana"​** care reprezintă valuta jocului apoi se trage o carte din **deck** și se introduce în mâna jucătorului.
 +
 +Cărțile din mâna unui jucător pot fi plasate pe masă pentru a fi folosite, dar pentru asta e nevoie de **mana**, deoarece fiecare carte "​costă"​ o cantitate de **mană** pentru a putea fi plasata pe masa de joc.
 +
 +**Masa de joc** este un loc în care se plasează cărțile pentru a putea interacționa între ele. Fiecare jucător are **2 rânduri** pe care poate pune o carte, cărțile fiind astfel făcute să poată fi plasate doar pe anumite rânduri.
 +**Eroii** jucătorilor sunt prezenți pe masă de la începutul jocului într-un loc special și aceștia au abilități speciale care pot afecta rândurile cu cărți ale jucătorilor.
 +
 +Scopul jocului este să folosești cărțile de pe masă pentru a ataca **eroul** adversar, până când unul dintre eroi rămâne fără viață. În acel moment, jucătorul care a dat lovitura finală câștigă.
 +Fiecare jucator are o **metrică proprie** în care se reține câte jocuri a câștigat și câte jocuri a jucat.
 +
 +===== Masa de joc =====
 +
 +Masa de joc este locul unde cărțile vor interacționa direct între ele. Ea poate fi reprezentată ca o matrice de **4x5**, fiecare jucător având **2 rânduri** asignate lui. Cărțile se plasează pe câte un rând conform restricțiilor impuse mai jos, fiind introduse pe rând de la **stânga la dreapta**, mai exact adăugăm mereu o carte la dreapta ultimei cărți adăugate până se umple rândul. Dacă o carte este omorâtă, atunci toate cărțile din dreapta ei vor fi mutate cu o poziție la stânga (fenomen cunoscut ca **shiftare la stânga**). De asemenea, pe un rând pot exista **maxim** 5 cărți.
 +
 +Rândurile 0 și 1 sunt asignate jucătorului 2, iar rândurile 2 și 3 sunt asignate jucătorului 1, conform imaginii de mai jos. Rândurile din față vor fi reprezentate de rândurile 1 și 2, iar rândurile din spate vor fi 0 si 3 (jucătorii vor fi așezați față în față). Totodată, eroii jucătorilor vor avea un loc special în care vor fi așezați de la începutul jocului.
 +
 +<​html>​
 +<br>
 +</​html>​
 +
 +{{:​poo-ca-cd:​teme:​tema_poo_new.png?​nolink&​800|}}
 +
 +<​html>​
 +<br>
 +</​html>​
 +
 +<note important>​În teste anumite acțiuni necesită coordonate ale cărților de pe tablă. Aceste coordonate vă sunt date de parametrii "​x"​ (rând) și "​y"​ (coloană).</​note>​
 +
 +===== Formatul cărților de joc =====
 +
 +Jucătorul va putea deține cărți de tip **minion** si o carte specială de tipul **erou** care îl va reprezenta în joc.
 +
 +==== Cartea Minion ====
 +
 +Minionii sunt cărți utilizate pentru atac și apărare pe tabla de joc. Fiecare minion are următoarele atribute:
 +
 +  * **mana** (int): costul necesar pentru a plasa cartea pe masă.
 +  * **health** (int): numărul de puncte de viață pe care le are minionul. Când acest număr este mai mic sau egal cu 0, minionul este eliminat de pe tablă.
 +  * **attackDamage** (int): punctele de atac ale minionului, folosite pentru a lovi inamicul.
 +  * **description** (String): o scurtă descriere a minionului.
 +  * **colors** (String/​Enum):​ culorile care definesc designul grafic al cărții.
 +  * **name** (String): numele cărții.
 +
 +<note important>​ Atributele fiecărui minion sunt primite la input, iar valorile pot varia, chiar dacă numele cărții este același. Astfel, două cărți cu același nume pot avea proprietăți diferite. La fel, nu există un minion generic, ci doar cărți specializate
 +de tipul minion. ​
 +</​note>​
 +
 +=== Tipuri de minioni: ===
 +
 +  * **Sentinel**,​ **Berserker**:​ Trebuie plasate pe rândul din spate al jucătorului.
 +  * **Goliath**,​ **Warden**: Trebuie plasate pe rândul din față al jucătorului.
 +
 +
 +== Condiții suplimentare:​ ==
 +
 +  * Jucătorul trebuie să aibă suficientă **mană** pentru a plasa un minion pe masă.
 +  * Minionii nu pot ataca de două ori în aceeași tură.
 +  * Minionii "​frozen"​ (înghețați) nu pot ataca până la finalul turei curente.
 +  * Atacurile trebuie direcționate către cărțile adversarului.
 +
 +=== Carțile de tip Tank ===
 +  * Minionii de tip **Goliath** și **Warden** au o abilitate specială: aceștia trebuie să fie atacați primii de către inamic. Această abilitate este pasivă și face ca atacatorii să nu poată ataca alte cărți sau eroul adversar până când toți minionii de tip Tank nu vor fi eliminați.
 +
 +Exemplu de situație: Dacă player-ul 1 dorește să atace o carte a player-ului 2, trebuie verificat dacă există un minion Tank pe rândul din față. Dacă există, acesta trebuie atacat primul. Abia după eliminarea Tank-urilor pot fi atacați alți minioni sau eroul adversarului.
 +
 +=== Carțile cu abilități speciale ===
 +
 +Aceste cărți au puteri unice care pot fi folosite in timpul jocul. Tipurile de cărți cu abilități speciale sunt:
 +
 +  * **The Ripper**: Abilitatea **"​Weak Knees"​** scade atacul unui minion inamic cu 2 puncte. Dacă atacul este mai mic de 2, acesta devine 0.
 +  * **Miraj**: Abilitatea **"​Skyjack"​** face schimb între viața lui și viața unui minion advers.
 +  * **The Cursed One**: Abilitatea **"​Shapeshift"​** face schimb între atacul și viața unui minion inamic. Dacă minionul atacat are atacul 0, viața acestuia devine 0 și este eliminat.
 +  * **Disciple**:​ Abilitatea **"​God'​s Plan"​** oferă +2 puncte de viață unui minion aliat.
 +
 +== Condiții suplimentare pentru abilități:​ ==
 +
 +  * **The Ripper** și **Miraj** trebuie plasate pe rândul din **față**.
 +  * **The Cursed One** și **Disciple** trebuie plasate pe rândul din **spate**.
 +  * Abilitățile speciale pot fi folosite doar pe minionii inamici (cu excepția **Disciple**).
 +  * **God'​s Plan** se va folosi doar pe o carte a jucătorului curent.
 +  * O carte nu poate ataca și folosi abilitatea specială în aceeași tură.
 +  * Nu se poate folosi abilitatea unei cărți care este "​frozen"​.
 +  * Efectul abilităților nu se va reseta după terminarea rundei.
 +
 +== Informații suplimentare ==
 +  * Abilitățile nu sunt date la input, ele fiind fixate pentru fiecare carte. Trebuie ca voi sa implementați efectul dorit atunci când se folosește abilitatea specială a unei cărți.
 +  * Cărțile **The Cursed One** și **Disciple** au atacul 0, deoarece în povestea noastră ei reprezintă niște druizi. În schimb, **The Ripper** și **Miraj** au atacul diferit de 0 fiind minioni legendari. Chiar dacă druizii au atacul 0, ei pot ataca pe oricine.
 +
 +==== Cartea Erou ====
 +
 +Eroii reprezintă personajele principale ale fiecărui jucător. Fiecare erou are următoarele atribute:
 +
 +  * mana (int): necesară pentru a folosi abilitatea specială a eroului.
 +  * health (fix 30): punctele de viață ale eroului. Când acestea ajung la 0, jocul se termină și adversarul câștigă.
 +  * description (String): o descriere a eroului.
 +  * colors (String/​Enum):​ culorile asociate eroului.
 +  * name (String): numele eroului.
 +
 +Fiecare erou are o abilitate unică ce poate fi folosită pe parcursul jocului:
 +
 +== Lord Royce ==
 +
 +**Sub-Zero**:​ îngheață toate cărțile de pe rând.
 +
 +== Empress Thorina ==
 +
 +**Low Blow**: distruge cartea cu cea mai mare viață de pe rând.
 +
 +== King Mudface ==
 +
 +**Earth Born**: +1 viață pentru toate cărțile de pe rând.
 +
 +== General Kocioraw ==
 +
 +**Blood Thirst**: +1 atac pentru toate cărțile de pe rând.
 +
 +=== Condiții suplimentare pentru eroi: ===
 +
 +  * Abilitățile eroilor **Lord Royce** și **Empress Thorina** pot fi folosite doar pe rândurile inamicului.
 +  * Abilitățile eroilor **King Mudface** și **General Kocioraw** pot fi folosite doar pe rândurile proprii.
 +  * Jucătorul trebuie să aibă suficientă **mana** pentru a folosi abilitatea specială a eroului.
 +  * Eroul jucătorului poate să atace o **singură** data per tură.
 +
 +
 +=== Informatii suplimentare:​ ===
 +  * Eroul jucătorului este ales random de către joc și vă va fi comunicat în input.
 +  * Abilitățile nu sunt date la input, ele fiind fixate pentru fiecare carte. Trebuie ca voi să implementați efectul dorit atunci când se folosește abilitatea specială a unei cărți de tipul erou.
 +
 +
 +<note warning>
 +Pentru aceste abilități se iterează de la stânga la dreapta și pentru **Low Blow** se ia prima carte de pe rând care respectă criteriul specificat mai sus (ex. dacă cartea cu indexul 0 și cartea cu indexul 3 au viață maximă de pe rând, se va selecta cartea cu indexul 0).
 +</​note>​
 +
 +===== Gameplay detaliat =====
 +
 +==== Pregătirea jucătorilor ====
 +
 +Fiecare jucător are mai multe pachete cu care poate începe jocul, prima lui sarcină fiind să aleagă pachetul cu care dorește să joace. Veți primi la input numărul de pachete de cărți, numărul de cărți din fiecare pachet, o listă cu pachetele de cărți și jucătorul pentru care se aplică acești parametri.
 +
 +<spoiler Click pentru input-ul asociat acestui pas>
 +<code json>
 +"​playerOneDecks":​ {
 +        "​nrCardsInDeck":​ 2,
 +        "​nrDecks":​ 2,
 +        "​decks":​ [
 +          [
 +            {
 +              "​mana":​ 1,
 +              "​attackDamage":​ 1,
 +              "​health":​ 7,
 +              "​description":​ "​Standard card: A warrior who is never afraid of battle, no matter the costs",​
 +              "​colors":​ [
 +                "​Red",​
 +                "​Purple"​
 +              ],
 +              "​name":​ "​Goliath"​
 +            },
 +            {
 +              "​mana":​ 1,
 +              "​attackDamage":​ 0,
 +              "​health":​ 1,
 +              "​description":​ "​Premium card: Nobody suspects an outcast, not even the Gods.",​
 +              "​colors":​ [
 +                "​Black",​
 +                "​White",​
 +                "​Red"​
 +              ],
 +              "​name":​ "The Cursed One"
 +            },
 +          ],
 +          [
 +            {
 +              "​mana":​ 1,
 +              "​attackDamage":​ 2,
 +              "​health":​ 2,
 +              "​description":​ "​Premium card: Fear him. Your last breath is now.",
 +              "​colors":​ [
 +                "​Red",​
 +                "​Blue",​
 +                "​Pink"​
 +              ],
 +              "​name":​ "​Berserker"​
 +            },
 +            {
 +              "​mana":​ 1,
 +              "​attackDamage":​ 0,
 +              "​health":​ 1,
 +              "​description":​ "​Standard card: Thrown from the highest cliff, revenge will be his glory.",​
 +              "​colors":​ [
 +                "​Pink",​
 +                "​Purple"​
 +              ],
 +              "​name":​ "The Cursed One"
 +            }
 +          ]
 +        ]
 +      }
 +    },
 +    {
 +      "​playerTwoDecks":​ {
 +        "​nrCardsInDeck":​ 2,
 +        "​nrDecks":​ 2,
 +        "​decks":​ [
 +          [
 +            {
 +              "​mana":​ 1,
 +              "​attackDamage":​ 3,
 +              "​health":​ 2,
 +              "​description":​ "​Premium card: Fear him. Your last breath is now.",
 +              "​colors":​ [
 +                "​Purple",​
 +                "​Yellow"​
 +              ],
 +              "​name":​ "​Berserker"​
 +            },
 +            {
 +              "​mana":​ 1,
 +              "​attackDamage":​ 0,
 +              "​health":​ 3,
 +              "​description":​ "​Standard card: Thrown from the highest cliff, revenge will be his glory.",​
 +              "​colors":​ [
 +                "​Black",​
 +                "​White",​
 +                "​Red"​
 +              ],
 +              "​name":​ "The Cursed One"
 +            }
 +          ],
 +          [
 +            {
 +              "​mana":​ 1,
 +              "​attackDamage":​ 1,
 +              "​health":​ 2,
 +              "​description":​ "​Standard card: Trained by the best, nothing will catch him off-guard.",​
 +              "​colors":​ [
 +                "​Black",​
 +                "​Grey",​
 +                "​Blue"​
 +              ],
 +              "​name":​ "​Sentinel"​
 +            },
 +            {
 +              "​mana":​ 1,
 +              "​attackDamage":​ 6,
 +              "​health":​ 4,
 +              "​description":​ "​Standard card: Death incarnate. No better time to die than now.",
 +              "​colors":​ [
 +                "​Orange",​
 +                "​Red",​
 +                "​Black"​
 +              ],
 +              "​name":​ "The Ripper"​
 +            }
 +          ]
 +        ]
 +      }
 +    }
 +</​code>​
 +</​spoiler>​
 +
 +<note important>​
 +Acest pas se întâmplă doar când se începe un test nou. Dacă jucătorii doresc să joace alt joc în cadrul aceluiași test, AI-ul vă va specifica doar ce pachet doresc să folosească pentru următorul meci, astfel **repetându-se pasul următor**. Ordinea pachetelor rămâne aceeași.
 +</​note>​
 +
 +<note warning>
 +La finalul unei partide dintre cei doi jucători aceștia trebuie să aibă posibilitatea să aleagă același pachet ca în jocul trecut pentru un nou joc, deci va trebui ca pachetul folosit să poată să revină **exact** la starea inițială, înainte de procesul de amestecare. ​
 +</​note>​
 +
 +==== Pregătirea jocului ====
 +
 +Fiecare jucător își alege un deck, acesta fiind specificat de AI în input. Deck-ul ales de fiecare jucător va fi amestecat la începutul jocului, deoarece dorim ca jocul sa nu fie previzibil. Pentru a ne asigura că rezultatele vor fi deterministe,​ server-ul va trimite la input și un **seed** folosit ca parametru pentru procesul de amestecare.
 +
 +Server-ul alege câte un erou aleator pentru fiecare jucător, aceștia fiind specificați la input.
 +
 +Se alege un jucător care să înceapă prima rundă, fiind specificat la input.
 +
 +<spoiler Click pentru input-ul asociat acestui pas>
 +<code json>
 +"​startGame":​ {
 +        "​playerOneDeckIdx":​ 1,
 +        "​playerTwoDeckIdx":​ 0,
 +        "​shuffleSeed":​ 882661,
 +        "​playerOneHero":​ {
 +          "​mana":​ 2,
 +          "​description":​ "​Standard card: Absolute order, a soldier must devote his life to his General.",​
 +          "​colors":​ [
 +            "​Red",​
 +            "​Black",​
 +            "​Purple"​
 +          ],
 +          "​name":​ "​General Kocioraw"​
 +        },
 +        "​playerTwoHero":​ {
 +          "​mana":​ 2,
 +          "​description":​ "​Premium card: Glory to all we see, glory to all he is, glory to everyone who will try to escape him.",
 +          "​colors":​ [
 +            "​Black",​
 +            "​Red",​
 +            "​Grey"​
 +          ],
 +          "​name":​ "Lord Royce"
 +        },
 +        "​startingPlayer":​ 1
 +      }
 +</​code>​
 +</​spoiler>​
 +
 +<note tip>
 +Pentru amestecarea cărților, vă recomandăm să folosiți metodele din clasa Random [[https://​docs.oracle.com/​javase/​6/​docs/​api/​java/​util/​Collections.html#​shuffle(java.util.List) | Shuffle]].
 +</​note>​
 +
 +<note important>​
 +Pentru a avea pachetul amestecat cum trebuie de fiecare dată trebuie să **reinstanțiați** clasa Random **la fiecare amestecare**.
 +</​note>​
 +
 +==== Începutul unei runde ====
 +
 +La începutul fiecărei runde, ambii jucători primesc prima carte disponibilă din pachetul de cărți ales. Cartea primită de fiecare jucător va fi adăugată în "​mâna"​ acestuia. Cartea primită este adăugată la sfârșitul listei de cărți din mână. ​
 +
 +<note warning>
 +**Dacă nu mai există cărți în pachet, nu mai trebuie trasă nicio carte în mână.**
 +</​note>​
 +
 +De asemenea, ambii jucători primesc **mana** la începutul fiecărei runde. Mana pe care o primesc jucătorii în prima rundă este 1, urmând ca aceasta sa fie incrementată pana la 10. In momentul în care se ajunge la 10 mana, aceasta nu va mai fi incrementată.
 +
 +<note important>​
 +**Exemplu primire mana** Să presupunem că jucătorii nu folosesc deloc mana. În prima rundă fiecare jucător primește 1 mana. După ce își fac cei 2 tura, începe runda a 2-a. Fiecare jucător primește 2 mana, ceea ce înseamnă că acum ambii jucători au **3 mana**. După ce își fac ambii tura, începe runda a 3-a. Cei 2 jucători primesc 3 mana, ceea ce înseamnă că fiecare are **6 mana** acum ș.a.m.d.
 +</​note>​
 +
 +<note important>​
 +Prima carte care va fi trasă de jucător va fi cea de la **începutul** listei de cărți amestecate ale jucătorului. Mai exact, cea cu index-ul 0 în lista de cărți din deck.
 +</​note>​
 +
 +<note warning>
 +  * O rundă este formată din două ture, una per jucător.
 +  * În cadrul unei ture pot fi făcute mai multe acțiuni de către jucătorul curent.
 +</​note>​
 +
 +==== Sfârșitul unei ture ====
 +
 +La finalul turei unui jucător, cărțile acestuia care au fost marcate ca fiind "​frozen"​ sunt demarcate, întrucât acestea au stat o tura.
 +
 +Totodată, se verifică dacă ambii jucători și-au sfârșit turele în cadrul rundei curente. Dacă această condiție este adevarată, se trece la următoarea rundă si se aplică pașii descriși mai sus.
 +
 +Marcarea sfârșitului unei ture va fi precizată explicit de AI în input pentru jucătorul curent.
 +
 +<spoiler Click pentru input-ul asociat acestui pas>
 +<code json>
 +{
 +    "​command":​ "​endPlayerTurn"​
 +}
 +</​code>​
 +</​spoiler>​
 +
 +<​html>​
 +    <br>
 +</​html>​
 +
 +==== Plasarea unei cărți pe masă ====
 +
 +Cărțile din mână pot fi plasate pe masă, cu condiția ca acestea să nu aibă costul de mana mai mare decât mana jucătorului.
 +
 +Cărțile trebuie plasate pe masă, pe rândul aferent jucătorului,​ dar și al tipului de carte (conform secțiunilor de mai sus).
 +
 +AI-ul vă va preciza în input indexul cărții din mână pe care dorește să o plaseze pe masa.
 +
 +Cazurile invalide trebuie testate la acest pas în această ordine:
 +  - Se verifică dacă cartea are costul mai mic decât mana jucătorului,​ altfel se printează: **”Not enough mana to place card on table.”**
 +  - Se verifică dacă rândul pe care trebuie plasata cartea nu este plin, altfel se printează: **”Cannot place card on table since row is full.”**
 +
 +<spoiler Click pentru input-ul asociat acestui pas>
 +<code json>
 +{
 +    "​command":​ "​placeCard",​
 +    "​handIdx":​ 1
 +}
 +</​code>​
 +</​spoiler>​
 +<spoiler Click pentru output în cazul unei erori>
 +<code json>
 +{
 +    "​command":​ "​placeCard",​
 +    "​handIdx":​ 0,
 +    "​error":​ "Not enough mana to place card on table."​
 +}
 +</​code>​
 +</​spoiler>​
 +
 +
 +<note important>​
 +  * Un jucător poate plasa toate cărțile din mână în cadrul aceleași ture dacă îndeplinește condițiile precizate.
 +  * În input nu se precizează mâna cărui jucător trebuie actualizată,​ drept urmare aceasta comandă va fi activată pentru jucătorul curent.
 +</​note>​
 +
 +==== Comanda de atac a unei cărți ====
 +
 +Fiecare carte plasată pe masă poate ataca altă carte care se află pe masa. În acest pas, se dorește ca viața minion-ului adversar țintit ​ să scadă cu atâtea puncte câte puncte are cartea atacatorului în câmpul **attackDamage**. Daca viața cărții atacate ajunge să fie <= 0, aceasta este **eliminată** de pe masă. O carte poate ataca o altă carte o singură dată per tură. După ce cartea și-a folosit atacul, aceasta nu va mai putea ataca altă carte sau erou decât tura următoare.
 +
 +AI-ul va specifica în input coordonatele de pe masă ale cărții atacate și ale cărții atacatorului.
 +
 +Cazurile invalide care trebuie testate în acest pas sunt:
 +  - Se verifică dacă acea carte atacată este o carte a inamicului, altfel se printează: **”Attacked card does not belong to the enemy.”**.
 +  - Se verifică dacă acea carte a atacatorului nu a atacat/​folosit abilitatea specială deja tura aceasta, altfel se printează: **”Attacker card has already attacked this turn.”**.
 +  - Se verifică dacă acea carte a atacatorului nu este "​frozen",​ altfel se printează: **”Attacker card is frozen.”**.
 +  - Se verifică dacă există o carte Tank pe rândurile adversarului.
 +    - Se verifică mai departe dacă aceasta a fost selectată pentru atac, altfel se printează: **”Attacked card is not of type '​Tank’.”**.
 +
 +<spoiler Click pentru input-ul asociat acestui pas>
 +<code json>
 +{
 +    "​command":​ "​cardUsesAttack",​
 +    "​cardAttacker":​ {
 +         "​x":​ 1,
 +         "​y":​ 0
 +     },
 +     "​cardAttacked":​ {
 +         "​x":​ 3,
 +         "​y":​ 0
 +     }
 +}
 +</​code>​
 +</​spoiler>​
 +<spoiler Click pentru output în cazul unei erori>
 +<code json>
 +{
 +    "​command":​ "​cardUsesAttack",​
 +    "​cardAttacker":​ {
 +      "​x":​ 3,
 +      "​y":​ 1
 +    },
 +    "​cardAttacked":​ {
 +      "​x":​ 3,
 +      "​y":​ 1
 +    },
 +    "​error":​ "​Attacked card does not belong to the enemy."​
 +}
 +</​code>​
 +</​spoiler>​
 +
 +
 +<note important>​
 +  * Dacă o carte este omorâtă, aceasta nu se introduce înapoi în deck-ul jucătorului atacat.
 +  * Dacă adversarul are mai multe cărți de tipul Tank pe rândurile lui, atunci atacatorul trebuie să atace una din cărțile de tipul Tank.
 +</​note> ​
 +
 +==== Comanda de utilizare a abilității unei carti ====
 +
 +Fiecare carte plasată pe masă își poate folosi abilitatea pe altă carte care se află pe masă. Fiecare abilitate specială va avea un efect diferit asupra celui atacat, abilitățile fiind descrise și asociate cu anumiți minioni conform secțiunilor de mai sus.
 +
 +AI-ul va specifica în input coordonatele de pe masă a cărții atacate și a cărții atacatorului.
 +
 +Cazurile invalide trebuie testate la acest pas în această ordine:
 +  - Se verifică dacă cartea atacatorului nu este "​frozen",​ altfel se printează: **”Attacker card is frozen.”**.
 +  - Se verifică dacă cartea atacatorului nu a atacat/​folosit abilitatea specială deja tura aceasta, altfel se printează: **”Attacker card has already attacked this turn.”**.
 +  - Se verifică dacă atacatorul este Disciple.
 +    - Se verifică dacă cartea atacată este o carte aliată, altfel se printează: **”Attacked card does not belong to the current player.”**.
 +  - Se verifică dacă atacatorul este The Ripper, Miraj sau The Cursed One
 +    - Se verifică dacă cartea atacată este o carte a inamicului, altfel se printează: **”Attacked card does not belong to the enemy.”**.
 +    - Se verifică dacă există o carte Tank pe rândurile adversarului.
 +      - Se verifică mai departe dacă aceasta a fost selectată pentru atac, altfel se printează: **”Attacked card is not of type '​Tank’.”**.
 +
 +<spoiler Click pentru input-ul asociat acestui pas>
 +<code json>
 +{
 +    "​command":​ "​cardUsesAbility",​
 +    "​cardAttacker":​ {
 +        "​x":​ 2,
 +        "​y":​ 0
 +     },
 +     "​cardAttacked":​ {
 +        "​x":​ 1,
 +        "​y":​ 0
 +     }
 +}
 +</​code>​
 +</​spoiler>​
 +<spoiler Click pentru output în cazul unei erori>
 +<code json>
 +{
 +    "​command":​ "​cardUsesAbility",​
 +    "​cardAttacker":​ {
 +      "​x":​ 3,
 +      "​y":​ 0
 +    },
 +    "​cardAttacked":​ {
 +      "​x":​ 3,
 +      "​y":​ 0
 +    },
 +    "​error":​ "​Attacker card is frozen."​
 +}
 +</​code>​
 +</​spoiler>​
 +
 +<note important>​
 +  * Se garantează că în input atacatorul este o carte care are abilitate specială.
 +  * Dacă atacatorul este Disciple, nu trebuie să se verifice că minionul atacat este Tank.
 +  * Dacă o carte este omorâtă (caz posibil pentru abilitatea **Shapeshift**),​ aceasta nu se introduce înapoi în deck-ul jucătorului atacat.
 +  * Dacă adversarul are mai multe cărți de tipul Tank pe rândurile lui, este suficient ca cel atacat să fie oricare dintre aceste cărți.
 +</​note> ​
 +
 +==== Comanda de utilizare a atacului unei cărți asupra eroului ====
 +
 +Fiecare carte plasată pe masă poate ataca eroul inamicului. În acest pas, se dorește ca viața eroului să scadă cu atâtea puncte câte are atacatorul atributul **attackDamage**. La finalul comenzii se verifică dacă eroul inamicului a murit, în acest caz jocul fiind câștigat de jucătorul curent.
 +
 +AI-ul va specifica în input coordonatele de pe masă a cărții atacatorului.
 +
 +Cazurile invalide trebuie testate la acest pas în această ordine:
 +  - Se verifică dacă cartea atacatorului nu este "​frozen",​ altfel se printează: **”Attacker card is frozen.”**
 +  - Se verifică dacă cartea atacatorului nu a atacat/​folosit abilitatea specială deja tura aceasta, altfel se printează: **”Attacker card has already attacked this turn.”**
 +  - Se verifică dacă există o carte Tank pe rândurile adversarului.
 +    - Se verifică mai departe dacă aceasta a fost selectată pentru atac, altfel se printează: **”Attacked card is not of type '​Tank’.”**
 +<​note>​
 +În urma atacului, se va verifica dacă eroul adversar mai este în viață. Dacă eroul adversar a fost învins, atunci se va afișa în funcție de caz:  **”Player one killed the enemy hero."​** sau **"​Player two killed the enemy hero."​**.
 +</​note>​
 +
 +<spoiler Click pentru input-ul asociat acestui pas>
 +<code json>
 +{
 +    "​command":​ "​useAttackHero",​
 +    "​cardAttacker":​ {
 +        "​x":​ 3,
 +        "​y":​ 0
 +     }
 +}
 +</​code>​
 +</​spoiler>​
 +
 +<spoiler Click pentru output în cazul unei erori>
 +<code json>
 +  {
 +    "​command":​ "​useAttackHero",​
 +    "​cardAttacker":​ {
 +      "​x":​ 2,
 +      "​y":​ 0
 +    },
 +    "​error":​ "​Attacked card is not of type '​Tank'​."​
 +  }
 +</​code>​
 +</​spoiler>​
 +
 +<spoiler Click pentru output în cazul în care unul din eroi este învins>
 +<code json>
 +{
 +   "​gameEnded":​ "​Player one killed the enemy hero."
 +}
 +</​code>​
 +</​spoiler>​
 +
 +<note important>​
 +  * Se permit doar atacuri directe către eroi, nu și folosirea abilităților speciale pe eroi.
 +  * Nu se permite atacarea propriilor eroi.
 +</​note>​
 +
 +<note warning>
 +Dacă un erou a fost omorât, jocul curent se termină instant. Mai exact, nu se va mai schimba nici tura și nici runda, iar fiecare jucător nu va mai primi mana sau cărți.
 +</​note>​
 +
 +==== Comanda de utilizare a abilității unui erou ====
 +
 +Fiecare erou poate ataca un rând de pe masă. Abilitățile eroilor sunt descrise în secțiunile de mai sus, aceștia având posibilitatea să atace doar minioni ai adversarului sau minioni aliați în funcție de abilitate.
 +
 +AI-ul vă specifică în input rândul ales pentru abilitate.
 +
 +Cazurile invalide trebuie testate la acest pas în această ordine:
 +  - Se verifică dacă jucătorul are destulă mana ca să folosească eroul, altfel se printează: **”Not enough mana to use hero's ability.”**
 +  - Se verifică dacă eroul nu a atacat deja tura aceasta, altfel se printează: **”Hero has already attacked this turn.”**
 +  - Se verifică dacă eroul este **Lord Royce** sau **Empress Thorina**.
 +    - Se verifică mai departe dacă rândul selectat pentru abilitate este un rând al adversarului,​ altfel se printează: **"​Selected row does not belong to the enemy."​**
 +  - Se verifică dacă eroul este **General Kocioraw** sau **King Mudface**.
 +    - Se verifică mai departe dacă rândul selectat pentru abilitate este un rând al jucătorului curent, altfel se printează: **"​Selected row does not belong to the current player.”**
 +
 +<spoiler Click pentru input-ul asociat acestui pas>
 +<code json>
 +{
 +    "​command":​ "​useHeroAbility",​
 +    "​affectedRow":​ 3
 +}
 +</​code>​
 +</​spoiler>​
 +
 +<spoiler Click pentru output în cazul unei erori>
 +<code json>
 +{
 +    "​command":​ "​useHeroAbility",​
 +    "​affectedRow":​ 3,
 +    "​error":​ "​Selected row does not belong to the enemy."​
 +}
 +</​code>​
 +</​spoiler>​
 +
 +<note important>​
 +  * Se garantează în input că eroii nu vor ataca rânduri goale.
 +  * Abilitățile eroilor nu iau în considerare prezența cărților de tip Tank.
 +  * Dacă se folosește abilitatea **Sub-Zero** pe o carte care este deja marcată ca fiind frozen, aceasta va rămâne tot frozen o singură tura.
 +  * Dacă o carte este omorâtă (caz posibil pentru abilitatea **Low Blow**), aceasta nu se introduce înapoi în deck-ul jucătorului.
 +</​note>​
 +
 +===== Comenzi de debug =====
 +
 +Pe parcursul jocului, server-ul vă poate cere oricând anumiți parametri pentru a verifica implementarea voastră.
 +
 +
 +==== Aflarea cărților din mână ====
 +
 +Pentru această comandă trebuie să puneți în output toate cărțile care se află în mâna jucătorului dat ca parametru la input.
 +
 +<spoiler Click pentru input-ul asociat acestui pas>
 +<code json>
 +{
 +    "​command":​ "​getCardsInHand",​
 +    "​playerIdx":​ 2
 +}
 +</​code>​
 +</​spoiler>​
 +
 +<spoiler Click pentru un exemplu de output pentru acest pas>
 +<code json>
 +{
 +    "​command":​ "​getCardsInHand",​
 +    "​playerIdx":​ 2,
 +    "​output":​ [
 +      {
 +        "​mana":​ 4,
 +        "​attackDamage":​ 2,
 +        "​health":​ 7,
 +        "​description":​ "​Premium card: No matter how many, his body will fight. Save your breath for the Mountain is strong.",​
 +        "​colors":​ [
 +          "​Red",​
 +          "​Purple"​
 +        ],
 +        "​name":​ "​Goliath"​
 +      },
 +      {
 +        "​mana":​ 4,
 +        "​attackDamage":​ 4,
 +        "​health":​ 4,
 +        "​description":​ "​Standard card: When he is near, close your eyes. They betray your mind.",​
 +        "​colors":​ [
 +          "​Red",​
 +          "​Black"​
 +        ],
 +        "​name":​ "​Miraj"​
 +      }
 +    ]
 +}
 +</​code>​
 +</​spoiler>​
 +
 +==== Aflarea cărților din pachet ====
 +
 +Pentru această comandă trebuie să puneți în output toate cărțile care se află în deck-ul jucătorului dat ca parametru la input.
 +
 +<spoiler Click pentru input-ul asociat acestui pas>
 +<code json>
 +{
 +    "​command":​ "​getPlayerDeck",​
 +    "​playerIdx":​ 2
 +}
 +</​code>​
 +</​spoiler>​
 +
 +<spoiler Click pentru un exemplu de output pentru acest pas>
 +<code json>
 +{
 +    "​command":​ "​getPlayerDeck",​
 +    "​playerIdx":​ 2,
 +    "​output":​ [
 +      {
 +        "​mana":​ 3,
 +        "​attackDamage":​ 3,
 +        "​health":​ 5,
 +        "​description":​ "​Standard card: He has seen everything, his mind has never been asleep since the making of the realm.",​
 +        "​colors":​ [
 +          "​Brown",​
 +          "​Blue"​
 +        ],
 +        "​name":​ "​Warden"​
 +      }
 +    ]
 +}
 +</​code>​
 +</​spoiler>​
 +
 +==== Afișarea cărților de pe masă ====
 +
 +Pentru această comandă trebuie să afișați la output toate cărțile prezente pe masă. Cărțile trebuie printate începând de la rândul 0, coloana 0 până la rândul 3, coloana 4, conform pozei de mai sus. 
 +
 +<spoiler Click pentru input-ul asociat acestui pas>
 +<code json>
 +{
 +    "​command":​ "​getCardsOnTable"​
 +}
 +</​code>​
 +</​spoiler>​
 +
 +<spoiler Click pentru un exemplu de output pentru acest pas>
 +<code json>
 +{
 +    "​command":​ "​getCardsOnTable",​
 +    "​output":​ [
 +      {
 +        "​mana":​ 3,
 +        "​attackDamage":​ 6,
 +        "​health":​ 3,
 +        "​description":​ "​Premium card: Ravished by the winds of hell, no soul is to be forgiven.",​
 +        "​colors":​ [
 +          "​Orange",​
 +          "​Red",​
 +          "​Black"​
 +        ],
 +        "​name":​ "The Ripper"​
 +      },
 +      {
 +        "​mana":​ 5,
 +        "​attackDamage":​ 4,
 +        "​health":​ 3,
 +        "​description":​ "​Standard card: When he is near, close your eyes. They betray your mind.",​
 +        "​colors":​ [
 +          "​Yellow",​
 +          "​Orange",​
 +          "​Red"​
 +        ],
 +        "​name":​ "​Miraj"​
 +      },
 +      {
 +        "​mana":​ 4,
 +        "​attackDamage":​ 6,
 +        "​health":​ 3,
 +        "​description":​ "​Standard card: Death incarnate. No better time to die than now.",
 +        "​colors":​ [
 +          "​Orange",​
 +          "​Red",​
 +          "​Black"​
 +        ],
 +        "​name":​ "The Ripper"​
 +      },
 +      {
 +        "​mana":​ 3,
 +        "​attackDamage":​ 1,
 +        "​health":​ 8,
 +        "​description":​ "​Standard card: A warrior who is never afraid of battle, no matter the costs",​
 +        "​colors":​ [
 +          "​Brown",​
 +          "​Black",​
 +          "​Grey"​
 +        ],
 +        "​name":​ "​Goliath"​
 +      },
 +      {
 +        "​mana":​ 3,
 +        "​attackDamage":​ 5,
 +        "​health":​ 3,
 +        "​description":​ "​Premium card: Ravished by the winds of hell, no soul is to be forgiven.",​
 +        "​colors":​ [
 +          "​Black",​
 +          "​Yellow"​
 +        ],
 +        "​name":​ "The Ripper"​
 +      },
 +      {
 +        "​mana":​ 3,
 +        "​attackDamage":​ 2,
 +        "​health":​ 5,
 +        "​description":​ "​Standard card: He has seen everything, his mind has never been asleep since the making of the realm.",​
 +        "​colors":​ [
 +          "​Black",​
 +          "​White",​
 +          "​Green"​
 +        ],
 +        "​name":​ "​Warden"​
 +      },
 +      {
 +        "​mana":​ 4,
 +        "​attackDamage":​ 4,
 +        "​health":​ 4,
 +        "​description":​ "​Standard card: When he is near, close your eyes. They betray your mind.",​
 +        "​colors":​ [
 +          "​Red",​
 +          "​Black"​
 +        ],
 +        "​name":​ "​Miraj"​
 +      },
 +      {
 +        "​mana":​ 2,
 +        "​attackDamage":​ 3,
 +        "​health":​ 6,
 +        "​description":​ "​Standard card: He has seen everything, his mind has never been asleep since the making of the realm.",​
 +        "​colors":​ [
 +          "​Brown",​
 +          "​Blue"​
 +        ],
 +        "​name":​ "​Warden"​
 +      },
 +      {
 +        "​mana":​ 4,
 +        "​attackDamage":​ 2,
 +        "​health":​ 7,
 +        "​description":​ "​Premium card: No matter how many, his body will fight. Save your breath for the Mountain is strong.",​
 +        "​colors":​ [
 +          "​Red",​
 +          "​Purple"​
 +        ],
 +        "​name":​ "​Goliath"​
 +      },
 +      {
 +        "​mana":​ 4,
 +        "​attackDamage":​ 1,
 +        "​health":​ 7,
 +        "​description":​ "​Premium card: No matter how many, his body will fight. Save your breath for the Mountain is strong.",​
 +        "​colors":​ [
 +          "​Red",​
 +          "​Purple"​
 +        ],
 +        "​name":​ "​Goliath"​
 +      }
 +    ]
 +  }
 +</​code>​
 +</​spoiler>​
 +
 +<note important>​
 +  * Cărțile de pe masă se vor printa sub forma unei liste începând de la rândul 0 până la rândul 3, de la stânga la dreapta.
 +</​note>​
 +
 +==== Aflarea jucătorului activ ====
 +
 +Pentru această comandă trebuie să printați la output jucătorul activ (adică jucătorul care nu și-a încheiat încă tura).
 +
 +<spoiler Click pentru input-ul asociat acestui pas>
 +<code json>
 +{
 +    "​command":​ "​getPlayerTurn"​
 +}
 +</​code>​
 +</​spoiler>​
 +
 +<spoiler Click pentru un exemplu de output pentru acest pas>
 +<code json>
 +{
 +    "​command":​ "​getPlayerTurn",​
 +    "​output":​ 2
 +}
 +</​code>​
 +</​spoiler>​
 +
 +==== Aflarea eroului unui jucător ====
 +
 +Pentru această comandă trebuie să printați la output eroul jucătorului dat ca parametru la input.
 +
 +<spoiler Click pentru input-ul asociat acestui pas>
 +<code json>
 +{
 +    "​command":​ "​getPlayerHero",​
 +    "​playerIdx":​ 1
 +}
 +</​code>​
 +</​spoiler>​
 +
 +<spoiler Click pentru un exemplu de output pentru acest pas>
 +<code json>
 +{
 +    "​command":​ "​getPlayerHero",​
 +    "​playerIdx":​ 1,
 +    "​output":​ {
 +      "​mana":​ 2,
 +      "​description":​ "​Premium card: An army is not sufficient, he is ready obliterate, it is time for chaos.",​
 +      "​colors":​ [
 +        "​Red",​
 +        "​Black",​
 +        "​Purple"​
 +      ],
 +      "​name":​ "​General Kocioraw",​
 +      "​health":​ 30
 +    }
 +  }
 +</​code>​
 +</​spoiler>​
 +
 +==== Afișarea unei cărții la o poziție dată ====
 +
 +Pentru această comandă trebuie să printați la output cartea aflată la poziția dată în input.
 +
 +<spoiler Click pentru input-ul asociat acestui pas>
 +<code json>
 +{
 +   "​command":​ "​getCardAtPosition",​
 +   "​x":​ 3,
 +   "​y":​ 0
 +}
 +</​code>​
 +</​spoiler>​
 +
 +<spoiler Click pentru un exemplu de output pentru acest pas>
 +<code json>
 +{
 +    "​command":​ "​getCardAtPosition",​
 +    "​x":​ 3,
 +    "​y":​ 0,
 +    "​output":​ {
 +      "​mana":​ 2,
 +      "​attackDamage":​ 0,
 +      "​health":​ 3,
 +      "​description":​ "​Premium card: Nobody suspects an outcast, not even the Gods.",​
 +      "​colors":​ [
 +        "​Black",​
 +        "​White",​
 +        "​Red"​
 +      ],
 +      "​name":​ "The Cursed One"
 +    }
 +}
 +</​code>​
 +</​spoiler>​
 +<spoiler Click pentru un exemplu de eroare pentru acest pas>
 +<code json>
 +{
 +    "​command":​ "​getCardAtPosition",​
 +    "​x":​ 3,
 +    "​y":​ 0,
 +    "​output":​ "No card available at that position."​
 +}
 +</​code>​
 +</​spoiler>​
 +
 +<note important>​Dacă nu există o carte la poziția dată, veți printa "No card available at that position."​.</​note>​
 +
 +
 +==== Afișarea manei unui jucător ====
 +
 +Pentru această comandă trebuie să printați la output mana unui jucător primit la input.
 +
 +<spoiler Click pentru input-ul asociat acestui pas>
 +<code json>
 +{
 +    "​command":​ "​getPlayerMana",​
 +    "​playerIdx":​ 2
 +}
 +</​code>​
 +</​spoiler>​
 +
 +<spoiler Click pentru un exemplu de output pentru acest pas>
 +<code json>
 +{
 +    "​command":​ "​getPlayerMana",​
 +    "​playerIdx":​ 2,
 +    "​output":​ 3
 +}
 +</​code>​
 +</​spoiler>​
 +
 +==== Afișarea cărților de pe masă care sunt "​frozen"​ ====
 +
 +Pentru această comandă trebuie să printați la output toate cărțile de pe masă care au flag-ul "​frozen"​ setat. Ordinea printării trebuie să respecte ordinea cărților de pe masă, mai exact se începe de la linia 0, coloana 0 și se termină la linia 3, coloana 4.
 +
 +<spoiler Click pentru input-ul asociat acestui pas>
 +<code json>
 +{
 +   "​command":​ "​getFrozenCardsOnTable"​
 +}
 +</​code>​
 +</​spoiler>​
 +
 +<spoiler Click pentru un exemplu de output pentru acest pas>
 +<code json>
 +{
 +  "​command":​ "​getFrozenCardsOnTable",​
 +  "​output":​ [
 +    {
 +      "​mana":​ 1,
 +      "​attackDamage":​ 6,
 +      "​health":​ 4,
 +      "​description":​ "​Premium card: Ravished by the winds of hell, no soul is to be forgiven.",​
 +      "​colors":​ [
 +        "​Orange",​
 +        "​Red",​
 +        "​Black"​
 +      ],
 +      "​name":​ "The Ripper"​
 +    }
 +  ]
 +}
 +</​code>​
 +</​spoiler>​
 +
 +<note important>​Dacă nu există cărți pe masă care să fie "​frozen",​ veți afișa o listă goală.</​note>​
 +
 +===== Comenzi pentru statistici =====
 +
 +Statisticile sunt reprezentate de numărul total de jocuri la care a participat fiecare jucator și numărul total de câștiguri
 +
 +
 +==== Afișarea numărului total de jocuri jucate =====
 +
 +Pentru această comandă va trebui să afișați la output numărul total de jocuri încheiate.
 +
 +<spoiler Click pentru input-ul asociat acestui pas>
 +<code json>
 +{
 +   "​command":​ "​getTotalGamesPlayed"​
 +}
 +</​code>​
 +</​spoiler>​
 +
 +<spoiler Click pentru un exemplu de output pentru acest pas>
 +<code json>
 +{
 +   "​command":​ "​getTotalGamesPlayed",​
 +   "​output":​ 2
 +}
 +</​code>​
 +</​spoiler>​
 +
 +==== Afișarea numărului total de jocuri câștigate =====
 +
 +Pentru această comanda va trebui să afișați la output numărul total de jocuri câștigate de un jucător. Vor exista două comenzi pentru fiecare jucător ("​getPlayerOneWins"​ si "​getPlayerTwoWins"​).
 +
 +<spoiler Click pentru input-ul asociat acestui pas>
 +<code json>
 +{
 +   "​command":​ "​getPlayerOneWins"​
 +}
 +</​code>​
 +</​spoiler>​
 +
 +<spoiler Click pentru un exemplu de output pentru acest pas>
 +<code json>
 +{
 +   "​command":​ "​getPlayerTwoWins",​
 +   "​output":​ 2
 +}
 +</​code>​
 +</​spoiler>​
 +
 +<​html>​
 +<br>
 +</​html>​
 +
 +===== Scheletul de cod ===== 
 +
 +În rezolvarea temei va fi nevoie de folosirea unor obiecte pentru stocarea și maparea datelor primite în format JSON. Scheletul temei vă oferă mai multe clase utile pentru ​ citirea și rularea temei. Acestea se regăsesc în cadrul scheletului astfel:
 +  * Clasele de input din cadrul pachetului fileio : Acestea se vor folosi pentru parsarea datelor de input. Astfel preluați toate informațiile necesare pentru a crea propriile clase pentru rezolvarea temei.
 +  * Clasa Main care este punctul de intrare pentru logica de rezolvare a temei.
 +
 +Pentru a întelege mai bine cum funcționează citirea/​scrie în fișierele JSON vă recomandăm să citiți [[https://​ocw.cs.pub.ro/​courses/​poo-ca-cd/​laboratoare/​tutorial-json-jackson | Json & Jackson]].
 +
 +<note tip> Implementarea voastră va începe din funcția **Main.action**,​ unde veți adăuga în **ArrayNode output** pe parcursul execuției toate output-urile comezilor date. **De asemenea, aveți un mic exemplu în schelet despre cum puteți face asta.** </​note>​
 +
 +<note important>​Output-ul nu trebuie formatat ca în ref-uri, fiindcă se verifică conținutul obiectelor și array-urilor JSON, nu textul efectiv. Cu toate acestea, dacă folosiți Jackson, vă recomandăm să utilizați **PrettyPrinter** [[https://​fasterxml.github.io/​jackson-databind/​javadoc/​2.7/​com/​fasterxml/​jackson/​databind/​ObjectMapper.html#​writerWithDefaultPrettyPrinter() | Documentație PrettyPrinter]]. Totodată, pentru a înțelege cum se poate realiza **scrierea în fișierele JSON de output**, vă sugerăm să consultați [[https://​attacomsian.com/​blog/​jackson-create-json-array|JSON Array]].</​note>​
 +
 +<note tip> Aveți în folder-ul **"​lib"​** toate dependințele necesare pentru rularea temei, mai exact bibliotecile Jackson.</​note>​
 +
 +===== Execuția temei =====
 +
 +  - Se încarcă datele citite din fișierul de test, în format JSON, în obiecte. ​
 +  - Se primesc secvențial acțiuni și se execută pe măsură ce sunt primite, rezultatul lor având efect asupra Repository-ului.
 +  - După executarea unei acțiuni, se afișează rezultatul ei în fișierul JSON de ieșire. ​
 +  - La terminarea tuturor acțiunilor se termină și execuția programului.
 +
 +
 +<note warning>
 +  * După ce clonați repo-ul de pe GitHub, vă rugăm să vă faceți un repository propriu privat în care să vă puneți doar conținutul folder-ului **"​tema"​** de pe repo-ul echipei de POO. Dacă nu puneți folder-ul cu tema la alta cale, **nu o să puteți** să faceți schimbări in Git, deoarece vă aflați în rădăcina repository-ului echipei de POO.
 +  * Pentru ca checker-ul să funcționeze trebuie să deschideți tema din Intellij la calea unde se află folderele **"​src"​**,​ **"​lib"​**,​ **"​ref"​**,​ **"​input"​**. Aveți folder-ul **.idea** pregenerat ca să vă ajute in acest sens. De asemenea, fișier-ul **.iml** contine calea către bibliotecile Jackson. Dacă aveți probleme stergeți folder-ul .idea si fișierul .iml si generațile voi din nou din Intellij.
 +</​note>​
 +
 +===== Recomandări =====
 +
 +  * Tema a fost concepută pentru a vă testa cunoștințele dobândite în urma parcurgerii laboratoarelor 1-3, aceasta putând fi rezolvată doar cu noțiunile invățate din acele laboratoare.
 +  * Tema fiind o specificație destul de stufoasă recomandăm citirea de cel putin două ori a enunțului inainte de inceperea implementării.
 +  * Pentru depanarea diferențelor dintre output-ul vostru si fișierele ref, vă recomandăm [[https://​www.jsondiff.com/​|acest site]].
 +  * Verificați periodic această pagină, deoarece scheletul/​cerința pot suferi modificări în urma unor erori din partea noastră.
 +
 +===== Evaluare =====
 +
 +Punctajul constă din:
 +  * 80p implementare - trecerea testelor
 +  * 10p coding style (vezi checkstyle)
 +  * 5p README clar, concis, explicații axate pe design (flow, interacțiuni)
 +  * 5p folosire git pentru versionarea temei
 +
 +<note important>​Pe pagina [[poo-ca-cd:​administrativ:​barem_teme|Indicații pentru teme]] găsiți indicații despre scrierea readme-ului și 
 + ​**baremul folosit la corectarea temei**. Vă incurajăm să treceți prin el cel puțin odată. </​note>​
 +
 +<note important>​ Pentru a primi punctajul pentru **Git**, după ce ați terminat tema și ați făcut toate commit-urile,​ executați comanda ''​git log > git_log.txt''​ in rădăcina proiectului și adăugați fisierul in arhiva trimisă. </​note>​
 +
 +<note tip>​Pentru folosirea tool-ului **Git** vă punem la dispoziție un tutorial actualizat și amplu despre el la acest [[poo-ca-cd:​resurse-utile:​tutorial-git|link]] și aveți de asemenea și un tutorial despre comenzile pe care puteți să le dați din IntelliJ la acest [[poo-ca-cd:​resurse-utile:​tutorial-intellij-git|link]].</​note>​
 +
 +Depunctările pentru **designul și organizarea codului** se vor scădea din punctajul testelor. Dacă vor apărea depunctări specifice temei în momentul evaluării, nemenționate pe pagina cu depunctări generale, ele se vor încadra în limitele de maxim 10p pentru design, 5p pentru readme. Dacă tema nu respecta cerințele, sau are zero design OOP atunci se pot face depunctari suplimentare.
 +
 +Folosirea git pentru versionare va fi verificata din folderul .git pe care trebuie să îl includeți în arhiva temei. Punctajul se va acorda dacă ați făcut **minim 3 commit-uri relevante și cu mesaj sugestiv**. **NU** este permis să aveți repository-urile de git publice până la deadline-ul hard.
 +
 +**Bonusuri:​**
 +La evaluare, putem oferi bonusuri pentru design foarte bun, cod bine documentat dar și pentru diverse elemente suplimentare alese de voi.
 +
 +<note warning>
 +  * Temele vor fi testate împotriva plagiatului. Orice tentativă de copiere va duce la **anularea punctajului** de pe parcursul semestrului şi **repetarea materiei** atât pentru sursă(e) cât şi pentru destinație(ii),​ fără excepție.
 +  * **Aveți grijă să nu puneți pe Vmchecker fișiere .idea sau .iml**.
 +</​note>​
 +
 +==== Checkstyle ====
 +
 +Unul din obiectivele temei este învățarea respectării code-style-ului limbajului pe care îl folosiți. Aceste convenții (de exemplu cum numiți fișierele, clasele, variabilele,​ cum indentați) sunt verificate pentru temă de către tool-ul [[https://​checkstyle.sourceforge.io/​|checkstyle]].
 +
 +Pe pagina de [[:​poo-ca-cd:​administrativ:​coding_style_ide|Recomandări cod]] găsiți câteva exemple de coding style.
 +
 +Dacă numărul de erori depistate de checkstyle depășește 30, atunci punctele pentru coding-style nu vor fi acordate. Dacă punctajul este negativ, //acesta se trunchiază la 0//.
 +
 +Exemple:
 +  * ''​punctaj_total = 100''​ și ''​nr_erori = 200''​ => ''​nota_finala = 90''​
 +  * ''​punctaj_total = 100''​ și ''​nr_erori = 29''​ => ''​nota_finala = 100''​
 +  * ''​punctaj_total = 80''​ și ''​nr_erori = 30''​ => ''​nota_finala = 80''​
 +  * ''​punctaj_total = 80''​ și ''​nr_erori = 31''​ => ''​nota_finala = 70''​
 +
 +
 +===== Upload temă =====
 +
 +Arhiva o veţi urca pe [[https://​curs.upb.ro/​2024/​mod/​assign/​view.php?​id=57526|VMChecker]],​ unde sunt si informații despre structura ei.
 +
 +===== FAQ =====
 +
 +**Q**: Pot folosi biblioteca "​X"?​\\
 +**A**: Dacă doriți să folosiți o anumită bibliotecă vă recomandăm să întrebați pe forum, ca apoi să o validăm și să o includem și pe Vmchecker.
 +
 +**Q**: Am descoperit edge case-ul "​Y",​ trebuie să îl tratez?\\
 +**A**: Nu. Toate datele necesare pentru soluționarea temei vă sunt date in cerință. Dacă totuși am omis ceva ne puteți contacta pe forum.
 +
 +**Q**: Pot folosi clase de tip "​Enum"​ pentru constante?​\\
 +**A**: Da.
 +
 +**Q**: Ce JDK recomandați?​\\
 +**A**: 11
 +
 +**Q**: Pot să fac în orice ordine testele?\\
 +**A**: Da! Testele au fost concepute sa fie cât mai decuplate și să testeze câte o funcționalitate în întregime. Cu toate astea, vă recomandăm să implementați mai întâi testele 01, 02, 03 deoarece reprezintă preambulul fiecărui joc.
 +===== Resurse și linkuri utile =====
 +
 +  * [[https://​github.com/​oop-pub/​oop-asignments/​tree/​master/​teme/​tema|Schelet de cod]]
 +  * [[https://​curs.upb.ro/​2024/​mod/​forum/​view.php?​id=46751|Forum]]
 +  * [[https://​www.youtube.com/​watch?​v=c3oXzl3kxSw|Hearthstone short gameplay]]
 +  * [[https://​www.youtube.com/​watch?​v=QE6V8NgKLEQ|Gwent short gameplay]]
 +  * [[poo-ca-cd:​administrativ:​barem_teme|Indicații pentru teme]]
 +  * [[poo-ca-cd:​administrativ:​coding_style_ide|Recomandări coding style & javadoc]]
 +
  
poo-ca-cd/arhiva/teme/2024/tema.txt · Last modified: 2025/09/27 10:30 by florian_luis.micu
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