Tema propune implementarea unor elemente legate de jocul de un singur jucător Light Up. Pentru familiarizare, puteți juca jocul aici.
Tema este împărțită în 2 etape:
Deadline-ul depinde de semigrupa în care sunteți repartizați. Restanțierii care refac tema și nu refac laboratorul beneficiază de ultimul deadline, și anume în zilele de 23.05, respectiv 30.05.
Rezolvările tuturor etapelor pot fi trimise până în ziua laboratorului 12 (deadline hard pentru toate etapele). Orice exercițiu trimis după un deadline soft se punctează la jumătate. Cu alte cuvinte, nota finală pe etapă se calculează conform formulei: n = (n1 + n2) / 2 (n1 = nota obținută înainte de deadline; n2 = nota obținută după deadline). Când toate submisiile preced deadline-ul, nota pe ultima submisie constituie nota finală (întrucât n1 = n2).
În fiecare etapă, veți valorifica ce ați învățat în săptămâna anterioară și veți avea la dispoziție un schelet de cod, cu toate că rezolvarea se bazează în mare măsură pe etapele anterioare. Enunțul caută să ofere o imagine de ansamblu atât la nivel conceptual, cât și în privința aspectelor care se doresc implementate, în timp ce detaliile se găsesc direct în schelet.
Jocul Light Up se joacă pe o tablă rectangulară – pentru simplitate vom presupune în această temă că tabla este întotdeauna pătrată – unde pot exista o serie de celule indisponibile – le vom numi pereți. Unii pereți pot avea asociate numere între 0 și 4.
În celulele unde nu sunt pereți se pot plasa becuri (lumini). O lumină plasată într-o celulă va lumina pe toate celulele pe aceeași verticală și pe aceeași orizontală cu poziția becului până la primul perete în fiecare direcție.
Obiectivul jocului este ca toate celulele fără pereți de pe tabla de joc să fie luminate, fără ca vreun bec să fie pe o celulă luminată de un alt bec. Dacă un perete are un număr, atunci pe pozițiile vecine rectangular (nu și diagonal) cu peretele trebuie să existe exact acel număr de becuri, nu mai multe, nu mai puține. O variantă rezolvată a tablei din imaginea anterioară poate fi văzută mai jos.
În această temă, trebuie să acoperiți următoarele puncte:
În etapa 1 ne interesează reprezentarea tablei de joc, accesul și modificarea acestei reprezentări, și calculul celulelor luminate.
În ambele etape veți lucra numai în fișierul lightup.pl
.
intern_*
și tt*
, nu aveți nevoie de ele.Faceți o implementare cât mai generală, nu hardcodați lucruri. De principiu, fiecare predicat ar trebui să aibă 1-2-3 reguli, și cele mai multe din această etapă se pot implementa nerecursiv.
În prima parte trebuie să dezvoltați o reprezentare a tablei de joc. Această reprezentare poate fi construită cum doriți. Ea trebuie să conțină informații despre:
Reprezentarea va fi construită și accesată numai prin intermediul predicatelor pe care le scrieți voi. Testerul va considera reprezentarea unei table ca fiind opacă și nu va parsa reprezentarea în niciun fel. Puteți alege ce reprezentare doriți. De exemplu, puteți folosi liste de liste (ca să reprezentați ca o matrice), sau o listă de tupluri care conțin poziția și informațiile despre o celulă. Sau orice altă reprezentare doriți.
În testarea unui nivel, vor exista două faze:
empty_state
și set_walls
pentru a construi reprezentarea unei table B
;B
rezultată, a predicatelor get_board_size
, is_wall
, și get_number
;add_light
și is_lit
.
Important: nu citiți direct reprezentarea nivelurilor din levels.pl
. Reprezentările corespunzătoare fiecărei table vor fi construite element cu element de către checker prin apeluri ale predicatelor corespunzătoare implementate de voi.
Reprezentăm o poziție pe tablă, în argumentele predicatelor, ca o pereche (X, Y)
, cu X
și Y
coordonatele corespunzătoare, 0-based, cu poziția (0, 0)
în colțul din stânga-sus al hărții.
Descrierea fiecărui predicat, împreună cu specificațiile sale, se găsește în schelet.
util.pl
make_repeat_list/3
și set_list_index/4
din util.pl
.nth0/3
din prolog, care poate fi folosit și pentru a afla ce element se află la un anumit index într-o listă, dar și pentru a afla la ce index se află un element într-o listă.member/2
din prolog. De exemplu, dacă avem o listă L = [(a, 1), (b, 2), (c, 3), (d, 4)]
și apelăm member((c, X), L)
, Prolog va lega X
la 3, pentru că a găsit elementul (c, 3)
în listă.is_wall(B, (X, Y)) :-
condiții – Prolog îmi va lega X
și Y
la coordonatele din poziția dată ca argument; sauis_wall(B, Pos) :- Pos = (X, Y),
alte condiții – Prolog îmi va lega X
și Y
la coordonatele din poziția dată ca argument.between(A, B, X)
, care poate fi folosit atât pentru a afla dacă X
este între A
și B
(inclusiv), dar și pentru a genera numere din intervalul [A, B]
.În etapa a doua veți implementa rezolvarea jocului Light Up. O soluție a jocului are următoarele proprietăți:
Veți avea de implementat predicate pentru:
Hints specifice pentru fiecare predicat sunt disponibile în schelet.
Încărcați în Prolog fișierul lightup.pl
. Pentru testare folosiți predicatele check
sau vmcheck
. Pentru teste individuale folosiți vmtest(<nume_test>).
, e.g. vmtest(b0)
. Vedeți și observația de la începutul fișierului testing.pl
.
La trimiterea temei, este suficient să puneți în arhivă fișierul lightup.pl
.
Testele se află în fișierul testing.pl
. Tipurile testelor sunt descrise succint la începutul fișierului. Pentru a verifica un test, puteți face o interogarea în consolă care conține scopurile plasate (de obicei) între ghilimele în primul argument al testului.
De exemplu, pentru a replica testul b0|a
puteți interoga la consolă:
set_empty_board(8, B)
iar pentru testul wall|c
:
ttSet(wn1, B)
Pentru rezultate mai detaliate ale testării, linia %detailed_mode_disabled :- !, fail.
din fișierul testing.pl
este decomentată. Atenție! În acest caz, este posibil ca punctarea să fie diferită decât rezultatul de pe vmchecker, unde linia este comentată. Dacă rezultatele detaliate nu apar, comentați la loc linia, apelați interogarea make, check.
apoi decomentați din nou și apelați interogarea make, check
din nou.
is_free
întoarce fals dacă este deja o lumină acolo.