Browse Source

Reconstruction

master
Valentin Moguérou 6 months ago
parent
commit
5f5f77bb24
  1. 2
      .gitignore
  2. 56
      CGU.txt
  3. 20
      Makefile
  4. BIN
      grille
  5. 382
      grille.c
  6. 8
      main.c
  7. 418
      src/cli.c
  8. 64
      src/display.c
  9. 473
      src/grille.c
  10. 23
      src/grille.h

2
.gitignore

@ -188,3 +188,5 @@ fabric.properties
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser
bin/
obj/

56
CGU.txt

@ -0,0 +1,56 @@
Conditions Générales d'Utilisation
En jouant à ce jeu, vous acceptez tacitement les présentes Conditions Générales d'Utilisation.
I. Définitions
Par Joueur nous entendons toute personne physique, morale ayant la capacité juridique ou, dans le cas contraire, ayant eu le consentement d'un de ses responsables légaux.
Par Programme nous entendons l'ensemble constitué de l'exécutable sous forme binaire virtuellement stockée sur un support physique idoine (disque dur, SSD, clef USB, disquette, cassette, carte à trous, serveur distant, papier calque, tableau noir ou serveur téléphonique accessible via un terminal minitel).
Par Autobus nous entendons toue passoire du troisième ordre dont le diamètre des trous est nul et qui ne possède pas de manche.
Par Conditions Générales D'Utilisation nous entendons le texte français que le Joueur lit, écoute, télépathe, rêve, crie, chuchotte, marmonne, hurle, et caetera.
II. Dispositions générales
1. Le précent logiciel est fourni sans aucune garantie, y compris sans garatie implicite de fiabilité ou d'adéquation à un usage particulier. En particulier, le non-amusement ne constitue pas un motif valable de remboursement du présent Logiciel.
2. En cas de désaccord avec les présentes Conditions générales, vous vous engagez à ne pas poursuivre l'exécution du Logiciel en effectuant l'une des actions suivantes :
2.1. Arrêt immédiat interne de l'exécution du logiciel en appuyant sur une des combinaisons de touche suivantes : ^C, ^D ;
2.2. Arrêt immédiat externe de l'exécution du logiciel en utilisant un logiciel externe non fourni (kill, gestionnaire des tâches) ;
2.3. Arrêt immédiat en éteignant votre ordinateur en appuyant sur un bouton physique ou virtuel
2.4. Arrêt différé du logiciel en débranchant toute source d'alimentation à votre ordinateur et en laissant sa batterie se vider (cet arrêt est immédiat si votre support d'exécution est dépourvu de batterie d'accumulateurs).
III. Dispositions spécifiques
1. Il est strictement interdit d'utiliser le Programme pour accomplir les actes suivants :
1.1. Actes terroristes ou de nature à porter atteinte à l'intégrité de la République Française, ou de tout état dans lequel le Programme est exécuté ;
1.2. Catastrophes naturelles (tornades, innondations, sécheresse, pluie, ouragan, typhon, tremblement de terre, glissement de terrain, éruption d'un volcan effusif ou explosif, tsunami, froid hivernal de nature à provoquer un rhume) ;
1.3. Création d'une œuvre artistique sonore de nature à constituer une chanson qui reste dans la tête et ce de ce fait, de nature à créer un trouble de l'ordre public.
IV. Effets secondaires
1. Le Joueur reconnaît que l'utilisation répétée du Jeu peut créer de l'addiction, de l'ennui, ou ultimement des troubles psychatriques irréversibles. Le Joueur s'engage à consulter son médecin traitant avant toute utilisation du Jeu.
2. Le Joueur reconnait que la non-utilisation du Jeu permet la réalisation d'activités de nature à améliorer le Joueur en tant que personne (sport, interactions sociales, jardinage, balade en forêt, pêche, programmation, mathématiques, physique, lecture, hygiène)
3. Le Joueur consent à la défaite tout comme à la victoire. En cas de litige, il est invité à consulter le Médiateur:
Médiateur des Mauvais Perdants
42 boulevard de la Mauvaise Foi
75021 Paris 21e arrdt. CEDEX
V. Applicabilité
L'auteur du Programme remercie le Joueur d'avoir pris le temps de lire les présentes Conditions. Le Joueur reconnaît que le Programme est placé sous license GNU GPL v3 ou ultérieure telle que publiée par la Free Software Foundation. Les termes et conditions de la GNU GPL v3 annulent et remplacent les présentes Conditions, à l'exceptions des années bissextiles multiples de 100 non multiples de 400.
Si vous acceptez les présentes Conditions,
vous pouvez appuyer sur <Entrée>.

20
Makefile

@ -0,0 +1,20 @@
CC=gcc
CFLAGS=-Wall -Wextra -Wpedantic
LDFLAGS=
bin/cli: obj/grille.o obj/cli.o
@mkdir -p bin
$(CC) -o $@ $^ $(LDFLAGS)
obj/grille.o: src/grille.c src/grille.h
@mkdir -p obj
$(CC) -o $@ -c $< $(CFLAGS)
obj/cli.o: src/cli.c
@mkdir -p obj
$(CC) -o $@ -c $< $(CFLAGS)
.PHONY: clean
clean:
rm -rf bin/ obj/

BIN
grille

Binary file not shown.

382
grille.c

@ -1,382 +0,0 @@
/*
* 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> // à enlever après
#include <stdlib.h>
#include <stdbool.h>
#include "grille.h"
char repr_jeton(jeton j)
{
switch (j)
{
case (BLEU):
return 'B';
case (ROUGE):
return 'R';
default:
return '_';
}
}
void print_tab(jeton *tab, int n)
{
for (int i=0; i<n; i++)
printf("%p --> %x (%d)\n", &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] = VIDE;
}
}
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)
{
if (col->hauteur >= col->capacite
&& !agrandir_colonne(Y_BLOCK_SIZE, col))
return false;
col->jetons[col->hauteur] = j;
printf("(%p)->jetons[%d] = %c\n", col, col->hauteur, repr_jeton(j));
col->hauteur++;
return true;
}
jeton get_jeton_col(int indice, colonne *col)
{
return (indice < col->hauteur) ? col->jetons[indice] : VIDE;
}
void detruire_colonne(colonne *col)
{
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(int largeur)
{
/* On divise largeur en deux :
*
* |-----------------------------|-----------------------------|
* negatifs 0 positifs
*
* d' 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 = largeur/2 + largeur%2;
g->n_negatifs = largeur/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) : VIDE;
}
bool ajouter_jeton(jeton j, int x, grille *g)
{
if (x >= 0 && x > g->n_positifs)
for (int i=0; i < x-g->n_positifs+1; i++)
if (!etendre_droite(X_BLOCK_SIZE, g))
return false;
if (x < 0 && ~x > g->n_negatifs)
for (int i=0; i < ~x-g->n_negatifs+1; i++)
if (!etendre_gauche(X_BLOCK_SIZE, g))
return false;
return ajouter_jeton_col(j, get_colonne(x, g));
}
void detruire_grille(grille *g)
{
for (int i=0; i < g->n_positifs; i++)
if (g->positifs[i] != NULL)
detruire_colonne(g->positifs[i]);
for (int i=0; i < g->n_negatifs; i++)
if (g->negatifs[i] != NULL)
detruire_colonne(g->negatifs[i]);
free(g);
}
// =========================================== TEST =================================================
int test_colonne()
{
colonne *col = creer_colonne(Y_BLOCK_SIZE);
print_colonne(col);
for (int i=0; i<15; i++)
{
if (ajouter_jeton_col((i%2==0) ? ROUGE : BLEU, col))
printf("Jeton ajouté.\n");
else
fprintf(stderr, "Erreur dans l'ajout d'un jeton.\n");
}
print_colonne(col);
detruire_colonne(col);
return 0;
}
void print_grille(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(20);
ajouter_jeton(BLEU, 0, g);
ajouter_jeton(BLEU, 0, g);
ajouter_jeton(BLEU, 0, g);
ajouter_jeton(ROUGE, -1, g);
ajouter_jeton(BLEU, -1, g);
ajouter_jeton(BLEU, -1, g);
ajouter_jeton(BLEU, -2, g);
ajouter_jeton(ROUGE, 4, g);
ajouter_jeton(ROUGE, 4, g);
ajouter_jeton(ROUGE, 4, g);
ajouter_jeton(BLEU, 240, g);
print_grille(g);
detruire_grille(g);
return 0;
}
int main()
{
return test_grille();
}

8
main.c

@ -1,8 +0,0 @@
#include "grille.h"
#include "display.h"
int main(int argc, char **argv)
{
return 0;
}

418
src/cli.c

@ -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

@ -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

@ -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' 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;
}
*/

23
grille.h → src/grille.h

@ -1,14 +1,13 @@
#ifndef GRILLE_H_INCLUDED
#define GRILLE_H_INCLUDED
#define X_BLOCK_SIZE 20
#include <stdio.h>
#include <stdbool.h>
#define X_BLOCK_SIZE 10
#define Y_BLOCK_SIZE 10
typedef enum jeton {
VIDE = 0,
BLEU = 1,
ROUGE = 2
} jeton;
typedef int jeton;
typedef struct colonne {
int hauteur;
@ -24,14 +23,22 @@ typedef struct grille {
} grille;
grille *creer_grille(int largeur);
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, 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 */
Loading…
Cancel
Save