Table of Contents

Prolog: Bloxorz

Obiective

Observații preliminare

Tema propune implementarea câtorva elemente din mecanica jocului Bloxorz. Puteți juca Bloxorz 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 24.05, respectiv 31.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.

Perspectivă generală

Fiecare nivel (stage) din Bloxorz conține o suprafață de joc formată din pătrățele (tiles) care pot fi normale sau au diverse proprietăți. Jucătorul controloează un bloc care trebuie dus prin mișcări sus / jos / dreapta / stânga până la trecerea printr-o pătrățică lipsă din suprafața de joc (o numim scop sau gaură). Puteți urmări rezolvarea nivelurilor de Bloxorz aici.

Aveți în directorul ref un fișier cu codurile pentru fiecare nivel (1-6) și cu imagini ale stării intițiale pentru fiecare nivel.

În această temă, trebuie să acoperiți următoarele puncte:

Etapa 1

În etapa 1 ne interesează reprezentarea stării și implementarea mecanicii principale de mișcare a blocului (fără partea de switches).

În ambele etape veți lucra numai în fișierul blox.pl.

Faceți o implementare cât mai generală, nu hardcodați lucruri. De principiu, fiecare predicat ar trebui să aibă 1-2-3 reguli. De exemplu, nu faceți reguli separate pentru cele 4 direcții, ci folosiți neighbors din util.pl.

Reprezentare

În prima parte trebuie să dezvoltați o reprezentare a stării jocului. 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 stări ca fiind opacă și nu va parsa reprezentarea în niciun fel. Puteți alege ce reprezentare doriți, folosind liste, tupluri, sau alți compuși, acestea putând fi și imbricate.

În testarea unui nivel, vor exista două faze:

  1. checkerul va apela predicatele empty_state și set_* pentru a construi reprezentarea unei stări S (care poate să corespundă unui nivel din joc sau nu);
  2. checkerul va verifica corectitudinea reprezentării prin apelul, pe starea S rezultată, a predicatelor get_*
  3. checkerul va verifica implementarea corectă a mecanicii jocului prin apelul predicatului move care să transforme o stare S într-o altă stare, rezultată în urma realizării unei acțiuni.

Important: nu citiți direct reprezentarea nivelurilor din levels.pl. Stările corespunzătoare fiecărui nivel vor fi construite pătrățică cu pătrățică de către checker prin apeluri ale predicatelor set_*.

Aveți de implementat următoarele predicate în Prolog, documentate și în sursă:

Partea de switches rămâne pentru etapa 2; switch-urile vor fi adăugate cu predicatul set_switch.

Coordonatele pozițiilor sunt perechi de forma (X, Y), cu X=0 pe cea mai din stânga coloană pe care există pătrățele și cu Y=0 pe cea mai de sus linie pe care există pătrățele. Predicatele set_* vor fi apelate în ordine pentru toate pătrățelele, de la stânga la dreapta, și de sus în jos. În imaginea de mai sus, am notat cu buline albe pozițiile pentru care se va apela, la construcția reprezentării set_blank.

De exemplu, pentru construcția reprezentării nivelului 3, testerul va apela următoarele predicate:

empty_state(S0), set_blank(S0, (0, 0), S1), set_blank(S1, (1, 0), S2), [...], set_blank(..., (5, 0), ...),
set_tile(..., (6, 0), ...), set_tile(..., (7, 0), ...), ..., set_tile(..., (12, 0), ...),
set_blank(..., (13, 0), ...), set_blank(..., (14, 0), ...), set_tile(..., (0, 1), ...),
set_tile(..., (1, 1), ...), ..., set_tile(..., (0, 3), ...), set_block_initial(..., (1, 3), ...), ...
set_target(..., (13, 3), ...), ..., set_tile(..., (14, 5), Level3).

După construcția unei reprezentări, putem utiliza predicate get_* pe această stare. De exemplu, pe starea de mai sus, putem apela get_cell(Level3, (8, 2), X) care ne așteptăm să lege X la tile.

După implementarea tuturor predicatelor set_* și get_* veți putea utiliza predicatul print_state/1 din util.pl pentru a afișa o stare. De exemplu, pentru Stage 03, starea va fi afișată ca

      +++++++   
++++  +++  ++   
+++++++++  ++++ 
+B++       ++$+ 
++++       ++++ 
            +++ 

Nu uitați că aveți predicate utile pentru calculul pozițiilor în fișierul util.pl.

Etapa 2

În această etapă trebuie să includeți funcționalitatea switch-urilor în mecanica jocului și să rezolvați nivelurile de Bloxorz date.

Un switch în Bloxorz permite activarea și/sau dezactivarea unor pătrățele din tabla de joc (numite și pod – bridge).

Aveți de implementat:

Pentru rezolvarea unui nivel, aveți de implementat predicatul:

Testare

Încărcați în Prolog fișierul blox.pl. Pentru testare folosiți predicatele check sau vmcheck. Pentru teste individuale folosiți vmtest(<nume_test>)., e.g. vmtest(s0). Vedeți și observația de la începutul fișierului testing.pl.

La trimiterea temei, este suficient să puneți în arhivă fișierul blox.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 argumental testului.

De exemplu, pentru a replica testul s0|b puteți interoga la consolă:

empty_state(S), ttSetCell(S, 0, 0, +, _, _)

iar pentru testul s0|c:

empty_state(S), ttSetCell(S, 0, 0, 'B', _, S1), get_cell(S1, (0, 0), X)

Pentru rezultate mai detaliate ale testării, puteți decomenta linia %detailed_mode_disabled :- !, fail. din fișierul testing.pl. Atenție! În acest caz, este posibil ca punctarea să fie diferită decât rezultatul de pe vmchecker, unde linia este comentată.

Pentru a face debug pe secvențe de mutări, puteți folosi predicatul ttSeqDbg din testing.pl, care afișează starea după fiecare mutare din secvență.

Resurse

Changelog