Table of Contents

Tema 1 - TetriBit

Responsabili

Update:

  • 27 Octombrie 2018: A fost actualizat deadline-ul temei (Post Forum). Atentie! Nu se mai accepta teme trimise dupa data de 5 Noiembrie 2018, ora 23:55.

Obiective

Introducere

Gigel nu este inițiat încă în tainele programării, dar vrea să învețe și să devină expert. Într-o zi i-a venit o idee care este foarte posibil să îi schimbe viața: lui îi plac foarte mult jocurile video și ar putea învăța foarte ușor programare îmbinând utilul cu plăcutul. Astfel, s-a gândit să implementeze cunoscutul joc Tetris folosind cunoștințele dobândite în primele 3 laboratore de la cursul de Programarea Calculatoarelor (cursul lui preferat de până acum).

Cerință

Harta

După ce a învățat în cadrul laboratorului operatorii pe biți, Gigel s-a gândit că se poate folosi de reprezentarea în baza 2 a unui număr pentru a desena harta jocului Tetris astfel:

De asemenea, pentru a avea o harta mai mare la dispoziție, a ales să folosească numere de 64 de biți (de exemplu: unsigned long long sau uint64_t) dimensiunea hărții fiind de 8 linii a câte 8 coloane (8 x 8). În plus, pentru o afișare mai frumoasă a decis să înlocuiască în afișare biții de 1 folosind caracterul ”#“ și biții de 0 folosind caracterul ”.”(punct).

Astfel, pentru numărul “284 803 830 071 167” a cărui reprezentare în bază 2 este:

00000000 00000001 00000011 00000111 00001111 00011111 00111111 01111111

Se poate crea harta:

........
.......#
......##
.....###
....####
...#####
..######
.#######

OBSERVAȚIE: În configurația inițială a hărții nu pot exista linii complete, adică nu pot apărea linii de forma:

########

în care toți cei 8 biți sunt setați pe 1.

Implementare

Gigel s-a gândit să își organizeze implementarea prin stabilirea de la început a tuturor funcționalităților pe care jocul lui este capabil să le realizeze.

Afișare hartă

Primul pas pe care acesta trebuie să îl efectueze este să afișeze harta primită la intrare.

Piese

La fel ca harta, piesele sunt primite ca input sub forma unui număr decimal.

Tipuri de piese:

  1. ...#....
  2.             |    ...#....   
    ...##...    |    ...#.... 
  3. ...#....    |    ...#....
    ..##....    |    ...##...
  4. ...##...
    ...##... 

Piesele pot apărea în orice poziție și pot să fie rotite în orice fel. De exemplu, piesele de tipul 3 pot să apară și sub forma:

.##.....
.#......

Mișcarea pieselor

Fiecare sesiune de joc conține un număr de mutări (numărul de mutări poate să fie și 0). Fiecare mutare conține piesa curentă și transformările care trebuie aplicate acesteia - câte o transformare pentru fiecare linie a hărții. Astfel, o mutare apare în input cu următorul format:

6168 -1 2 -2 0 0 1 1 -3

Unde primul număr reprezintă codificarea în decimal a piesei și următoarele 8 numere sunt transformările care trebuie aplicate asupra piesei. Numărul specific fiecărei transformări reprezintă numărul de poziții cu care piesa trebuie deplasată:

OBSERVAȚIE 1: Numărul specific fiecărei transformări poate să fie mai mare decât numărul maxim de deplasări posibile ale piesei. În acest caz, trebuie deplasată piesa doar cu numărul maxim de mutări posibile. De exemplu, pentru piesa 6168, care arată asftel:

...##...
...##...

o transformare cu -6 produce rezultatul:

##......
##......

pentru că numărul maxim posibil de deplasări în stânga este 3.

De asemenea, pentru piesa:

....#...

O transformare cu -9, ținând cont că linia pe care trebuie să se deplaseze arată astfel:

#.#.....

Va produce următorul rezultat pe linia mai sus menționată:

#.#.#... -> #.##....

Deci piesa nu poate să treacă peste o zonă deja ocupată, ci trebuie să rămână în ultimul loc disponibil (în cazul curent piesa efecutează o singură deplasare la stanga).

OBSERVAȚIE 2: Numărul de transformări este întotdeauna egal cu 8. Dacă, din motivul unei coliziuni, nu se pot efectua toate transformările, atunci celelalte transformări trebuie ignorate.

OBSERVAȚIE 3: Pentru consecvență, se alege ca ordinea operațiilor să fie următoarea:

  1. Pasul 1: se face mutarea piesei pe linia de jos.
  2. Pasul 2: se face deplasarea piesei în cadrul liniei curente.

Coliziune

În cazul în care, în drumul spre ultima linie, o piesă întâlnește un obstacol, aceasta trebuie să nu mai execute următoarele transformări și să se oprească în poziția rămasă.

De exemplu, pentru harta:

........
........
........
........
#####...
#####...
#####...
#####...

și piesa:

....##..
....##..

cu mutarea:

3084 0 0 0 0 2 0 0 0 0

execuția mutării se va opri dupa cea de-a 4-a mutare (a 5-a mutare nu poate fi efectuată din cauză că apare o coliziune și din cauza ordinii operațiilor de mutare a piesei), harta finală fiind:

........
........
....##..
....##..
#####...
#####...
#####...
#####...

Eliminarea liniilor complete

În cazul în care, după o mutare care își termină execuția (ajunge la ultima linie sau se oprește din cauza unei coliziuni), o linie de pe hartă devine completă (toți cei 8 biți sunt 1), atunci acea linie trebuie eliminată si toate liniile de deasupra coborâte cu o poziție. De asemenea, dacă mai multe linii devin complete după o mutare, toate trebuie eliminate.

De exemplu, pentru harta:

........
........
##...#..
#######.
#######.
#####.##
#####.##
#####.##

și piesa:

#.......
#.......

cu mutarea:

32896 0 10 0 0 0 0 0 0

secvența de afișări este:

........
........
##...#..
#######.
#######.
#####.##
#####.##
#####.##

#.......
........
##...#..
#######.
#######.
#####.##
#####.##
#####.##

.......#
.......#
##...#..
#######.
#######.
#####.##
#####.##
#####.##

........
.......#
##...#.#
#######.
#######.
#####.##
#####.##
#####.##

........
........
##...#.#
########
#######.
#####.##
#####.##
#####.##

........
........
##...#..
########
########
#####.##
#####.##
#####.##

........
........
........
........
##...#..
#####.##
#####.##
#####.##

GAME OVER!
Score:7.89

Terminarea jocului

Un joc poate să se încheie în 2 cazuri:

  1. Toate mutările au fost efectuate
  2. Piesa nu are loc în întregime pe hartă. Adică apare o coliziune înainte ca aceasta să fie afișată complet pe hartă.

De exemplu: Pentru harta:

........
#..#####
####..##
#.######
##.#####
####.###
#.######
####.###

și piesa

...##...
...##...

cu mutarea

6168 1 1 1 1 1 1 1 1 

Secventa de rulare este:

........
#..#####
####..##
#.######
##.#####
####.###
#.######
####.###

....##..
#..#####
####..##
#.######
##.#####
####.###
#.######
####.###

....##..
#..#####
####..##
#.######
##.#####
####.###
#.######
####.###

GAME OVER!
Score:4.87

OBSERVAȚIE: În cazul în care piesa nu are loc în întregime pe hartă și jocul trebuie încheiat, afișarea variantei finale a hărții se face de 2 ori (după cum se observă și în exemplul de mai sus).

Scor

Pentru că un joc de tetris fără scor nu are farmec, Gigel s-a gandit să inventeze o formula de calcul a scorului pentru harta finala. Astfel, după terminarea mutărilor, el calculează scorul folosind următoarea formulă:

\begin{eqnarray*} & & score = \ \sqrt{zerosNumber} + 1.25^{completedLines})\\ \end{eqnarray*}

Unde:

De asemenea, pentru a evita rezultatele lungi, el s-a hotarât să afișeze scorul cu o precizie de 2 zecimale (rotunjit).

Format input

H
M
P1 T1_1 T1_2 T1_3 T1_4 T1_5 T1_6 T1_7 T1_8
P2 T2_1 T2_2 T2_3 T2_4 T2_5 T2_6 T2_7 T2_8
...
PM TM_1 TM_2 TM_3 TM_4 TM_5 TM_6 TM_7 TM_8

unde:

Citirea se va face de la stdin (tastatură), dar, pentru a facilita testarea, se recomandă scrierea input-ului într-un fișier și rularea executabilului folosind redirectarea din fișierul creat. Exemplu:

./tema1 <in/test0.in

Format output

GAME OVER!
Score:S

unde S este scorul calculat folosind formula de mai sus.

Pentru că testarea corectitudinii temei se face automat, este necesar să se respecte cu strictețe formatul de output. NU trebuie să existe afișări în plus.

Punctaj

TOTAL: 100p

Trimitere temă

Tema va fi trimisă folosind vmchecker, cursul Programarea Calculatoarelor (CB & CD).
Găsiți checker-ul aici.

Formatul arhivei va fi următorul:

  1. fișier(ele) .c (și fișiere .h - dacă este cazul).
  2. Un fișier Makefile (detalii aici) care să conțină următoarele reguli:
    1. build: creează executabilul aferent (numele executabilului: tema1)
    2. run: rulează executabilul aferent
    3. clean: șterge fișierele obiect/executabile create.
  3. Un fișier README în care vă descrieți rezolvarea temei.

Este necesară scrierea numelui si a grupei atât în fișierul README, cât și în toate fișierele sursă pe care le adăugați în arhiva temei.

  1. Arhiva trebuie să fie de tipul zip.
  2. Inputul se va fi citit de la stdin (tastatura), iar output-ul va fi afișat la stdout (ecran). Testarea se face cu ajutorul redirectării acestora din linia de comandă/bash.

Observații

Listă depunctări

Referințe