Reconstruction
This commit is contained in:
418
src/cli.c
Normal file
418
src/cli.c
Normal file
@@ -0,0 +1,418 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <ctype.h>
|
||||
#include <locale.h>
|
||||
#include <unistd.h>
|
||||
#include <termios.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#include "grille.h"
|
||||
|
||||
#define NEXT_CH_BUFFER_IS(ch) (!feof(stdin) && getc(stdin)==ch)
|
||||
|
||||
/*
|
||||
* Sur Caséine le terminal fait 132 caractères de large
|
||||
*
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int lignes;
|
||||
int colonnes;
|
||||
} ecran;
|
||||
|
||||
|
||||
bool is_number(wchar_t string[])
|
||||
{
|
||||
int i=0;
|
||||
if (!isdigit(string[0]) && string[0] != L'+' && string[0] != L'-')
|
||||
return false;
|
||||
i++;
|
||||
|
||||
while (string[i] != L'\0')
|
||||
{
|
||||
if (!isdigit(string[i]))
|
||||
return false;
|
||||
i++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wcmp_fst_word(wchar_t str1[], wchar_t str2[])
|
||||
{
|
||||
int i=0;
|
||||
while ((str1[i] != L' ' && str1[i] != L'\0') && (str2[i] != L' ' && str2[i] != L'\0'))
|
||||
{
|
||||
if (str1[i] != str2[i])
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void flush_stdin()
|
||||
{
|
||||
int c;
|
||||
while ((c=getchar()) != '\n' && c != EOF);
|
||||
}
|
||||
|
||||
const char symbols[][5] = {
|
||||
" ", // VIDE
|
||||
"\U0001f534", // red circle
|
||||
"\U0001f535", // blue circle
|
||||
"\U0001f7e2", // green circle
|
||||
"\U0001f7e1", // yellow circle
|
||||
"\U0001f7e0", // orange circle
|
||||
"\U0001f7e3", // purple circle
|
||||
"\U0001f7e4", // brown circle
|
||||
"\u26AB", // black circle
|
||||
"\u26AA", // white circle
|
||||
};
|
||||
|
||||
void cur_goto(int line, int column)
|
||||
{
|
||||
printf("\033[%d;%dH", line, column);
|
||||
}
|
||||
|
||||
void clear_screen()
|
||||
{
|
||||
printf("\033[2J");
|
||||
}
|
||||
|
||||
void rect(int x1, int x2, int y1, int y2)
|
||||
{
|
||||
cur_goto(y1, x1);
|
||||
printf("\u250C");
|
||||
cur_goto(y1, x2);
|
||||
printf("\u2510");
|
||||
cur_goto(y2, x1);
|
||||
printf("\u2514");
|
||||
cur_goto(y2, x2);
|
||||
printf("\u2518");
|
||||
|
||||
for (int x=x1+1; x<x2; x++)
|
||||
{
|
||||
cur_goto(y1, x);
|
||||
printf("\u2500");
|
||||
cur_goto(y2, x);
|
||||
printf("\u2500");
|
||||
}
|
||||
|
||||
for (int y=y1+1; y<y2; y++)
|
||||
{
|
||||
cur_goto(y, x1);
|
||||
printf("\u2502");
|
||||
cur_goto(y, x2);
|
||||
printf("\u2502");
|
||||
}
|
||||
}
|
||||
|
||||
void print_rect_fichier(int x1, int x2, int y1, int y2, const char* nom_fichier, int offset_y)
|
||||
{
|
||||
FILE * fichier = fopen(nom_fichier, "r");
|
||||
|
||||
int x=x1, y=y1-offset_y;
|
||||
wchar_t ch = fgetwc(fichier);
|
||||
|
||||
while (ch != EOF && y <= y2)
|
||||
{
|
||||
if (ch == '\n')
|
||||
{
|
||||
x = x1;
|
||||
y++;
|
||||
}
|
||||
else if (y >= y1)
|
||||
{
|
||||
cur_goto(y, x);
|
||||
printf("%lc", ch);
|
||||
x++;
|
||||
}
|
||||
|
||||
if (x>x2)
|
||||
{
|
||||
y++;
|
||||
x = x1;
|
||||
}
|
||||
ch = fgetwc(fichier);
|
||||
}
|
||||
|
||||
fclose(fichier);
|
||||
}
|
||||
|
||||
void print_rect(int x1, int x2, int y1, int y2, int* chaine, int offset_y)
|
||||
{
|
||||
int x=x1, y=y1-offset_y;
|
||||
|
||||
for (int *ch = chaine; *ch != '\0' && y <= y2; ch++)
|
||||
{
|
||||
if (x>x2)
|
||||
{
|
||||
y++;
|
||||
x = x1;
|
||||
}
|
||||
|
||||
if (*ch == '\n')
|
||||
{
|
||||
x = x1;
|
||||
y++;
|
||||
}
|
||||
else if (y >= y1)
|
||||
{
|
||||
cur_goto(y, x);
|
||||
printf("%lc", *ch);
|
||||
x++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int **prompt_names(ecran ecr, const int prompt[], int n_joueurs)
|
||||
{
|
||||
clear_screen();
|
||||
rect(ecr.colonnes/3, 2*ecr.colonnes/3, ecr.lignes/3, 2*ecr.lignes/3);
|
||||
|
||||
getchar();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int quot(int a, int b)
|
||||
{
|
||||
return (a>=0) ? a/b : a/b-1;
|
||||
}
|
||||
|
||||
void print_grille(ecran ecr, int base_x, int base_y, grille *g)
|
||||
{
|
||||
clear_screen();
|
||||
if (ecr.lignes-base_y-1 < ecr.lignes && ecr.lignes > base_y+1)
|
||||
{
|
||||
for (int x=1; x<=ecr.colonnes; x+=2)
|
||||
{
|
||||
cur_goto(ecr.lignes-base_y-2, x);
|
||||
printf("\u2500\u2500"); // box drawing character
|
||||
if ((quot((x+1),2)-base_x)%10==0 && x+2 < ecr.colonnes) printf("\v%d", quot(x+1,2)-base_x);
|
||||
}
|
||||
}
|
||||
|
||||
for (int y=1; y<ecr.lignes-base_y-2 && y<ecr.lignes; y++)
|
||||
{
|
||||
for (int x=1; x<=ecr.colonnes; x+=2)
|
||||
{
|
||||
cur_goto(y, x);
|
||||
|
||||
jeton j = get_case(quot(x,2)-base_x, ecr.lignes-base_y-3-y, g);
|
||||
printf("%s", symbols[j]);
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void process_command(ecran ecr, int *offset_x, int *offset_y, bool *do_abort, bool *tour, grille *g)
|
||||
{
|
||||
cur_goto(ecr.lignes, 0);
|
||||
printf(":");
|
||||
wchar_t c = getchar();
|
||||
wchar_t prompt[100] = L"";
|
||||
int i=0;
|
||||
|
||||
while (c != '\n')
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case '\003':
|
||||
case '\004':
|
||||
*do_abort = true;
|
||||
fprintf(stderr, (c == '\003') ? "^C\n" : "^D\n");
|
||||
return;
|
||||
case '\177':
|
||||
if (i>0)
|
||||
{
|
||||
prompt[i-1] = 0;
|
||||
i--;
|
||||
}
|
||||
break;
|
||||
case '\033':
|
||||
if (NEXT_CH_BUFFER_IS('['))
|
||||
switch (getchar())
|
||||
{
|
||||
case 'C': // ->
|
||||
break;
|
||||
case 'D': // <-
|
||||
if (i>0)
|
||||
i--;
|
||||
}
|
||||
else
|
||||
return;
|
||||
default:
|
||||
if (i<99)
|
||||
{
|
||||
prompt[i] = c;
|
||||
prompt[i+1] = 0;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
cur_goto(ecr.lignes, 0);
|
||||
printf("\033[2K:%ls", prompt);
|
||||
cur_goto(ecr.lignes, i+2);
|
||||
c = getchar();
|
||||
}
|
||||
|
||||
if (is_number(prompt))
|
||||
{
|
||||
*offset_x = ecr.colonnes/4 - wcstol(prompt, NULL, 10);
|
||||
}
|
||||
/* else if (wcmp_fst_word(prompt, L"save"))
|
||||
{
|
||||
printf("Saving...");
|
||||
getchar();
|
||||
} */
|
||||
}
|
||||
|
||||
void process_input(ecran ecr, int *offset_x, int *offset_y, bool *do_abort, jeton joueur, int *last_x, int *last_y, grille *g)
|
||||
{
|
||||
bool tour = true;
|
||||
while (tour && !*do_abort)
|
||||
{
|
||||
print_grille(ecr, *offset_x, *offset_y, g);
|
||||
cur_goto(0, ecr.colonnes/2+1);
|
||||
printf("%s", symbols[joueur]);
|
||||
|
||||
switch (getchar())
|
||||
{
|
||||
case ':':
|
||||
process_command(ecr, offset_x, offset_y, do_abort, &tour, g);
|
||||
break;
|
||||
case '\003':
|
||||
printf("^C\n");
|
||||
*do_abort = true;
|
||||
break;
|
||||
case '\004':
|
||||
printf("^D\n");
|
||||
*do_abort = true;
|
||||
break;
|
||||
case '\033':
|
||||
if (NEXT_CH_BUFFER_IS('['))
|
||||
switch(getc(stdin))
|
||||
{
|
||||
case 'A':
|
||||
//printf("A"); break;
|
||||
(*offset_y)--; break;
|
||||
case 'B':
|
||||
//printf("B"); break;
|
||||
(*offset_y)++; break;
|
||||
case 'C':
|
||||
//printf("C"); break;
|
||||
(*offset_x)--; break;
|
||||
case 'D':
|
||||
//printf("D"); break;
|
||||
(*offset_x)++; break;
|
||||
}
|
||||
break;
|
||||
case ' ':
|
||||
*last_x = ecr.colonnes/4 - *offset_x;
|
||||
ajouter_jeton(joueur, *last_x, last_y, g);
|
||||
tour = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool read_cgu(ecran ecr)
|
||||
{
|
||||
|
||||
int offset_y=0;
|
||||
bool cgu_agree = false, cgu_disagree = false;
|
||||
while (!cgu_agree && !cgu_disagree)
|
||||
{
|
||||
clear_screen();
|
||||
rect(2, ecr.colonnes-1, 2, ecr.lignes-1);
|
||||
|
||||
cur_goto(3,4);
|
||||
print_rect_fichier(4, ecr.colonnes-3, 3, ecr.lignes-2, "CGU.txt", offset_y);
|
||||
|
||||
switch (getchar())
|
||||
{
|
||||
case '\n':
|
||||
cgu_agree = true; break;
|
||||
case '\033': // ESC
|
||||
if (NEXT_CH_BUFFER_IS('['))
|
||||
switch(getchar())
|
||||
{
|
||||
case 'A': if (offset_y>0) offset_y--; break;
|
||||
case 'B': offset_y++; break;
|
||||
}
|
||||
break;
|
||||
case '\003':
|
||||
case '\004':
|
||||
cgu_disagree = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return cgu_agree;
|
||||
}
|
||||
|
||||
void jouer(ecran ecr, int n_joueurs)
|
||||
{
|
||||
grille *g = creer_grille();
|
||||
|
||||
ajouter_jeton(BLEU, 0, NULL, g);
|
||||
ajouter_jeton(ROUGE, 0, NULL, g);
|
||||
|
||||
int offset_x = ecr.colonnes/4, offset_y = 0;
|
||||
int last_x = 0, last_y = 0;
|
||||
bool do_abort = false;
|
||||
|
||||
jeton joueur = 0;
|
||||
|
||||
do {
|
||||
joueur = joueur%n_joueurs + 1;
|
||||
|
||||
process_input(ecr, &offset_x, &offset_y, &do_abort, joueur, &last_x, &last_y, g);
|
||||
} while (!gagnant(last_x, last_y, 5, g) && !do_abort);
|
||||
|
||||
if (!do_abort)
|
||||
{
|
||||
print_grille(ecr, offset_x, offset_y, g);
|
||||
cur_goto(0,0);
|
||||
printf("Le joueur %s a gagné. Appuyer sur une touche pour continuer...", symbols[joueur]);
|
||||
getchar();
|
||||
cur_goto(0,0);
|
||||
clear_screen();
|
||||
}
|
||||
|
||||
detruire_grille(g);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
setlocale (LC_ALL, "");
|
||||
|
||||
static struct termios oldterm, newterm;
|
||||
|
||||
tcgetattr(STDIN_FILENO, &oldterm);
|
||||
newterm = oldterm;
|
||||
|
||||
newterm.c_lflag &= ~(ICANON | IEXTEN | ISIG | ECHO | ECHONL);
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &newterm);
|
||||
|
||||
ecran ecr = {20, 80};
|
||||
|
||||
setvbuf(stdin, NULL, _IONBF, 4);
|
||||
|
||||
printf("\033[?1049h"); // écran alternatif
|
||||
|
||||
if (read_cgu(ecr))
|
||||
{
|
||||
//prompt_names(ecr, L"Joueurs ?", 2);
|
||||
jouer(ecr, 2);
|
||||
}
|
||||
|
||||
|
||||
printf("\033[?1049l"); // écran initial
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &oldterm);
|
||||
|
||||
flush_stdin();
|
||||
|
||||
return 0;
|
||||
}
|
||||
64
src/display.c
Normal file
64
src/display.c
Normal file
@@ -0,0 +1,64 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <wchar.h>
|
||||
#include <locale.h>
|
||||
|
||||
#define ATOM_SIZE 3
|
||||
|
||||
typedef wchar_t pixel;
|
||||
|
||||
typedef struct {
|
||||
int width, height;
|
||||
pixel **pixels;
|
||||
} ecran;
|
||||
|
||||
ecran* creer_ecran(int width, int height)
|
||||
{
|
||||
ecran* ecr = malloc(sizeof(ecran));
|
||||
|
||||
ecr->width = width;
|
||||
ecr->height = height;
|
||||
ecr->pixels = malloc(height * sizeof(pixel));
|
||||
|
||||
for (int i=0; i<ecr->height; i++)
|
||||
ecr->pixels[i] = malloc((width+1) * sizeof(pixel));
|
||||
|
||||
return ecr;
|
||||
}
|
||||
|
||||
void detruire_ecran(ecran* ecr)
|
||||
{
|
||||
for (int i=0; i<ecr->height; i++)
|
||||
free(ecr->pixels[i]);
|
||||
|
||||
free(ecr->pixels);
|
||||
free(ecr);
|
||||
}
|
||||
|
||||
void set_px(pixel px, int x, int y, ecran *ecr)
|
||||
{
|
||||
ecr->pixels[y][x] = px;
|
||||
}
|
||||
|
||||
pixel get_px(int x, int y, ecran *ecr)
|
||||
{
|
||||
return ecr->pixels[y][x];
|
||||
}
|
||||
|
||||
void print_ecran(ecran *ecr)
|
||||
{
|
||||
for (int i=0; i<ecr->height; i++)
|
||||
printf("%ls\n", ecr->pixels[i]);
|
||||
}
|
||||
|
||||
|
||||
int main(void)
|
||||
{
|
||||
setlocale(LC_ALL, "");
|
||||
|
||||
ecran *ecr = creer_ecran(100, 50);
|
||||
|
||||
print_ecran(ecr);
|
||||
|
||||
detruire_ecran(ecr);
|
||||
}
|
||||
473
src/grille.c
Normal file
473
src/grille.c
Normal file
@@ -0,0 +1,473 @@
|
||||
/*
|
||||
* Infini puissance N : un jeu à plusieurs joueurs.
|
||||
* Copyright (C) 2023 Valentin Moguérou
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdio.h> // pour la gestion des fichiers
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "grille.h"
|
||||
|
||||
/*
|
||||
void print_tab(jeton *tab, int n)
|
||||
{
|
||||
for (int i=0; i<n; i++)
|
||||
printf("%p --> %x (%d)\n", (void*)&tab[i], tab[i], tab[i]);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void print_colonne(colonne *col)
|
||||
{
|
||||
for (int i=0; i<col->capacite; i++)
|
||||
putc(repr_jeton(col->jetons[i]), stdout);
|
||||
putc('\n', stdout);
|
||||
}
|
||||
*/
|
||||
|
||||
void init_zeros(jeton* ptr, int count)
|
||||
{
|
||||
for (int i=0; i<count; i++)
|
||||
{
|
||||
ptr[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
colonne *creer_colonne(int capacite)
|
||||
{
|
||||
colonne *col = malloc(sizeof(colonne));
|
||||
if (col == NULL)
|
||||
return NULL;
|
||||
|
||||
col->jetons = malloc(capacite*sizeof(jeton));
|
||||
if (col->jetons == NULL)
|
||||
{
|
||||
free(col);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
init_zeros(col->jetons, capacite);
|
||||
|
||||
col->capacite = capacite;
|
||||
col->hauteur = 0;
|
||||
|
||||
return col;
|
||||
}
|
||||
|
||||
bool agrandir_colonne(int diff_taille, colonne *col)
|
||||
{
|
||||
jeton *jetons_nouv = realloc(col->jetons, (col->capacite + diff_taille)*sizeof(jeton));
|
||||
if (jetons_nouv == NULL)
|
||||
return false; // allocation impossible, on garde col->jetons tel quel
|
||||
|
||||
col->jetons = jetons_nouv;
|
||||
|
||||
// on met des zéros dans la partie nouvellement attribuée
|
||||
init_zeros(col->jetons + col->capacite, diff_taille);
|
||||
|
||||
// free est appelée par realloc et les éléments sont copiés par realloc
|
||||
col->capacite += diff_taille;
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool ajouter_jeton_col(jeton j, colonne *col, int* y)
|
||||
{
|
||||
if (col->hauteur >= col->capacite)
|
||||
if (!agrandir_colonne(Y_BLOCK_SIZE, col))
|
||||
return false;
|
||||
|
||||
col->jetons[col->hauteur] = j;
|
||||
col->hauteur++;
|
||||
|
||||
if (y != NULL) *y = col->hauteur - 1;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
jeton get_jeton_col(int indice, colonne *col)
|
||||
{
|
||||
return (indice < col->hauteur && indice >= 0) ? col->jetons[indice] : 0;
|
||||
}
|
||||
|
||||
void detruire_colonne(colonne *col)
|
||||
{
|
||||
if (col == NULL) return;
|
||||
|
||||
free(col->jetons);
|
||||
free(col);
|
||||
}
|
||||
|
||||
/*
|
||||
* On essaie de représenter une structure abstraite comme ceci :
|
||||
* En abscisse, les "colonne*"; en ordonnée, les "jeton"
|
||||
*
|
||||
* +oo (jetons)
|
||||
* ^
|
||||
* |
|
||||
* |
|
||||
* |
|
||||
* |
|
||||
* |
|
||||
* -oo <------------------------I----------------------> +oo (colonne*)
|
||||
*
|
||||
* Représentation en mémoire :
|
||||
*
|
||||
* g->positifs = [colonne*(0), colonne*(1), ...]
|
||||
* // autant que de colonnes positives ou nulles ç.à.d autant que g->n_positifs
|
||||
*
|
||||
* g->negatifs = [colonne*(-1), colonne*(-2) , ...]
|
||||
* // autant que de colonnes str. négatives ç.à.d autant que g->n_negatifs
|
||||
*/
|
||||
|
||||
grille *creer_grille()
|
||||
{
|
||||
/* On divise largeur en deux :
|
||||
*
|
||||
* |-----------------------------|-----------------------------|
|
||||
* negatifs 0 positifs
|
||||
*
|
||||
* d'où n_positifs = largeur/2 + largeur%2
|
||||
* n_negatifs = largeur/2
|
||||
*
|
||||
* de telle sorte que:
|
||||
* n_negatifs + n_positifs = largeur
|
||||
*
|
||||
* Ex :
|
||||
* - L'intervalle [-10, 9] de cardinal 20 se découpe en
|
||||
* 10 nombres positifs [0, 9] et 10 nombres négatifs [-10, -1] représenté
|
||||
*/
|
||||
|
||||
grille *g = malloc(sizeof(grille));
|
||||
if (g == NULL)
|
||||
return NULL;
|
||||
|
||||
g->n_positifs = X_BLOCK_SIZE/2 + X_BLOCK_SIZE%2;
|
||||
g->n_negatifs = X_BLOCK_SIZE/2;
|
||||
g->positifs = malloc(g->n_positifs * sizeof(colonne*));
|
||||
g->negatifs = malloc(g->n_negatifs * sizeof(colonne*));
|
||||
|
||||
if (g->positifs == NULL || g->negatifs == NULL)
|
||||
{
|
||||
free(g->positifs);
|
||||
free(g->negatifs);
|
||||
free(g);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool echec_allocation = false;
|
||||
|
||||
for (int i=0; i < g->n_positifs; i++)
|
||||
{
|
||||
g->positifs[i] = creer_colonne(Y_BLOCK_SIZE);
|
||||
if (g->positifs[i] == NULL)
|
||||
echec_allocation = true;
|
||||
}
|
||||
|
||||
for (int i=0; i < g->n_negatifs; i++)
|
||||
{
|
||||
g->negatifs[i] = creer_colonne(Y_BLOCK_SIZE);
|
||||
if (g->negatifs[i] == NULL)
|
||||
echec_allocation = true;
|
||||
}
|
||||
|
||||
|
||||
// si une colonne n'a pas pu être crée, on détruit la grille
|
||||
if (echec_allocation)
|
||||
{
|
||||
detruire_grille(g);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return g;
|
||||
}
|
||||
|
||||
|
||||
bool etendre_tab(int d_len, int *len, colonne ***tab)
|
||||
{
|
||||
/* Fonction qui prend en entrée une différence de taille, un pointeur
|
||||
* vers un tableau de colonnes et un pointeur vers sa longueur.
|
||||
*
|
||||
* Si la réallocation n'échoue pas (99.99% des cas), le pointeur vers
|
||||
* le tableau est éventuellement modifié (selon la tambouille de realloc)
|
||||
* et la taille est modifiée.
|
||||
*
|
||||
* Un argument est un colonne*** car c'est un pointeur vers un tableau de colonne*
|
||||
*
|
||||
*/
|
||||
|
||||
colonne **tab_nouv = realloc(*tab, (*len + d_len)*sizeof(colonne*));
|
||||
if (tab_nouv == NULL)
|
||||
return false; // la mémoire n'a pas pu être allouée
|
||||
|
||||
*tab = tab_nouv;
|
||||
|
||||
bool echec_allocation = false;
|
||||
for (int i=0; i<d_len; i++)
|
||||
{
|
||||
(*tab)[*len + i] = creer_colonne(Y_BLOCK_SIZE);
|
||||
if ((*tab)[*len + i] == NULL)
|
||||
echec_allocation = true;
|
||||
}
|
||||
|
||||
// si échec on revient à l'état initial
|
||||
if (echec_allocation)
|
||||
{
|
||||
for (int i=0; i<d_len; i++)
|
||||
if ((*tab)[*len + i] != NULL)
|
||||
detruire_colonne((*tab)[*len + i]);
|
||||
return false;
|
||||
}
|
||||
|
||||
*len += d_len;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool etendre_gauche(int d_len, grille *g)
|
||||
{
|
||||
// application sur les négatifs
|
||||
return etendre_tab(d_len, &g->n_negatifs, &g->negatifs);
|
||||
}
|
||||
|
||||
bool etendre_droite(int d_len, grille *g)
|
||||
{
|
||||
// application sur les positifs
|
||||
return etendre_tab(d_len, &g->n_positifs, &g->positifs);
|
||||
}
|
||||
|
||||
|
||||
colonne *get_colonne(int i, grille *g)
|
||||
{
|
||||
/* La structure de tableau double sens se traduit de la façon suivante :
|
||||
*
|
||||
* Si i >= 0, on regarde g->positifs[i]
|
||||
* Si i < 0, on regarde g->negatifs[-i-1]
|
||||
*/
|
||||
|
||||
if (i >= 0 && i < g->n_positifs)
|
||||
return g->positifs[i];
|
||||
else if (i < 0 && ~i < g->n_negatifs)
|
||||
return g->negatifs[~i];
|
||||
else
|
||||
return NULL; // en dehors de l'allocation
|
||||
}
|
||||
|
||||
jeton get_case(int x, int y, grille *g)
|
||||
{
|
||||
colonne *col = get_colonne(x, g);
|
||||
return (col != NULL) ? get_jeton_col(y, col) : 0;
|
||||
}
|
||||
|
||||
int ceil_div(int a, int b)
|
||||
{
|
||||
return (a%b == 0) ? (a/b) : (a/b + 1);
|
||||
}
|
||||
|
||||
int next_step(int x, int step)
|
||||
{
|
||||
return step * ceil_div(x, step);
|
||||
}
|
||||
|
||||
|
||||
bool ajouter_jeton(jeton j, int x, int *y, grille *g)
|
||||
{
|
||||
if (x >= 0 && x >= g->n_positifs)
|
||||
{
|
||||
if (!(etendre_droite(next_step(x - g->n_positifs + 1, X_BLOCK_SIZE), g)))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (x < 0 && ~x >= g->n_negatifs)
|
||||
{
|
||||
if (!(etendre_gauche(next_step(~x - g->n_negatifs + 1, X_BLOCK_SIZE), g)))
|
||||
return false;
|
||||
}
|
||||
|
||||
return ajouter_jeton_col(j, get_colonne(x, g), y);
|
||||
}
|
||||
|
||||
|
||||
void detruire_grille(grille *g)
|
||||
{
|
||||
for (int i=0; i < g->n_positifs; i++)
|
||||
detruire_colonne(g->positifs[i]);
|
||||
|
||||
for (int i=0; i < g->n_negatifs; i++)
|
||||
detruire_colonne(g->negatifs[i]);
|
||||
|
||||
free(g);
|
||||
}
|
||||
|
||||
|
||||
bool gagnant_aux(int x, int y, int dx, int dy, int n, grille *g)
|
||||
{
|
||||
if (n==1)
|
||||
return true;
|
||||
|
||||
return (get_case(x+dx, y+dy, g) == get_case(x, y, g) && get_case(x, y, g) != 0)
|
||||
? gagnant_aux(x+dx, y+dy, dx, dy, n-1, g)
|
||||
: false;
|
||||
}
|
||||
|
||||
bool gagnant(int x, int y, int N, grille *g)
|
||||
{
|
||||
/* Fonction qui renvoie si le dernier joueur gagne
|
||||
* en fonction de la position du dernier joueur.
|
||||
*
|
||||
* x: abscisse du dernier jeton posé
|
||||
* y: ordonnée du dernier jeton posé
|
||||
* g: grille de travail
|
||||
*/
|
||||
|
||||
for (int dx = -1; dx < 2; dx++)
|
||||
for (int dy = -1; dy < 2; dy++)
|
||||
if ((dx != 0 || dy != 0) && gagnant_aux(x, y, dx, dy, N, g))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void sauvegarder_colonne(FILE *stream, colonne *c)
|
||||
{
|
||||
for (int i=0; i<c->hauteur; i++)
|
||||
if (c->jetons[i] != 0)
|
||||
fprintf(stream, "%d\n", c->jetons[i]);
|
||||
}
|
||||
|
||||
void sauvegarder(FILE *stream, grille *g)
|
||||
{
|
||||
for (int i=0; i<g->n_positifs; i++)
|
||||
{
|
||||
fprintf(stream, "%d;", i);
|
||||
sauvegarder_colonne(stream, g->positifs[i]);
|
||||
}
|
||||
|
||||
for (int i=0; i<g->n_negatifs; i++)
|
||||
{
|
||||
fprintf(stream, "%d;", ~i);
|
||||
sauvegarder_colonne(stream, g->negatifs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
grille *charger(FILE *stream)
|
||||
{
|
||||
grille *g = creer_grille();
|
||||
|
||||
int col, joueur;
|
||||
while (fscanf(stream, "%d;%d", &col, &joueur) == 3)
|
||||
ajouter_jeton(joueur, col, NULL, g);
|
||||
|
||||
return g;
|
||||
}
|
||||
|
||||
// =========================================== TEST =================================================
|
||||
|
||||
/*
|
||||
|
||||
|
||||
int test_colonne()
|
||||
{
|
||||
colonne *col = creer_colonne(Y_BLOCK_SIZE);
|
||||
print_colonne(col);
|
||||
|
||||
int y;
|
||||
for (int i=0; i<241; i++)
|
||||
{
|
||||
if (ajouter_jeton_col((i%2==0) ? ROUGE : BLEU, col, &y))
|
||||
printf("Jeton ajouté à hauteur %d.\n", y);
|
||||
else
|
||||
fprintf(stderr, "Erreur dans l'ajout d'un jeton.\n");
|
||||
}
|
||||
|
||||
print_colonne(col);
|
||||
|
||||
detruire_colonne(col);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void print_grille_temp(grille *g)
|
||||
{
|
||||
printf("n_positifs : %d ; n_negatifs : %d\n", g->n_positifs, g->n_negatifs);
|
||||
for (int i=-g->n_negatifs; i<g->n_positifs; i++)
|
||||
{
|
||||
printf("% 5d | ", i);
|
||||
print_colonne(get_colonne(i, g));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int test_grille()
|
||||
{
|
||||
grille *g = creer_grille();
|
||||
|
||||
int y;
|
||||
for (int i=0; i<6; i++)
|
||||
{
|
||||
ajouter_jeton(BLEU, 0, &y, g);
|
||||
|
||||
print_grille_temp(g);
|
||||
printf("\n\n\n\n\n");
|
||||
|
||||
if (gagnant(0, y, 5, g))
|
||||
printf("Le dernier joueur a gagné.\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
detruire_grille(g);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
jeton jouer()
|
||||
{
|
||||
grille *g = creer_grille();
|
||||
int tour = 0;
|
||||
|
||||
int x, y;
|
||||
do {
|
||||
print_grille_temp(g);
|
||||
|
||||
printf("Test %c\n", repr_jeton(get_case(-50, -50, g)));
|
||||
|
||||
printf("Tour %d, joueur %c. Entrer colonne : ", tour, repr_jeton((jeton)(tour%2 + 1)));
|
||||
scanf("%d", &x);
|
||||
|
||||
ajouter_jeton((jeton)(tour%2 + 1), x, &y, g);
|
||||
|
||||
tour++;
|
||||
} while (!gagnant(x, y, 5, g));
|
||||
|
||||
print_grille_temp(g);
|
||||
|
||||
jeton gagnant = (tour-1)%2 + 1;
|
||||
printf("Le gagnant est %c.\n", repr_jeton(gagnant));
|
||||
|
||||
return gagnant;
|
||||
}
|
||||
|
||||
|
||||
int main(void)
|
||||
{
|
||||
jouer();
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
44
src/grille.h
Normal file
44
src/grille.h
Normal file
@@ -0,0 +1,44 @@
|
||||
#ifndef GRILLE_H_INCLUDED
|
||||
#define GRILLE_H_INCLUDED
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define X_BLOCK_SIZE 10
|
||||
#define Y_BLOCK_SIZE 10
|
||||
|
||||
typedef int jeton;
|
||||
|
||||
typedef struct colonne {
|
||||
int hauteur;
|
||||
int capacite;
|
||||
jeton* jetons;
|
||||
} colonne;
|
||||
|
||||
typedef struct grille {
|
||||
int n_positifs;
|
||||
colonne **positifs;
|
||||
int n_negatifs;
|
||||
colonne **negatifs;
|
||||
} grille;
|
||||
|
||||
|
||||
grille *creer_grille();
|
||||
|
||||
colonne *get_colonne(int i, grille *g);
|
||||
|
||||
jeton get_case(int x, int y, grille *g);
|
||||
|
||||
bool ajouter_jeton(jeton j, int x, int *y, grille *g);
|
||||
|
||||
void detruire_grille(grille *g);
|
||||
|
||||
bool gagnant(int x, int y, int N, grille *g);
|
||||
|
||||
jeton get_case(int x, int y, grille *g);
|
||||
|
||||
void sauvegarder(FILE *stream, grille *g);
|
||||
|
||||
grille *charger(FILE *stream);
|
||||
|
||||
#endif /* GRILLE_H_INCLUDED */
|
||||
Reference in New Issue
Block a user