#include #include #include #include #include #include "utils.h" #include "taquin.h" #include "graph_sup.h" #define OFFSET_X 650 #define OFFSET_Y 70 //Variables résponsables de la bonne division en cases et de l'apparence du Taquin. int ** Taquin; int Rows, Columns; char TaquinFilename[500]; //Variables résponsable du bon positionement et de la bonne échelle de l'image. int ImageX, ImageY, SizeX, SizeY; //Met à jour l'entièreté du Taquin. void UpdateTaquin() { for (int Y = 0; Y < Rows; Y++) { for (int X = 0; X < Columns; X++) { UpdatePiece(X, Y, Taquin[X][Y], GetColorN("black")); } } } //Vérifie si le Taquin est en ordre et retourne 1 si oui, 0 si non. int CheckVictory() { int X, Y; for (int i = 0; i < Rows * Columns; i++) { X = i % Columns; Y = i / Columns; if (Taquin[X][Y] != i) return 0; } return 1; } //Met à jour une pièce spécifique du Taquin. void UpdatePiece(int X, int Y, int Index, couleur Color) { int StartX = OFFSET_X + (X * SizeX); int StartY = OFFSET_Y + (Y * SizeY) + (500 - ImageY) / 2; int IStartX = SizeX * (Index % Columns); int IStartY = SizeY * (Index / Columns); SetColorC(Color); if (Index != 0) { DessinerRectangle(StartX, StartY, SizeX-1, SizeY-1); ChargerImage(TaquinFilename, StartX+1, StartY+1, IStartX, IStartY, SizeX-2, SizeY-2); } else { DessinerRectangle(StartX, StartY, SizeX-1, SizeY-1); SetColorN("white"); RemplirRectangle(StartX + 1, StartY + 1, SizeX - 2, SizeY - 2); } } //Vérifie la validité d'un mouvement de pièce et le fait s'il est valide. //Renvoie si le mouvement est valide ou non ( 1 ou 0 ) int MovePiece(int X, int Y, int Index, int ShouldUpdate) { int NewX = 0; int NewY = 0; if (X - 1 >= 0 && Taquin[X-1][Y] == 0) { NewX = -1; } else if (X + 1 < Columns && Taquin[X+1][Y] == 0) { NewX = 1; } else if (Y - 1 >= 0 && Taquin[X][Y-1] == 0) { NewY = -1; } else if (Y + 1 < Rows && Taquin[X][Y+1] == 0) { NewY = 1; } else return 0; Taquin[X][Y] = 0; Taquin[X + NewX][Y + NewY] = Index; for (int i = 0; i < BT_Count; i++) { if (Buttons[i].id == Index) Buttons[i].id = 0; else if (Buttons[i].id == 0) Buttons[i].id = Index; } if (ShouldUpdate) { UpdatePiece(X + NewX, Y + NewY, Index, GetColorN("black")); UpdatePiece(X, Y, 0, GetColorN("red")); } return NewX + 2 * NewY; } //Randomise le Taquin. void RandomizeTaquin() { int CX = 0, CY = 0; int LastMove = -1; srand(Microsecondes()); for (int i = 0; i < 50000; i++) { LastMove = rand() % 4 == LastMove ? (LastMove + 1) % 4 : rand() % 4; srand(Microsecondes()); if (LastMove == 0 && CX + 1 < Columns) /*Droite*/ { CX++; MovePiece(CX, CY, Taquin[CX][CY], 0); } else if (LastMove == 1 && CY + 1 < Rows) /*Bas*/ { CY++; MovePiece(CX, CY, Taquin[CX][CY], 0); } else if (LastMove == 2 && CX - 1 > -1) /*Gauche*/ { CX--; MovePiece(CX, CY, Taquin[CX][CY], 0); } else if (LastMove == 3 && CY - 1 > -1) /*Haut*/ { CY--; MovePiece(CX, CY, Taquin[CX][CY], 0); } } } void TaquinRenderLogicLoop() { int CurID = -1, LastID = -1, LastX = 0, LastY = 0, Victory = 0; //Variable indiquant quel périphérique controle actuellement le Taquin //0 = Souris, 1 = Clavier int Controller = 0; //On lance la boucle principale qui servira de boucle graphique et logique. //Elle met à jour le Taquin lorsqu'une pièce est bougée et déclenche les évenements logiques tels qu'un mouvement de pièce lors d'un clic. while(!Victory) { if (DrawNextFrame()) { if (Controller == 0) { SourisPosition(); CurID = GetButton(_X, _Y); } //Vérifie que la souris clique sur une pièce du Taquin et appelle la fonction de mouvement en fonction. if (SourisCliquee() && CurID != -1) { int handled = 0; Controller = 0; CurID = GetButton(_X, _Y); for (int Y = 0; Y < Rows; Y++) { for (int X = 0; X < Columns; X++) { if (handled) break; if (Taquin[X][Y] == CurID) { int movement = MovePiece(X, Y, CurID, 1); if (movement % 2 != 0) LastX += SizeX * movement; else LastY += SizeY * (movement/2); Victory = CheckVictory(); handled = 1; break; } } } } if (ToucheEnAttente()) { int key = Touche(); if (CurID == -1) { CurID = 0; LastID = -1; } int DeltaX = 0, DeltaY = 0; if (key == XK_Left) { DeltaX--; } else if (key == XK_Right) { DeltaX++; } else if (key == XK_Up) { DeltaY--; } else if (key == XK_Down) { DeltaY++; } else if (key == XK_space) { int handled = 0; for (int Y = 0; Y < Rows; Y++) { for (int X = 0; X < Columns; X++) { if (handled) break; if (Taquin[X][Y] == CurID) { int movement = MovePiece(X, Y, CurID, 1); if (movement % 2 != 0) LastX += SizeX * movement; else LastY += SizeY * (movement/2); if (movement != 0) { LastID = CurID; CurID = 0; } Victory = CheckVictory(); handled = 1; break; } } } } if (DeltaX != 0 || DeltaY != 0) { Controller = 1; int handled = 0; for (int Y = 0; Y < Rows; Y++) { for (int X = 0; X < Columns; X++) { if (handled) break; if (Taquin[X][Y] == CurID) { LastID = CurID; CurID = Taquin[clamp(X + DeltaX, 0, Columns-1)][clamp(Y + DeltaY, 0, Rows-1)]; handled = 1; break; } } } } } //Indicateur lumineux de la case actuellement sélectionnée. if (CurID != LastID) { for (int Y = 0; Y < Rows; Y++) { for (int X = 0; X < Columns; X++) { if (CurID == Taquin[X][Y]) { if (CurID != -1) UpdatePiece(X, Y, CurID, GetColorN("red")); if (LastID!= -1) UpdatePiece(LastX, LastY, LastID, GetColorN("black")); LastID = CurID; LastX = X; LastY = Y; } } } } } } } void ShowVictoryScreen() { } //Initialise le Taquin, la fonction appelle la création graphique et logique du Taquin. void CreateTaquin(char * FileName, int ImX, int ImY, int RowNumber, int ColumnNumber) { Rows = RowNumber; Columns = ColumnNumber; ImageX = ImX; ImageY = ImY; SizeX = ImageX / Columns; SizeY = ImageY / Rows; strcpy(TaquinFilename, FileName); //On alloue dynamiquement la mémoire afin de stocker l'arrangement des pièces du Taquin. Taquin = calloc(Columns, sizeof(int*)); for (int i = 0; i < Columns; i++) { Taquin[i] = calloc(Rows, sizeof(int)); } //On définit la position de départ de chaque pièce (au début en ordre, puis on randomise) for (int i = 0; i < Columns * Rows; i++) { Taquin[i % Columns][i / Columns] = i; int StartX = OFFSET_X + SizeX * (i % Columns); int StartY = OFFSET_Y + SizeY * (i / Columns) + (500 - ImageY) / 2; AddButton(StartX, StartY, SizeX, SizeY, i); } //On affiche la solution à gauche SetColorN("black"); DessinerRectangle(49, OFFSET_Y + (500 - ImageY) / 2 - 1, ImageX + 1, ImageY + 1); ChargerImage(FileName, 50, OFFSET_Y + (500 - ImageY) / 2, 0, 0, ImageX, ImageY); RandomizeTaquin(); //On randomise notre taquin. UpdateTaquin(); TaquinRenderLogicLoop(); //Cette fonction est responsable de tout le déroulement de la partie. ShowVictoryScreen(); //On est après une partie, on affiche l'écran de victoire. }