User Tools

Site Tools


Problem constructing authldap
laboratoare:old-exercises
Differences

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

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
laboratoare:old-exercises [2019/11/10 12:49]
Adriana Draghici
laboratoare:old-exercises [2020/01/04 12:19] (current)
Adriana Draghici [Singleton, Observer, Factory]
Line 138: Line 138:
  
 == Clase interne == == Clase interne ==
-  ​ 
-  
   ​   ​
  ​Implementați un terminal bash simplu pornind de la {{ :​laboratoare:​old-exercises:​clase-interne-skel.zip |scheletul de cod}}. Comenzile pe care va știi să le execute sunt: **echo, cd, ls și history**. Bash-ul va citi comenzi de la tastatură până când va primi comanda **exit** când se va închide (programul se termină). ​  ​Implementați un terminal bash simplu pornind de la {{ :​laboratoare:​old-exercises:​clase-interne-skel.zip |scheletul de cod}}. Comenzile pe care va știi să le execute sunt: **echo, cd, ls și history**. Bash-ul va citi comenzi de la tastatură până când va primi comanda **exit** când se va închide (programul se termină). ​
Line 232: Line 230:
  
 == Visitor pattern, Overriding, Overloading == == Visitor pattern, Overriding, Overloading ==
-  - **(2p)** ​Scheletul de laborator conține implementarea folosind pattern-ul Visitor a scenariului Employee-Manager descris [[.:​visitor#​scenariu-visitor| in laborator]]. Spre deosebire de exemplele din laborator, clasa Employee conține și câmpul extraHours, relevant pentru exercițiul 3.+  - Scheletul de laborator conține implementarea folosind pattern-ul Visitor a scenariului Employee-Manager descris [[.:​visitor#​scenariu-visitor| in laborator]]. Spre deosebire de exemplele din laborator, clasa Employee conține și câmpul extraHours, relevant pentru exercițiul 3.
          * a) Rulați codul și observați comportamentul și interacțiunea dintre obiectele vizitate și obiectul de tip Visitor.          * a) Rulați codul și observați comportamentul și interacțiunea dintre obiectele vizitate și obiectul de tip Visitor.
          * b) Nu mai suprascrieți metoda ''​accept''​ din //​Manager//,​ rulați și explicați rezultatul execuției.          * b) Nu mai suprascrieți metoda ''​accept''​ din //​Manager//,​ rulați și explicați rezultatul execuției.
-  - **(5p)** ​Obiectele Employee-Manager pot fi reprezentate printr-o structură arborescentă,​ ce are ca rădăcină un Manager (ceo-ul). Creați un Visitor care să permită parcurgerea ierarhiei și efectuarea unei acțiuni pe fiecare nod. Acea acțiune este practic o operație, implementată într-o altă clasă de tip Visitor, deci TreeVisitor-ul va primi un obiect de tip Visitor pe care să îl aplice pe nodurile parcurse.+  - Obiectele Employee-Manager pot fi reprezentate printr-o structură arborescentă,​ ce are ca rădăcină un Manager (ceo-ul). Creați un Visitor care să permită parcurgerea ierarhiei și efectuarea unei acțiuni pe fiecare nod. Acea acțiune este practic o operație, implementată într-o altă clasă de tip Visitor, deci TreeVisitor-ul va primi un obiect de tip Visitor pe care să îl aplice pe nodurile parcurse.
        * fiecare //Manager// va ţine referinţe către angajaţii aflaţi sub răspunderea lui directă (ce pot fi alţi șefi la rândul lor, sau salariaţi obişnuiţi)        * fiecare //Manager// va ţine referinţe către angajaţii aflaţi sub răspunderea lui directă (ce pot fi alţi șefi la rândul lor, sau salariaţi obişnuiţi)
        * implementați un //​TreeVisitor//​ care pentru:        * implementați un //​TreeVisitor//​ care pentru:
Line 241: Line 239:
              * //Manager// - parcurge subordonații și apoi aplică operația primită pe Manager              * //Manager// - parcurge subordonații și apoi aplică operația primită pe Manager
        * implementați un visitor (numit //​MostHardworkingEmployeeFinder//​) care compară numărul mediu de ore suplimentare pentru angajați cu cel pentru șefi. ​        * implementați un visitor (numit //​MostHardworkingEmployeeFinder//​) care compară numărul mediu de ore suplimentare pentru angajați cu cel pentru șefi. ​
-   ​- ​**(3p)** ​Adăugați încă un tip de obiect vizitabil - //Intern//. Acesta nu are salariu și extra hours, doar nume și durata (în luni) a internship-ului. ​+   - Adăugați încă un tip de obiect vizitabil - //Intern//. Acesta nu are salariu și extra hours, doar nume și durata (în luni) a internship-ului. ​
        * modificați clasele existente deja, pentru a lua în considerare și obiectele Intern        * modificați clasele existente deja, pentru a lua în considerare și obiectele Intern
        * testați operațiile de la exercițiile anterioare pe o colecție care conține și obiecte Intern ​        * testați operațiile de la exercițiile anterioare pe o colecție care conține și obiecte Intern ​
        * :!: Observați modificările pe care le-ați efectuat pentru a adăuga o nouă operație (ex. 2) și pe cele pentru a adăuga un nou tip de obiect în colecție. Ca să merite să aplicăm pattern-ul Visitor, ce situație ar trebui să fie evitată?        * :!: Observați modificările pe care le-ați efectuat pentru a adăuga o nouă operație (ex. 2) și pe cele pentru a adăuga un nou tip de obiect în colecție. Ca să merite să aplicăm pattern-ul Visitor, ce situație ar trebui să fie evitată?
        ​{{:​laboratoare:​visitor:​employee-manager-visitor.jpg?​500|}}        ​{{:​laboratoare:​visitor:​employee-manager-visitor.jpg?​500|}}
-   ​- ​**(bonus - 2p)** Găsiți folosind java.nio toate fișierele cu extensia "​.class"​ dintr-un director. ​+   - Găsiți folosind ​''​java.nio'' ​toate fișierele cu extensia "​.class"​ dintr-un director. ​
        * implementați un [[http://​docs.oracle.com/​javase/​8/​docs/​api/​index.html?​java/​nio/​file/​FileVisitor.html | FileVisitor]],​ extinzând [[http://​docs.oracle.com/​javase/​8/​docs/​api/​java/​nio/​file/​SimpleFileVisitor.html | SimpleFileVisitor]] în care suprascrieți metoda de vizitare a fișierelor ​        * implementați un [[http://​docs.oracle.com/​javase/​8/​docs/​api/​index.html?​java/​nio/​file/​FileVisitor.html | FileVisitor]],​ extinzând [[http://​docs.oracle.com/​javase/​8/​docs/​api/​java/​nio/​file/​SimpleFileVisitor.html | SimpleFileVisitor]] în care suprascrieți metoda de vizitare a fișierelor ​
         * un exemplu similar găsiți în [[http://​docs.oracle.com/​javase/​tutorial/​essential/​io/​walk.html | acest tutorial]]         * un exemplu similar găsiți în [[http://​docs.oracle.com/​javase/​tutorial/​essential/​io/​walk.html | acest tutorial]]
Line 253: Line 251:
 * {{.:​visitor:​skel-visitor-manager-employee.zip| Schelet cod}} * {{.:​visitor:​skel-visitor-manager-employee.zip| Schelet cod}}
  
 +== Colecții ==
 +
 +  - Instanţiati o colecţie care sǎ **nu** permitǎ introducerea elementelor duplicate, folosind o implementare corespunzǎtoare din bibliotecă. La introducerea unui element existent, semnalaţi eroare. Colecţia va reţine ''​String''​-uri şi va fi parametrizatǎ.
 +  - Creaţi o clasǎ ''​Student''​.
 +    - Adǎugaţi urmǎtorii membri:
 +       * **câmpurile** ''​nume''​ (de tip ''​String''​) şi ''​medie''​ (de tip ''​float''​)
 +       * un **constructor** care îi iniţializeazǎ
 +       ​* ​ metoda ''​toString''​.
 +    -  Folosiţi codul de la **exerciţiul anterior** şi modificaţi-l astfel încât colecţia aleasǎ de voi sǎ reţinǎ obiecte de tip ''​Student''​. Testaţi prin adǎugare de elemente duplicate, având aceleaşi valori pentru toate câmpurile, instanţiindu-le,​ de fiecare datǎ, cu ''​new''​. Ce observaţi?
 +    - Prelucraţi implementarea de mai sus astfel încât colecţia sǎ reprezinte o tabelǎ de dispersie, care calculează codul de dispersie al elementelor dupǎ un criteriu ales de voi (puteţi suprascrie funcţia **hashCode**).
 +       * În ''​Student''​ suprascrieți metoda ''​equals''​ astfel încât să se ţină cont de câmpurile clasei, şi încercaţi din nou. Ce observaţi?
 +    * //Hint:// [[http://​docs.oracle.com/​javase/​8/​docs/​api/​java/​util/​Set.html#​add(E)|Set.add]],​ [[http://​docs.oracle.com/​javase/​8/​docs/​api/​java/​lang/​Object.html#​equals(java.lang.Object)|Object.equals]],​ [[http://​docs.oracle.com/​javase/​8/​docs/​api/​java/​lang/​Object.html#​hashCode()|Object.hashCode]]
 +  - Plecând de la implementarea exerciţiului anterior, realizaţi urmǎtoarele modificǎri:​
 +     * Supraîncǎrcaţi,​ în clasa ''​Student'',​ metoda ''​equals'',​ cu o variantǎ care primeşte un parametru ''​Student'',​ şi care întoarce întotdeauna ''​false''​.
 +     * Testaţi comportamentul prin crearea unei colecţii ce conţine instanţe de ''​Student''​ şi iteraţi prin această colecţie, afişând la fiecare pas ''​element.equals(element)''​ şi ''​%%((Object)element).equals(element)%%''​ (unde ''​element''​ este numele de variabilă ales pentru fiecare element al colecţiei). Cum explicaţi comportamentul observat? Dacă folosiţi un iterator, acesta va fi şi el **parametrizat**.
 +  - Creați clasa ''​Gradebook'',​ de tip ''​Map'',​ pentru reţinerea studenţilor dupǎ medie: cheile sunt mediile și valorile sunt liste de studenți. Gradebook va menţine cheile **ordonate descrescǎtor**. Extindeţi o implementare potrivitǎ a interfeţei ''​Map'',​ care sǎ permitǎ acest lucru.
 +    - Caracteristicile clasei definite sunt:
 +      - Cheile pot avea valori de la 0 la 10 (corespunzǎtoare mediilor posibile). Verificați acest lucru la adăugare.
 +      - Valoarea asociată fiecǎrei chei va fi o listǎ (''​List''​) care va reţine toţi studenţii cu media rotunjitǎ egalǎ cu cheia. Considerǎm cǎ un student are media rotunjitǎ 8 dacǎ media sa este în intervalul [7.50, 8.49].
 +     - Implementați un [[http://​docs.oracle.com/​javase/​8/​docs/​api/​java/​util/​Comparator.html|Comparator]] pentru stabilirea ordinii cheilor. Gradebook va primi un parametru de tip ''​Comparator''​ în constructor și îl va da mai departe constructorului clasei moștenite.
 +     - Definiţi în clasǎ metoda ''​add(Student)'',​ ce va adǎuga un student în lista corespunzǎtoare mediei lui. Dacǎ, în prealabil, nu mai existǎ niciun student cu media respectivǎ (rotunjitǎ),​ atunci lista va fi creatǎ la cerere.
 +    - Testați clasa:
 +      - instanțiați un obiect Gradebook și adăugați in el câţiva studenţi.
 +      - iteraţi pe Gradebook şi sortaţi alfabetic fiecare listǎ de studenţi pentru fiecare notă. Pentru a sorta, se va folosi metoda [[https://​docs.oracle.com/​javase/​8/​docs/​api/​java/​util/​Collections.html#​sort-java.util.List-|Collections.sort]],​ iar clasa Student va implementa o interfață care specifică modul în care sunt comparate elementele.
 +        * clasa ''​Student''​ va implementa interfaţa [[http://​docs.oracle.com/​javase/​8/​docs/​api/​java/​lang/​Comparable.html|Comparable]],​ suprascriind metoda [[http://​docs.oracle.com/​javase/​8/​docs/​api/​java/​lang/​Comparable.html#​compareTo(T)|compareTo]].
 +  - Creaţi o clasǎ care moşteneşte ''​HashSet<​Integer>''​.
 +    * Definiţi în aceastǎ clasǎ o variabilǎ membru care reţine numǎrul total de elemente adǎugate. Pentru a contoriza acest lucru, suprascrieți metodele ''​add''​ şi ''​addAll''​. Pentru adǎugarea efectivǎ a elementelor,​ folosiţi implementǎrile din clasa pǎrinte (''​HashSet''​).
 +    * Testaţi, folosind atât ''​add''​ cât şi ''​addAll''​. Ce observaţi? Corectaţi dacǎ este cazul.
 +    * Modificaţi implementarea astfel încât clasa voastrǎ sǎ moşteneascǎ ''​LinkedList<​Integer>''​. Ce observaţi? Ce **concluzii** trageţi?
 +    * Hint: [[http://​docs.oracle.com/​javase/​8/​docs/​api/​java/​util/​Collection.html#​add(E)|Collection.add]],​ [[http://​docs.oracle.com/​javase/​8/​docs/​api/​java/​util/​Collection.html#​addAll(java.util.Collection)|Collection.addAll]].
 +    * Hint: implementarea ''​addAll''​ din sursele pentru [[http://​grepcode.com/​file/​repository.grepcode.com/​java/​root/​jdk/​openjdk/​8u40-b25/​java/​util/​HashSet.java#​HashSet|HashSet]] şi [[http://​grepcode.com/​file/​repository.grepcode.com/​java/​root/​jdk/​openjdk/​8u40-b25/​java/​util/​LinkedList.java#​LinkedList|LinkedList]].
 +
 +
 +== Excepții ==
 +
 +  - **(2p)** ​ Scrieţi o metodă (scurtă) care să genereze [[http://​docs.oracle.com/​javase/​7/​docs/​api/​java/​lang/​OutOfMemoryError.html|OutOfMemoryError]] şi o alta care să genereze [[http://​docs.oracle.com/​javase/​7/​docs/​api/​java/​lang/​StackOverflowError.html|StackOverflowError]]. ​ Verificaţi posibilitatea de a continua rularea după interceptarea acestei erori. Comparaţi răspunsul cu posibilitatea de a realiza acelaşi lucru într-un limbaj compilat, ce rulează direct pe platforma gazdă (ca C).
 +  - **(2p)** Demonstraţi într-un program execuţia blocului ''​finally''​ chiar şi în cazul unui ''​return''​ din metoda.
 +
 +== Design Patterns ==
 +
 +=== Singleton, Observer, Factory ===
 +Exercițiile din această secțiune și din urmatoarea au ca temă comună realizarea unui joc controlat din consolă. Jocul constă dintr-o lume (aka hartă) în care se plimbă eroi de trei tipuri, colectează comori și se bat cu monștri. În acestă secțiune trebuie să implementați o parte din funcționalitățile jocului folosind patternurile //​Singleton//,​ //Factory// și //​Observer//,​ urmând ca în secțiunea următoare să terminați implementarea.
 +
 +Schelet: {{.:​design-patterns:​design-patterns1-skel.zip|Schelet}}
 +
 +Detalii joc:
 +* //Harta//
 +   * reprezentată printr-o matrice. Fiecare element din matrice reprezintă o zonă care poate fi liberă, poate conține obstacole sau poate conține o comoară (în secțiunea următoare poate conține și monștrii).
 +   * este menținută în clasa ''​World''​.
 +* //​Eroii// ​
 +   * sunt reprezentați prin clase de tip ''​Hero''​ și sunt de trei tipuri: //Mage//, //​Warrior//,​ //Priest//.
 +   * puteți adăuga oricâți eroi doriți pe hartă (cât vă permite memoria :))
 +   * într-o zonă pot fi mai mulți eroi
 +   * acțiunile pe care le pot face:
 +     * ''​move''​ - se mută într-o zonă învecinată
 +     * ''​attack''​ (de implementat în laboratorul următor)
 +     * ''​collect''​ - eroul ia comoara găsită în zona în care se află
 +* Entry-point-ul în joc îl consitituie clasa ''​Main''​.
 +* Folosiți design pattern-ul //Factory// pentru crearea obiectelor.
 +  - Creati clase care mostenesc ''​Hero''​ pentru fiecare tip de erou.
 +       * suprascrieti metoda ''​toString''​ din ''​Object''​ pentru fiecare erou
 +       * metoda ''​attack''​ - deocamdată nu va omorî pe nimeni - puteți afișa ceva la consolă
 +  - Uitați-vă la clasele ''​TreasureFactory''​ și ''​HeroFactory''​. Trebuie să implementăm două metode: ''​createTreasure''​ în ''​TreasureFactory''​ și o metodă de creare de eroi în ''​HeroFactory'',​ fie ea ''​createHero''​.
 +    - Puteți pune orice date doriți în comori, respectiv eroi.
 +    - La ''​HeroFactory.createHero'',​ pasați ca parametru un ''​Hero.Type''​ și un ''​String''​ cu numele eroului și întoarceți un subtip de ''​Hero''​ potrivit pentru tipul de erou.
 +  - După ce ați creat factory-urile,​ folosiți-le:​
 +    - Completați metoda ''​populateTreasures''​ din ''​World''​. Folosiți-vă de membrii ''​map''​ și ''​treasures''​ din ''​World''​. Trebuie să marcați pe hartă că aveți o comoară și să adăugați obiectul-comoară în lista de comori.
 +    - Uitați-vă apoi la cazul ''​add''​ din metoda ''​main''​. Trebuie să adăugați eroi acolo. Folosiți ''​HeroFactory.createHero''​.
 +* Folosiți design pattern-ul //​Singleton//​ pentru elementele din joc care trebuie să aibă doar o instanță.
 +  * Ce clase vor avea doar o singură instanță?
 +* Folosiți design pattern-ul //​Observer//​ pentru a monitoriza ceea ce se întâmplă în joc. Scheletul de cod vă sugerează două tipuri de observatori,​ pentru bonus puteți adăuga și alții.
 +  - veți folosi interfața [[https://​docs.oracle.com/​javase/​8/​docs/​api/​java/​util/​Observer.html|Observer]] și clasa [[https://​docs.oracle.com/​javase/​8/​docs/​api/​java/​util/​Observable.html|Observable]] din java.util.
 +    - Înainte să vă apucați să scrieți, citiți comentariile din cod (e.g. TreasureDiscoverer) să vă faceți o idee despre ce vrem să facem în clasele observatoare.
 +    - Asigurati-va ca implementati corect functionalitatea din **Observable**. Mare atentie la faptul ca **metoda notifyObservers nu va face nimic daca nu este apelata mai intai metoda setChanged**.
 +  - Care sunt elementele observatoare și care sunt observabile?​ Uitați-vă și în comentariile din cod.
 +  - Implementați interfețele ''​Observer''​ și ''​Observable''​ în clasele potrivite.
 +  - Înregistrați observatori la ''​World''​. Cazul ''​start''​ din metoda ''​main''​.
 +  - Notificați observatorii lui ''​World''​ când eroii execută o acțiune. Aveți două ''​TODO''​-uri în clasa ''​Hero''​.
 +* Începeți rezolvarea prin implementarea claselor pentru eroi și implementarea design pattern-ului factory pentru crearea lor. Pentru a putea vizualiza harta trebuie să implementați partea de observare a stării jocului. ''​World''​ trebuie să fie observabilă și să notifice pe observatorii săi atunci când a început jocul și când se schimbă ceva (e.g. s-a mutat un erou).
 +    * Urmăriți **todo**-urile din scheletul de cod (pentru a le vizualiza mai ușor pe toate puteți să folosiți view-ul pt ele din IDE, de exemplu în eclipse aveți //Window -> Show View -> Tasks//)
 +
 +<​imgcaption exercitii|>​
 +{{:​laboratoare:​design-patterns:​exercitiu.png|Componentele jocului}}</​imgcaption>​
 +
 +=== Strategy, Command ===
 +Această secțiune și cea precedentă au ca temă comună a exercițiilor realizarea unui joc controlat din consolă. Jocul constă dintr-o lume (aka hartă) în care se plimbă eroi de trei tipuri, colectează comori și se bat cu monștrii. În acestă secțiune terminam jocul inceput in cea precedenă folosind pattern-urile //​Strategy//​ și //​Command//​.
  
 +Detalii joc:
 +* //Harta//
 +   * reprezentată printr-o matrice. Fiecare element din matrice reprezintă o zonă care poate fi liberă, poate conține obstacole, monștrii sau o comoară
 +   * este menținută în clasa ''​GameState''​.
 +* //​Eroii// ​
 +   * sunt reprezentați prin clase de tip ''​Hero''​ și sunt de trei tipuri: //Mage//, //​Warrior//,​ //Priest//.
 +   * puteți adăuga oricâți eroi doriți pe hartă (cât vă permite memoria :))
 +   * într-o zonă pot fi mai mulți eroi
 +   * acțiunile pe care le pot face:
 +     * ''​move''​ - se mută într-o zonă învecinată
 +     * ''​attack''​ - ataca un monstru cand se afla pe aceeasi pozitie cu el
 +     * ''​collect''​ - eroul ia comoara găsită în zona în care se află
 +* Entry-point-ul în joc îl consitituie clasa ''​Main''​.
 +* Folosiți design pattern-ul //Command// pentru a implementa functionalitatea de undo si redo la comanda ''​move''​.
 +   * Momentan, aveti erori de compilare in clasele Main si GameState. Dupa ce veti implementa acest exercitiu, se vor rezolva, nu modificati in mod direct acolo.
 +   * Va trebui sa completati clasa ''​MoveCommand''​ care implementeaza interfata ''​Command''​. Urmariti //​TODO-urile//​ din aceasta clasa. ​
 +   * //​__Hint__//:​ Pentru Undo, de exemplu, daca v-ati deplasat la dreapta, ar trebui sa va deplasati la stanga. Creati-va o metoda ajutatoare care trateaza astfel de cazuri.
 +   * Precum si clasa ''​CommandManager''​ care va tine evidenta comenzilor si ordinea lor. 
 +   * //​__Hint__//:​ Amintiti-va de la cursul de Structuri de Date cum se implementează operatiile Redo si Undo. Folositi doua stive.
 +* Folosiți design pattern-ul //​Strategy//​ pentru a implementa logica de atac a unui monstru.
 +   * Pentru acest exercitiu va trebui sa implementati 2 strategii: **AttackStrategy** si **DefenseStrategy**. Ambele vor implementa Strategy si metodele aferente. Fiecare din aceste Strategy, va retine o referinta interna la un Hero. Abordarea este urmatoarea:
 +    * Exista 3 clase Hero, fiecare cu cate un DamageType aferent: Warrior - Blunt, Mage - Magic, Priest - Poison ​
 +    * Fiecare monstru are un weakness (slabiciune la atacurile de tip Blunt, Magic sau Poison)
 +    * **AttackStrategy**:​ In metoda attack(), veti itera prin inventory-ul eroului si veti verifica daca exista un obiect Treasure care are DamageType-ul identic cu cel al eroului. Daca da, atunci damage-ul pe care il veti da unui obiect Monster este **3 x damage-ul treasure-ului**. Daca nu aveti un astfel de Treasure, atunci cautati un Treasure cu un DamageType identic cu cel al mob-ului (mobul poate fi vulnerabil la Magic, de ex.). Daca gasiti un astfel de Treasure, damage-ul pe care il veti imprima mob-ului este **2 x damage-ul treasure-ului**. Daca nu, veti scade din HP-ul mob-ului rezultatul apelului metodei getBaseDamage() asupra Hero-ului.
 +    * **DefenseStrategy**:​ In metoda attack(), veti itera prin inventory-ul eroului si veti verifica, la fel, daca exista un obiect Treasure care are DamageType-ul identic cu cel al eroului. Daca da, atunci veti da un boost de HP egal cu treasure.getBoostHp() + getBaseHpBoost() eroului (getBaseHpBoost este implementata in clasa Hero). Daca nu, veti da doar un boost egal cu ce va intoarce getBaseHpBoost(). Damage-ul imprimat mobului va fi, de asemenea, egal cu ce va intoarce getBaseDamage(). Adaugati log-uri in clasa DefenseStrategy,​ pentru a va asigura ca i se mareste viata eroului.
 +    * Urmariti si TODO-urile din cele doua clase
 +   * Implementati metoda //attack// din clasa **Hero** astfel incat, daca eroul are mai mult de **50HP**, folositi strategia **AttackStrategy**. Altfel, folositi **DefenseStrategy**. Urmariti TODO-urile din cod.
 +* Implementați coliziunile cu obstacolele de pe hartă
 +  * Va trebui sa creati un nou obiect ''​Obstacle''​ precum si un ''​ObstacleObserver''​
 +  * Cand eroul ajunge pe un obstacol se va printa un mesaj ''​Can'​t move there !''​ si se va apela automat undo pe ultima comanda de move pentru a reveni in pozitia anterioara coliziunii. Acest feature de wall collision va fi implementat in ''​ObstacleObserver''​
laboratoare/old-exercises.1573382965.txt.gz · Last modified: 2019/11/10 12:49 by Adriana Draghici