The Emperor's New Sudoku

Responsabili:

Scopul temei:

  • utilizarea structurilor de date;
  • lucrul cu fisiere, atat text, cat si binare;
  • utilizare bibliotecilor externe;
  • familiarizarea cu formatul JSON.

Termen de predare:

  • Data publicării: 27.12.2020
  • Deadline soft: 27.01.2021
  • Deadline hard: 27.01.2021
Întrebări

Dacă aveți nelămuriri, puteți să ne contactați pe forumul dedicat temei de casă nr. 3.

Actualizări:

  • 15.01.2021 - VMchecker este live.
  • 14.01.2021 - Update deadline.
  • 10.01.2021 - Adaugat pseudocod task bonus
  • 08.01.2021 - Corectat teste task bonus.(checkerul)
  • 08.01.2021 - Corectat teste task 4.
  • 07.01.2021 - Actualizari mod de rulare.
  • 06.01.2021 - Am adaugat checkerul local. (link). Schimbare cerinte Makefile & mod de rulare.
  • 05.01.2021 - Actualizari importante fisiere de input/output. (link)
  • 04.01.2021 - Mici actualizari ale cerintei. (in special [1] si bonusul)

Reguli Sudoku

Pentru a putea rezolva aceasta tema trebuie sa fiti familiari cu jocul Sudoku.

Sudoku se joacă într-o grilă care este alcătuită din 9 x 9 căsuțe separate în 9 rânduri (poziționate orizontal) și 9 coloane (poziționate vertical) grupate în pătrate cu dimensiuni 3 x 3.

Obiectivul jocului este sa se completeze fiecare patrat cu cifre de la 1 la 9 astfel incat:

  • fiecare linie orizontala sa contina toate cifrele exact o data
  • fiecare coloana de verticala sa contina toate cifrele exact o data
  • fieacre subpatrat sa contina toate cifrele exact o data

Exemplu_grid_sudoku

Mai multe informatii despre joc gasiti aici.

Structura formatului BMP

Vom lucra cu fisiere BMP, deci, cu fisiere binare.

O imagine BMP are urmatoarea structura:

  • un File Header care are urmatoarele campuri:
    1. signature – 2 octeti - literele 'B' si 'M' in ASCII;
    2. file size – 4 octeti – dimensiunea intregului fisier;
    3. reserved – 4 octeti – nefolosit;
    4. offset – 4 octeti – offsetul de la inceputul fisierului pana la inceputului bitmap-ului, adica al matricei de pixeli.
  • un Info Header care poate avea structuri diferite, insa noi vom lucra cu cel care se numeste BITMAPINFOHEADER. Are urmatoarele campuri:
    1. size – 4 octeti – dimensiunea Info Header-ului, care are o valoare fixa, 40;
    2. width – 4 octeti – latimea matricei de pixeli (numarul de coloane);
    3. height – 4 octeti – inaltimea matricei de pixeli (numarul de randuri);
    4. planes – 2 octeti – setat la valoarea fixa 1;
    5. bit count – 2 octeti – numarul de biti per pixel. In cazul nostru va avea mereu valoarea 24, adica reprezentam fiecare pixel pe 3 octeti, adica cele 3 canale, RGB;
    6. compression – 4 octeti – tipul de compresie. Acest camp va fi 0;
    7. image size – 4 octeti – se refera la dimensiunea matricei de pixeli, inclusiv padding-ul adaugat (vedeti mai jos);
    8. x pixels per meter – 4 octeti – se refera la rezolutia de printare. Pentru a simplifica putin tema, veti seta acest camp pe 0. Nu o sa printam imaginile :).
    9. y pixels per meter – la fel ca mai sus;
    10. colors used – numarul de culori din paleta de culori. Aceasta este o sectiune care va lipsi din imaginile noastre BMP, deoarece ea se afla in general imediat dupa Info Header insa doar pentru imaginile care au campul bit count mai mic sau egal cu 8. Prin urmare, campul va fi setat pe 0;
    11. colors important – numarul de culori importante. Va fi, de asemenea, setat pe 0, ceea ce inseamna ca toate culorile sunt importante.
  • BitMap-ul, care este matricea de pixeli si care ocupa cea mai mare parte din fisier. Trei lucruri trebuie mentionate despre aceasta:
    1. pixelii propriu-zisi se afla intr-o matrice de dimensiune height x width, insa ea poate avea o dimensiune mai mare de atat din cauza paddingului. Acest padding este adaugat la sfarsitul fiecarei linii astfel incat fiecare linie sa inceapa de la o adresa (offset fata de inceputul fisierului) multiplu de 4. Mare atentie la citire, pentru ca acest padding trebuie ignorat (fseek). De asemenea, la scriere va trebui sa puneti explicit valoarea 0 pe toti octetii de padding.
    2. este rasturnata, ceea ce inseamna ca prima linie in matrice contine de fapt pixelii din extremitatea de jos a imaginii. Vedeti exemplul de mai jos;
    3. canelele pentru fiecare pixel sunt in ordinea BGR (Blue Green Red).

Header-ele pe care le puteti folosi in implementare se afla in scheletul de cod asociat temei.

Urmatiti cu foarte mare atentie exemplul de aici si incercati sa intelegeti cum e reprezentata o imagine BMP inainte de a incepe implementarea. Daca e ceva neclar, puteti intreba oricand pe forum.

Puteti folosi utilitare precum xxd sau hexdump pentru a putea vizualiza continutul unui fisier binar (in cazul nostru, a unei imagini bmp). Vedeti si raspunsurile de aici .

Introducere

Prietenul tau, Emperor Tiramisu, a inceput sa se joace sudoku, dar nu stie exact regulile. Din acest motiv are nevoie de ajutorul tau pentru a stii daca a completat corect sau nu matricea. Deoarece stie ca sunteti studenti la ACS el vrea de la voi sa “automatizati” acest proces. Veti primi de la el o poza cu tabla lui de sudoku si va trebui sa ii spuneti daca a castigat sau a pierdut.

Task 1 - 10p

Emperor Tiramisu a decis sa comunice cu tine prin intermediul unui server (mai specific, de HTTP, insa nu conteaza acest aspect in rezolvarea temei - mai multe informatii referitoare la ce este un server de http gasiti aici - Nu este relevant pentru implementarea temei!). Din cauza aceasta mesajul primit de la el a ajuns la tine in format JSON. Prima ta sarcina este sa transformi mesajul primit intr-o imagine bmp. Ca sa poti face asta trebuie sa stii ce inseamna JSON.

Informatii JSON

Informatii JSON

JSON (JavaScript Object Notation) este un format de reprezentare și interschimb de date între aplicații informatice. Este un format text, inteligibil pentru oameni, utilizat pentru reprezentarea obiectelor și a altor structuri de date și este folosit în special pentru a transmite date structurate prin rețea. Se bazeaza pe un model de forma: “cheie”:“valoare”.

Exemplu urmator arata cum am putea stoca date despre o persona in format JSON.


{
  "firstName": "John",
  "lastName": "Smith",
  "age": 27,
  "address": {
    "streetAddress": "21 2nd Street",
    "city": "New York",
  },
  "phoneNumbers": [
    {
      "type": "home",
      "number": "212 555-1234"
    },
    {
      "type": "office",
      "number": "646 555-4567"
    }
  ],
  "children": [],
  "spouse": null
}

Mai multe informatii despre formatul JSON.

Pentru a parsa datele de intrare din fisier va recomandam sa folositi o biblioteca externa precum cJSON sau JSMN. Nu sunteti restrictionati doar la aceste 2 biblioteci externe, ci puteti folosi ce doriti voi doar pentru lucrul cu jsoane. Va trebui sa motivati in README de ce ati ales biblioteca externa pe care ati folosit-o/ati facut prelucrarea de mana.

Orice folosire de cod din alte surse pentru a va ajuta in implementarea altor parti din tema va atrage după sine depunctarea cu punctajul aferent temei, conform regulamentului

Exemplu input

Puteti gasi fisierul json aici. Il copiati local si il salvati cu extensia ”.json”.

In exemplul de mai jos, campul “bitmap” nu este populat complet.

Input:

board_0.json
{
	"bitmap":	[0,0,0,...,0,0,0,0,0,0,0,255,255,255,255,255,255,...],
	"file_header":	{
		"offset":	54,
		"signature":	"BM",
		"reserved":	0,
		"file_size":	16114
	},
	"info_header":	{
		"colors_used":	0,
		"size":	40,
		"colors_important":	0,
		"image_size":	16060,
		"y_pixels_per_meter":	0,
		"x_pixels_per_meter":	0,
		"width":	73,
		"planes":	1,
		"bit_count":	24,
		"compression":	0,
		"height":	73
	}
}

Output:

O imagine in format bmp.

Informatiile despre file header si info header nu trebuiesc hardcodate. Le veti citi din json. In caz contrar veti fi depunctati.

Informatii despre imagine

O imagine este formata dintr-o multime de pixel, iar fiecare pixel este reprezentat (in cazul nostru) prin 3 valori (R, G, B), ele reprezentand intensitatea culorilor: Rosu, Verde si Albastru (folosind combinatii din aceste culori se pot forma altele). Puteti observa aici cum intensitatea unei culori, schimba culoarea finala.

Imaginea este de 73×73 pixeli, 9×9 patratele care respecta urmatoarele dimensiuni:

  1. o margine de 1 pixel neagra/gri
  2. o margine de 1 pixel alba in jurul cifrei
  3. cifra de 5×5

Marginile nu se dubleaza nicaieri. Peste tot in imagine marginile au grosimea de 1 pixel. Marginile care delimiteaza un subpatrat sunt negre, dar cele din interiorul sectiunii sunt gri.

Exemplu de sectiune de 3×3 patrate (pentru a intelege ceva din exemplu recomandam sa va uitati de pe un Desktop). Daca notam cu “X” un pixel roz (r:255, g:175, b:175) din cifra, cu “.” un pixel alb(r:255, g:255, b:255) din fundal, cu “O” un pixel negru (r:0, g:0, b:0) din margine si cu 0 un pixel gri (r:128, g:128, b:128):


OOOOOOOOOOOOOOOOOOOOOOOOO
O.......0.......0.......O
O.....X.0.XXXXX.0.XXXXX.O
O.....X.0.....X.0.....X.O
O.....X.0.XXXXX.0.XXXXX.O
O.....X.0.X.....0.....X.O
O.....X.0.XXXXX.0.XXXXX.O
O.......0.......0.......O
O00000000000000000000000O
O.......0.......0.......O
O.X...X.0.XXXXX.0.XXXXX.O
O.X...X.0.X.....0.X.....O
O.XXXXX.0.XXXXX.0.XXXXX.O
O.....X.0.....X.0.X...X.O
O.....X.0.XXXXX.0.XXXXX.O
O.......0.......0.......O
O00000000000000000000000O
O.......0.......0.......O
O.XXXXX.0.XXXXX.0.XXXXX.O
O.....X.0.X...X.0.X...X.O
O.....X.0.XXXXX.0.XXXXX.O
O.....X.0.X...X.0.....X.O
O.....X.0.XXXXX.0.XXXXX.O
O.......0.......0.......O
OOOOOOOOOOOOOOOOOOOOOOOOO

Task 2 - 20p

Dupa ce ati reusit sa obtineti o imagine din mesajul primit de la Emperor Tiramisu, puteti observa ca nu se pricepe nici la comunicatii HTTP. Mesajul a fost encodat gresit iar imaginea obtinuta are o problema. Urmatorul pas pentru voi este repararea imaginii.

Aveti deja datele stocate in memorie! Nu mai este nevoie sa cititi inca o data din fisier

Hint

Hint

Hint: Cifrele sunt mirrored (acesta este singurul caz posibil). Pastrand aceeasi notatie de mai sus avem:


Rezultatul obtinut in urma parsarii jsonului:                  Outputul asteptat:
            000000000                                             000000000
            0.......0                                             0.......0
            0.XXXXX.0                                             0.XXXXX.0
            0.X.....0                                             0.....X.0
            0.XXXXX.0                           ->                0.XXXXX.0
            0.X.....0                                             0.....X.0
            0.XXXXX.0                                             0.XXXXX.0
            0.......0                                             0.......0
            000000000                                             000000000

Input:

Imaginea de la cerinta anterioara.

Output:

output_task1

Task 3 - 30p

Dupa toate prelucrarile anterioare asupra setului de date primit de la Emperor Tiramisu, in final putem verifica daca jocul de sudoku este completat corect sau nu. Pentru a face acest lucru trebuie sa verificati daca se respecta cele 3 reguli ale jocului de sudoku. Acest lucru implica recunoasterea de cifre dintr-o imagine bmp.

Hint

Hint

Deoarece comunicatia cu Emperor Tiramisu se face printr-un server remote, veti afisa starea jocului in format json, intr-un fisier “output_task3_board##.json” (unde ”##” reprezinta numarul boardului primit ca input). Jsonul va avea 2 campuri: campul “input_file” - numele fisierului de intrare si in campul “game_state” - “Win!” daca Emperor Tiramisu a reusit sa completeze corect jocul sau “Loss :(” in caz contrar.

Orice tabla de joc care contine casute necompletate sau alte simboluri in afara de cele adimse (cifre de la 1 la 9) se considera pierduta.

Aveti deja datele stocate in memorie! Nu mai este nevoie sa cititi inca o data din fisier

Input

Imaginea obtinuta ca output la punctul anterior.

Output

output_task3.json
{
	"input_file":	"board0.json",
	"game_state":	"Win!"
}

Task 4 - 40p

Se pare ca Emperor Tiramisu s-a plictisit sa completeze jocurile de sudoku (si sa afle de la voi ca a gresit :-)), iar acum ati inceput sa primiti jocuri neterminate pe care trebuie sa le rezolvati.

La acest task veti citi o imagine .bmp cu cifre lipsa si veti completa spatiile goale cu cifrele potrivite. Cifrele scrise de voi vor avea alta culoare fata de cele din imaginiea initiala: magenta (r:255, g:0, b:255).

Se garanteaza ca testele nu vor avea o complexitate ridicata (nu va fi necesar backtrackingul).

Input input_task4.bmp

Output output_task4.bmp

Bonus - 35p

Acum ca ati trecut prin toate aceste taskuri de la Emperor Tiramisu ar trebui sa reusiti (cu putin ajutor din partea noastra) sa rezolvati singuri un joc de sudoku, de la 0.

Asemenea taskului 4, veti primi ca input o imagine bmp cu o tabla de sudoku necompletat, iar voi va trebui sa rezolvati jocul folosind un algoritm propriu sau urmarind pseudocodul de mai jos.

Pseudocod Backtracking

Pseudocod Backtracking

solve_sudoku (board, row, col)
	set nextRow and nextCol to the next position
	if board[row, col] is not open then // skip pinned numbers
		return [nextRow, nextCol] is out of bounds
				or solve_sudoku(nextRow, nextCol) is true
	end if

	for each number in {1..9} do
		if is_valid (board, row, col, number) is true then
			set board[row, col] to number
			
			if [nextRow, nextCol] is out of bounds
			    or solve_sudoku(nextRow, nextCol) is true then
					return true; // we have a solution
			end if

            restore board[row, col] to "open" // backtrack
		end if
	end for
	
	return false // no more numbers to try. all failed.
end solve_sudoku

is_valid (board, row, col, number)
	- function that returns 1 if the "number" cand be placed in the board, 
		on "row" and "col", and does not violate the 3 rules of sudoku.


Cifrele lipsa vor fi completate din nou cu magenta. In cazul in care jocul nu poate fi completat, va trebui sa suprascrieti fiecare cifra din imagine cu un X, scris cu rosu (r: 255, g: 0, b:0).

Format X

Format X


000000000
0.......0
0.X...X.0
0..X.X..0
0...X...0
0..X.X..0
0.X...X.0
0.......0
000000000

Input output_bonus.bmp

Output input rezolvabil output_bonus.bmp

Output input nerezolvabil output_task4_nerezolvabil.bmp

Resurse si checker-ul local

Resursele pentru tema se pot descarca de aici. Sunt prezente:

  • bmp_header.h: headerul care contine declaratiile struct-urilor pe care le veti folosi in citirea unui fisier BMP;
  • checker: folderul in care se gasesc testele si checkerul local

Daca aveti prima varianta a checkerului va rugam sa o luati pe aceasta.
Instructiuni pentru rularea checkerului, gasiti in READMEul acestuia.

Fisiere de intrare/iesire

  • Fisierele de intrare vor fi primite ca argumente in linia de comanda, iar fisierele de iesire pentru fiecare task vor fi denumite in felul urmator “output_<task1/2/3/4/>/bonus_board?.<json/bmp>”, unde ”?” reprezinta numarul boardului primit ca intrare.
  • Tema se va rula in felul urmator: ”./sudoku input <123/4/bonus>”, al doilea parametru este necesar pentru a se putea rula checkerul.
  • Se ruleaza pe rand task 1, 2, 3 sau task 4 sau task bonus.

Restrictii si precizari

  • Pentru taskurile 1, 2 si 3 datele se citesc o singura data din fisierul .json si se pastreaza in memorie optim imaginea. In caz contrar puteti suferi depunctari.
  • Nu folositi variabile globale.
  • Fiti consistenti in ceea ce priveste Coding Style-ul.
  • Toate matricile si vectorii folositi se vor aloca dinamic, pe heap;
  • Nu veti avea de modificat nimic in headerele imaginii;
  • Tema se va trimite pe vmchecker si se va testa local cu ajutorul checker-ului care va fi disponibil in curand;
  • Pe vmchecker veti uploada o arhiva in format .zip care sa contina:
    1. Makefile (facut de voi), cu cel puțin 3 targeturi, build și clean; Regula run trebuie sa ruleze executabilul care a fost obtinut la regula build si care are numele tema3 sudoku;
    2. sursele voastre, adică fișierele .c și .h. Inclusiv headerul bmp_header.h sau sub orice altă denumire îl folosiți si biblioteca externa pentru manipularea datelor in format JSON;
    3. README, în care trebuie să dați detalii despre implementare, de ce ați ales să rezolvați într-un anumit fel, etc.

Temele care nu folosesc alocare dinamica vor avea o depunctare de pana la 50 de puncte din punctajul temei, in functie de gravitate! De asemenea, nu va fi acordat punctajul pe bonus in acest caz!

Nu descarcati imaginile atasate in enunt pentru testare! Acestea nu respecta formatul BMP! Pentru testare folositi numai imaginile puse la dispozitie in arhiva de testare. Imaginile de mai sus au doar caracter informativ.

Listă depunctări

Lista nu este exhaustivă. Se pot aplica chiar depunctări mai mari în cazuri excepționale.

  • o temă care nu compilează și nu a rulat pe vmchecker nu va fi luată în considerare
  • o temă care nu rezolvă cerința și trece testele prin alte mijloace nu va fi luată în considerare
  • [-50.0]: o tema care nu folosește deloc alocarea dinamică
  • [-1.0]: warning-uri la compilare (este obligatorie folosirea în fișierul Makefile a flag-ului de compilare -Wall pentru regula build)
  • [-1.0]: numele variabilelor nu sunt sugestive
  • [-1.0]: linii mai lungi de 80 de caractere in cod / in fișierul README
  • [-1.0]: cod nemodular, funcții prea lungi (inclusiv main)
  • [-2.5]: variabile globale
  • [-5.0]: abordare ineficientă
    • în cadrul cursului de programare nu avem ca obiectiv rezolvarea programelor in cel mai eficient mod posibil; totuși, ne dorim ca abordarea să nu fie una ineficientă (exemple de asa NU: să folosiți instrucțiuni repetitive acolo unde clar nu era cazul; sa alocati vectori de 1000000 de elemente pentru a citi din fisier, cand puteati afla dimensiunea fisierului inainte de alocare).
programare/teme_2020/tema3_2020_cbd.txt · Last modified: 2021/01/19 11:31 by vlad.burcea
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