2021-11-29 00:31:21 +01:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <graph.h>
|
|
|
|
#include <string.h>
|
2021-11-30 09:38:39 +01:00
|
|
|
#include <time.h>
|
2021-11-29 00:31:21 +01:00
|
|
|
#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;
|
|
|
|
}
|
|
|
|
|
2021-11-30 09:38:39 +01:00
|
|
|
//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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-29 00:31:21 +01:00
|
|
|
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);
|
|
|
|
|
2021-11-30 09:38:39 +01:00
|
|
|
RandomizeTaquin(); //On randomise notre taquin.
|
|
|
|
|
2021-11-29 00:31:21 +01:00
|
|
|
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.
|
|
|
|
}
|