Menu v3
This commit is contained in:
@@ -1,28 +1,40 @@
|
||||
# Makefile pour le projet Taquin - SAE S1.02 / S1.04
|
||||
|
||||
# Variables de compilation
|
||||
CC = gcc
|
||||
CFLAGS = -Wall -Wextra -std=c89
|
||||
LIBS = -lgraph
|
||||
OBJ_DIR = obj
|
||||
SRC_DIR = src
|
||||
LDFLAGS = -lgraph
|
||||
TARGET = taquin
|
||||
|
||||
SRC = $(wildcard $(SRC_DIR)/*.c)
|
||||
OBJ = $(SRC:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o)
|
||||
# Liste de tous les fichiers sources (.c)
|
||||
SRCS = src/main.c src/menu_view.c src/game_logic.c src/images.c src/utils.c
|
||||
|
||||
EXEC = taquin
|
||||
# Liste de tous les fichiers objets (.o) correspondants
|
||||
OBJS = $(patsubst src/%.c, obj/%.o, $(SRCS))
|
||||
|
||||
all: $(EXEC)
|
||||
# ----------------------------------------------------------------------
|
||||
# Cibles principales
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
$(EXEC): $(OBJ)
|
||||
$(CC) $(CFLAGS) -o $@ $^ $(LIBS)
|
||||
# Cible par défaut (crée l'exécutable)
|
||||
all: dir $(TARGET)
|
||||
|
||||
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
|
||||
@mkdir -p $(OBJ_DIR)
|
||||
# Crée le dossier obj/ si non existant
|
||||
dir:
|
||||
@mkdir -p obj
|
||||
|
||||
# Règle de liaison : crée l'exécutable taquin à partir de tous les objets
|
||||
$(TARGET): $(OBJS)
|
||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||
|
||||
# Règle générique pour la compilation de tous les .c en .o
|
||||
obj/%.o: src/%.c
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
run: $(EXEC)
|
||||
./$(EXEC)
|
||||
# Exécute le programme
|
||||
run: $(TARGET)
|
||||
./$(TARGET)
|
||||
|
||||
# Nettoyage
|
||||
clean:
|
||||
rm -rf $(OBJ_DIR) $(EXEC)
|
||||
|
||||
.PHONY : all clean run
|
||||
@rm -rf obj $(TARGET)
|
||||
|
||||
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
@@ -0,0 +1,165 @@
|
||||
/* src/game_logic.c */
|
||||
|
||||
#include "game_logic.h"
|
||||
#include "utils.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* --- Utilitaires de positionnement --- */
|
||||
|
||||
/* Convertit un index 1D en coordonnées 2D */
|
||||
static void index_to_coords(int index, int cols, int *r, int *c)
|
||||
{
|
||||
*r = index / cols;
|
||||
*c = index % cols;
|
||||
}
|
||||
|
||||
/* Trouve les indices des tuiles adjacentes à la case vide */
|
||||
static int find_adjacent_indices(int idx, int rows, int cols, int *out_indices)
|
||||
{
|
||||
int r = idx / cols;
|
||||
int c = idx % cols;
|
||||
int n = 0;
|
||||
|
||||
if (r > 0) out_indices[n++] = (r - 1) * cols + c; /* Haut */
|
||||
if (r < rows - 1) out_indices[n++] = (r + 1) * cols + c; /* Bas */
|
||||
if (c > 0) out_indices[n++] = r * cols + (c - 1); /* Gauche */
|
||||
if (c < cols - 1) out_indices[n++] = r * cols + (c + 1); /* Droite */
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
/* --- Fonctions publiques --- */
|
||||
|
||||
/* Initialise le jeu à l'état résolu et alloue la mémoire */
|
||||
void game_init(game_state_t *state, int rows, int cols, tile_t **tiles)
|
||||
{
|
||||
int num_tiles = rows * cols;
|
||||
int i;
|
||||
|
||||
state->rows = rows;
|
||||
state->cols = cols;
|
||||
state->moves = 0UL;
|
||||
state->is_solved = 1;
|
||||
state->all_tiles = tiles;
|
||||
|
||||
/* Allocation dynamique de la permutation (malloc) */
|
||||
state->permutation = (int *)malloc(num_tiles * sizeof(int));
|
||||
|
||||
if (state->permutation == NULL) {
|
||||
fprintf(stderr, "Erreur: Allocation permutation echouee.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Remplissage à l'état résolu : IDs 0, 1, 2, ... N-2 */
|
||||
for (i = 0; i < num_tiles - 1; i++) {
|
||||
state->permutation[i] = i;
|
||||
}
|
||||
|
||||
/* La dernière case est la case vide (-1) */
|
||||
state->permutation[num_tiles - 1] = -1;
|
||||
state->empty_index = num_tiles - 1;
|
||||
}
|
||||
|
||||
/* Libère la mémoire allouée par game_init */
|
||||
void game_free(game_state_t *state)
|
||||
{
|
||||
if (state->permutation != NULL) {
|
||||
free(state->permutation);
|
||||
state->permutation = NULL;
|
||||
}
|
||||
/* Note: tiles sont libérés par images_free_tiles dans main.c */
|
||||
}
|
||||
|
||||
/* Vérifie si la tuile peut bouger (adjacence) */
|
||||
int game_can_move(const game_state_t *state, int index_to_move)
|
||||
{
|
||||
int r_tile, c_tile;
|
||||
int r_empty, c_empty;
|
||||
|
||||
if (index_to_move == state->empty_index) return 0;
|
||||
if (index_to_move < 0 || index_to_move >= state->rows * state->cols) return 0;
|
||||
|
||||
index_to_coords(index_to_move, state->cols, &r_tile, &c_tile);
|
||||
index_to_coords(state->empty_index, state->cols, &r_empty, &c_empty);
|
||||
|
||||
/* Test d'adjacence géographique (manhattan distance = 1) */
|
||||
if (abs_val(r_tile - r_empty) + abs_val(c_tile - c_empty) == 1) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Déplace la tuile vers la case vide si possible */
|
||||
int game_move_tile(game_state_t *state, int index_to_move)
|
||||
{
|
||||
int temp_tile_id;
|
||||
|
||||
if (!game_can_move(state, index_to_move)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Échange des valeurs (swap) */
|
||||
temp_tile_id = state->permutation[index_to_move];
|
||||
state->permutation[index_to_move] = state->permutation[state->empty_index];
|
||||
state->permutation[state->empty_index] = temp_tile_id;
|
||||
|
||||
/* Mise à jour de la nouvelle position de la case vide */
|
||||
state->empty_index = index_to_move;
|
||||
|
||||
/* Mise à jour des compteurs */
|
||||
state->moves++;
|
||||
state->is_solved = game_is_solved(state);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Vérifie si le plateau est dans l'état résolu */
|
||||
int game_is_solved(const game_state_t *state)
|
||||
{
|
||||
int num_tiles = state->rows * state->cols;
|
||||
int i;
|
||||
|
||||
/* La case vide doit être en dernière position (-1) */
|
||||
if (state->permutation[num_tiles - 1] != -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Toutes les autres tuiles doivent être dans l'ordre (ID = Position) */
|
||||
for (i = 0; i < num_tiles - 1; i++) {
|
||||
if (state->permutation[i] != i) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Mélange garanti solvable par N mouvements aléatoires */
|
||||
void game_shuffle_safe(game_state_t *state, int steps)
|
||||
{
|
||||
int prev_move = -1;
|
||||
int choices[4];
|
||||
int n_choices;
|
||||
int pick_index;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < steps; i++) {
|
||||
n_choices = find_adjacent_indices(state->empty_index, state->rows, state->cols, choices);
|
||||
|
||||
/* Choisir une tuile adjacente au hasard, sans revenir en arrière immédiatement */
|
||||
do {
|
||||
pick_index = choices[random_int(n_choices)];
|
||||
} while (n_choices > 1 && pick_index == prev_move);
|
||||
|
||||
/* Déplacer la tuile (utilise la logique de déplacement) */
|
||||
game_move_tile(state, pick_index);
|
||||
|
||||
/* L'ancienne position vide est la tuile qui vient d'être déplacée (pour la prochaine itération) */
|
||||
prev_move = pick_index;
|
||||
}
|
||||
|
||||
state->moves = 0UL;
|
||||
state->is_solved = 0;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/* src/game_logic.h
|
||||
* Définition de l'état du plateau et des prototypes pour le moteur de jeu.
|
||||
*/
|
||||
|
||||
#ifndef GAME_LOGIC_H
|
||||
#define GAME_LOGIC_H
|
||||
|
||||
#include "images.h" /* Nécessaire pour le type tile_t */
|
||||
|
||||
/* Structure de l'état complet du Taquin */
|
||||
typedef struct {
|
||||
int rows;
|
||||
int cols;
|
||||
|
||||
/* Tableau 1D alloué dynamiquement pour la permutation */
|
||||
int *permutation;
|
||||
|
||||
int empty_index; /* Position actuelle (index 1D) de la case vide */
|
||||
unsigned long moves; /* Compteur de coups */
|
||||
int is_solved; /* 1 si gagné */
|
||||
|
||||
tile_t **all_tiles; /* Les tuiles découpées */
|
||||
} game_state_t;
|
||||
|
||||
|
||||
/* Prototypes des fonctions publiques */
|
||||
void game_init(game_state_t *state, int rows, int cols, tile_t **tiles);
|
||||
void game_free(game_state_t *state);
|
||||
|
||||
/* Logique de jeu */
|
||||
int game_move_tile(game_state_t *state, int index_to_move);
|
||||
int game_can_move(const game_state_t *state, int index_to_move);
|
||||
|
||||
/* Solvabilité */
|
||||
int game_is_solved(const game_state_t *state);
|
||||
void game_shuffle_safe(game_state_t *state, int steps);
|
||||
|
||||
#endif /* GAME_LOGIC_H */
|
||||
@@ -0,0 +1,89 @@
|
||||
/* src/images.c
|
||||
* Gère le découpage de l'image source en tuiles (structures tile_t).
|
||||
*/
|
||||
|
||||
#include "images.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Stocke les chemins des images disponibles (doit correspondre à NUM_IMAGES dans menu_view.h) */
|
||||
static const char *IMAGE_PATHS[] = {
|
||||
"assets/image1.png",
|
||||
"assets/image2.png",
|
||||
"assets/image3.png"
|
||||
};
|
||||
|
||||
/* Retourne les informations de l'image choisie */
|
||||
image_source_t get_image_source(int selected_index)
|
||||
{
|
||||
image_source_t src;
|
||||
|
||||
/* TODO: Normalement, il faudrait charger l'image ici pour obtenir la VRAIE taille (width/height)
|
||||
avec une fonction IUT. Pour l'instant, on simule une taille fixe. */
|
||||
src.width = 750;
|
||||
src.height = 450;
|
||||
|
||||
if (selected_index >= 0 && selected_index < 3) {
|
||||
strcpy(src.path, IMAGE_PATHS[selected_index]);
|
||||
} else {
|
||||
strcpy(src.path, IMAGE_PATHS[0]);
|
||||
}
|
||||
return src;
|
||||
}
|
||||
|
||||
/* Crée un tableau de tuiles découpées (allocation dynamique de structures) */
|
||||
tile_t **images_slice(image_source_t img_src, int rows, int cols)
|
||||
{
|
||||
int num_tiles = rows * cols;
|
||||
int tile_w, tile_h;
|
||||
tile_t **tiles;
|
||||
int i, j, id = 0;
|
||||
|
||||
/* Calcul des dimensions d'une tuile */
|
||||
tile_w = img_src.width / cols;
|
||||
tile_h = img_src.height / rows;
|
||||
|
||||
/* Allocation du tableau de pointeurs vers les structures de tuiles */
|
||||
tiles = (tile_t **) calloc(num_tiles, sizeof(tile_t *)); /* calloc pour initialiser à NULL */
|
||||
if (tiles == NULL) return NULL;
|
||||
|
||||
for (i = 0; i < rows; i++) {
|
||||
for (j = 0; j < cols; j++) {
|
||||
/* Allocation de la structure de tuile */
|
||||
tile_t *t = (tile_t *) malloc(sizeof(tile_t));
|
||||
if (t == NULL) {
|
||||
/* Gérer l'échec de malloc */
|
||||
images_free_tiles(tiles, id);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Remplissage des champs (coordonnées de découpe) */
|
||||
strcpy(t->path, img_src.path);
|
||||
t->width = tile_w;
|
||||
t->height = tile_h;
|
||||
t->src_x = j * tile_w;
|
||||
t->src_y = i * tile_h;
|
||||
t->id = id;
|
||||
|
||||
tiles[id] = t;
|
||||
id++;
|
||||
}
|
||||
}
|
||||
return tiles;
|
||||
}
|
||||
|
||||
/* Libère la mémoire allouée par images_slice */
|
||||
void images_free_tiles(tile_t **tiles, int num_tiles)
|
||||
{
|
||||
int i;
|
||||
if (tiles == NULL) return;
|
||||
|
||||
for (i = 0; i < num_tiles; i++) {
|
||||
if (tiles[i] != NULL) {
|
||||
free(tiles[i]);
|
||||
tiles[i] = NULL;
|
||||
}
|
||||
}
|
||||
free(tiles);
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/* src/images.h
|
||||
* Définition des structures pour la gestion et le découpage de l'image.
|
||||
*/
|
||||
|
||||
#ifndef IMAGES_H
|
||||
#define IMAGES_H
|
||||
|
||||
/* Une tuile est une partie de l'image source */
|
||||
typedef struct {
|
||||
char path[30];
|
||||
/* Coordonnées de la tuile DANS l'image source */
|
||||
int src_x, src_y;
|
||||
int width, height;
|
||||
int id; /* ID unique, de 0 à (L*C - 2) */
|
||||
} tile_t;
|
||||
|
||||
/* Structure pour l'image source complète */
|
||||
typedef struct {
|
||||
int width;
|
||||
int height;
|
||||
char path[30];
|
||||
} image_source_t;
|
||||
|
||||
/* Prototypes */
|
||||
|
||||
/* Obtient les informations de l'image choisie */
|
||||
image_source_t get_image_source(int selected_index);
|
||||
|
||||
/* Crée et retourne un tableau de tuiles (découpage) */
|
||||
tile_t **images_slice(image_source_t img_src, int rows, int cols);
|
||||
|
||||
/* Libère la mémoire allouée par images_slice (selon la règle free/malloc) */
|
||||
void images_free_tiles(tile_t **tiles, int num_tiles);
|
||||
|
||||
#endif /* IMAGES_H */
|
||||
+37
-17
@@ -4,11 +4,15 @@
|
||||
*/
|
||||
|
||||
#include "menu_view.h"
|
||||
#include <graph.h> /* La bibliothèque IUT */
|
||||
#include <stdlib.h> /* Pour EXIT_SUCCESS */
|
||||
#include <stdio.h> /* Pour printf */
|
||||
#include "game_logic.h" /* Nouveau: pour initialiser le jeu */
|
||||
#include "images.h" /* Nouveau: pour le chargement des tuiles */
|
||||
#include "utils.h" /* Nouveau: pour l'aléatoire */
|
||||
#include <graph.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h> /* Pour srand() */
|
||||
|
||||
/* Constantes de la fenêtre (doivent être disponibles partout) */
|
||||
/* Constantes de la fenêtre */
|
||||
#define WINDOW_WIDTH 800
|
||||
#define WINDOW_HEIGHT 600
|
||||
|
||||
@@ -24,42 +28,58 @@ int main(void)
|
||||
InitialiserGraphique();
|
||||
CreerFenetre(10, 10, WINDOW_WIDTH, WINDOW_HEIGHT);
|
||||
|
||||
/* Initialisation du générateur aléatoire (OBLIGATOIRE pour game_shuffle) */
|
||||
srand((unsigned int)time(NULL));
|
||||
|
||||
menu_init(&menu_state);
|
||||
|
||||
next_update = Microsecondes() + REFRESH_CYCLE;
|
||||
|
||||
/* 2. Boucle du Menu (tant que le joueur n'a pas validé ou quitté) */
|
||||
/* 2. Boucle du Menu */
|
||||
while (menu_state.ready_to_play == 0)
|
||||
{
|
||||
/* Gestion du temps et Rendu (dessin) */
|
||||
if (Microsecondes() > next_update)
|
||||
{
|
||||
menu_render(&menu_state);
|
||||
|
||||
/* FORCER L'AFFICHAGE : Copier l'écran 0 vers l'écran 0
|
||||
(Technique souvent nécessaire avec XLib pour forcer le rafraîchissement) */
|
||||
/* Force l'affichage */
|
||||
CopierZone(0, 0, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, 0, 0);
|
||||
|
||||
next_update = Microsecondes() + REFRESH_CYCLE;
|
||||
}
|
||||
|
||||
/* Gestion des événements Souris */
|
||||
if (SourisCliquee())
|
||||
{
|
||||
/* _X et _Y sont mis à jour par SourisCliquee() */
|
||||
menu_handle_mouse_click(&menu_state);
|
||||
}
|
||||
|
||||
/* Gestion des événements Clavier */
|
||||
menu_handle_key(&menu_state);
|
||||
}
|
||||
|
||||
/* 3. Sortie */
|
||||
/* 3. Transition vers le jeu ou sortie */
|
||||
if (menu_state.ready_to_play == 1) {
|
||||
printf("Configuration valide. Image %d choisie, grille %d x %d. Lancement du jeu...\n",
|
||||
menu_state.selected_image + 1, menu_state.rows, menu_state.cols);
|
||||
|
||||
/* TODO: Appeler game_init, game_shuffle et la boucle de jeu (GRANDE PARTIE 2) */
|
||||
image_source_t img_src;
|
||||
tile_t **tiles;
|
||||
game_state_t game_state;
|
||||
int num_tiles = menu_state.rows * menu_state.cols;
|
||||
|
||||
/* 3.1. Préparation des données et allocation */
|
||||
img_src = get_image_source(menu_state.selected_image);
|
||||
tiles = images_slice(img_src, menu_state.rows, menu_state.cols);
|
||||
|
||||
/* Initialisation du jeu */
|
||||
game_init(&game_state, menu_state.rows, menu_state.cols, tiles);
|
||||
|
||||
/* Mélange (Partie 3) */
|
||||
game_shuffle_safe(&game_state, 500);
|
||||
|
||||
printf("DEBUG: Jeu prêt. Grille %d x %d melangee. Lancement de la boucle de jeu...\n",
|
||||
game_state.rows, game_state.cols);
|
||||
|
||||
/* TODO: Boucle de JEU (GRANDE PARTIE 3) */
|
||||
|
||||
/* 3.2. Nettoyage après la fin de la partie */
|
||||
images_free_tiles(tiles, num_tiles);
|
||||
game_free(&game_state);
|
||||
}
|
||||
|
||||
FermerGraphique();
|
||||
|
||||
+5
-3
@@ -1,4 +1,6 @@
|
||||
/* src/menu_view.h */
|
||||
/* src/menu_view.h
|
||||
* Définition de l'état du menu et des prototypes pour le module de configuration.
|
||||
*/
|
||||
|
||||
#ifndef MENU_VIEW_H
|
||||
#define MENU_VIEW_H
|
||||
@@ -12,10 +14,10 @@ typedef struct {
|
||||
int selected_image; /* Index de l'image (0, 1, ou 2) */
|
||||
int rows; /* Nombre de lignes (3 à 8) */
|
||||
int cols; /* Nombre de colonnes (3 à 8) */
|
||||
int ready_to_play; /* 1 si le joueur a validé */
|
||||
int ready_to_play; /* 1 si le joueur a validé, -1 si demande de quitter */
|
||||
} menu_state_t;
|
||||
|
||||
/* Prototypes des fonctions */
|
||||
/* Prototypes des fonctions publiques */
|
||||
void menu_init(menu_state_t *state);
|
||||
void menu_render(const menu_state_t *state);
|
||||
void menu_handle_mouse_click(menu_state_t *state);
|
||||
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
/* src/utils.c */
|
||||
|
||||
#include "utils.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Renvoie la valeur absolue */
|
||||
int abs_val(int n)
|
||||
{
|
||||
if (n < 0) {
|
||||
return -n;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
/* Renvoie un entier aléatoire entre 0 et max-1 */
|
||||
int random_int(int max)
|
||||
{
|
||||
if (max <= 0) return 0;
|
||||
/* rand() est initialisé dans main.c */
|
||||
return rand() % max;
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
/* src/utils.h
|
||||
* Déclarations des fonctions utilitaires simples.
|
||||
*/
|
||||
|
||||
#ifndef UTILS_H
|
||||
#define UTILS_H
|
||||
|
||||
/* Renvoie la valeur absolue d'un entier */
|
||||
int abs_val(int n);
|
||||
|
||||
/* Renvoie un entier aléatoire entre 0 et max-1 */
|
||||
int random_int(int max);
|
||||
|
||||
#endif /* UTILS_H */
|
||||
|
||||
Reference in New Issue
Block a user