Sunteți pe pagina 1din 10

ENSEIRB-MATMECA

Rapport de Projet

Kitty Wonderland

Tara Bahrami
Table des matières
1 Choix des types de données 2
1.1 Choix du plateau . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.2 Choix d’un joueur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.3 Choix d’une carte . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4

2 La version de base 4
2.1 Les fonctions de base . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2.1.1 L’effet des cartes . . . . . . . . . . . . . . . . . . . . . . . . . 4
2.1.2 Modélisation de la main . . . . . . . . . . . . . . . . . . . . . 5
2.1.3 Mort d’un joueur . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.2 Choix des différents modules . . . . . . . . . . . . . . . . . . . . . . . 5
2.3 Les difficultés rencontrées . . . . . . . . . . . . . . . . . . . . . . . . 5

3 Achievement 1 6
3.1 Structure du deck . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
3.2 Déroulement du jeu . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
3.2.1 Modifications apportées . . . . . . . . . . . . . . . . . . . . . 6
3.2.2 Influence sur les autres fichiers . . . . . . . . . . . . . . . . . . 7
3.3 Les difficultés rencontrées . . . . . . . . . . . . . . . . . . . . . . . . 7
3.4 Gestion du Makefile . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8

4 Fonctions tests 8

1
Introduction
Dans le cadre du projet d’algorithmique et de programmation nous avons ici
travaillé sur un jeu nommé Kitty Wonderland. Ainsi, le but de ce projet est de mo-
déliser un jeu de société. En effet, Kitty Wonderland est un jeu de carte.
Tous les joueurs de la partie sont munis d’une jauge de points d’énergie, d’une
jauge d’idées, d’un gain mais également de cartes. Chaque joueur reçoit un nombre
fini de cartes. Il existe cinq types de cartes différentes : KITTY_THINK, KITTY_STEAL,
KITTY_PANACEA, KITTY_RAZOR, KITTY_HELL_IS_OTHERS. Ayant cha-
cune une rareté et un coût. Ainsi, chaque carte jouée a un impact sur le joueur et/ou
sur un adversaire. Un joueur meurt lorsque sa jauge d’énergie est inférieure ou égale
à zéro. Par conséquent, le jeu termine lorsqu’il ne reste plus qu’un joueur.

Il nous a été demandé de modéliser ce jeu sur des algorithmes rédigés en langage
C. Nous avons donc tout d’abord réfléchi aux éléments nécessaires à la définition
du plateau, d’un joueur et d’une carte. Dans un deuxième temps, nous avons pro-
grammé les fonctions de base c’est-à-dire les fonctions appliquant le traitement au
joueur selon la carte jouée. Enfin, nous avons codé un algorithme général faisant
tourner le jeu.
Ce rapport a pour but d’expliquer nos choix, nos démarches mais également des
certaines difficultés rencontrées.

1 Choix des types de données


1.1 Choix du plateau
Tout d’abord, nous devons créer un plateau de jeu qui dépend du nombre de
joueur. Ainsi, afin d’implémenter le plateau nous allons utiliser une structure struct
plateau. On fixe dans celle-ci le nombre de joueur nb_joueur et un tableau tj[MAX_JOUEUR]
contenant à chaque case un des joueur du jeu.
Nous avons choisi de modéliser le plateau de cette manière afin de pouvoir choisir
le nombre de joueur lors d’une partie et de stocker ces derniers ; ici dans un tableau.

Figure 1 – Struct plateau

Nous pouvons voir que le tableau de joueurs contient des éléments du type struct
joueur. Ce type sera explicité dans la partie suivante.

2
1.2 Choix d’un joueur
Comme nous l’avons vu dans l’introduction, tous les joueurs ont chacun une
jauge de points d’énergie, d’une jauge d’idées (autrement dit mana), d’un gain et de
cartes. Il nous a donc paru judicieux de modéliser le joueur à l’aide d’une structure
contenant toutes ces caractéristiques.

Figure 2 – Struct joueur

Nous avons choisi d’attribuer à chaque joueur un numéro d’identification (id ).


Ce choix a été fait car cela nous facilitait la gestion des joueurs. Ainsi par exemple,
pour initialiser le plateau de jeu, il suffit de rentrer le nombre de joueur souhaité sur
le plateau. Ensuite, en faisant une boucle for, à chaque passage dans la boucle on
crée un nouveau joueur avec l’identifiant correspondant au passage de boucle.
En effet, chaque joueur a également sa propre pioche (deck ). Cependant, dans
la version de base ce dernier n’est pas utilisé : le joueur tire une carte aléatoirement
en fonction de sa rareté.
Enfin, les joueurs ont une main de cartes, qui est également composée aléatoire-
ment. Cette main de cartes est modélisée par un tableau rempli de kittycartes. Nous
avons décidé de faire une énumération pour les différentes cartes car le type enum
est vu comme un entier et il nous semblait plus facile de manipuler des objets de
type entier que des objets de type caractère.

3
1.3 Choix d’une carte
Pour finir nous allons aborder la gestion des cartes. Comme dans les deux der-
nières sous parties nous avons choisi d’utiliser une structure pour modéliser ces
dernières.

Figure 3 – Struct carte

Cette structure est très simple, elle comporte le type enum kittycarte et son coût
qui dépend de cette dernière.

2 La version de base
Comme nous l’avons vu dans la partie précédente, chaque joueur a une jauge de
points d’énergie, une jauge d’idée et d’un gain. En effet, avant de commencer le jeu,
chaque joueur reçoit par défaut cinquante points d’énergie, un point de gain et a sa
jauge d’énergie réduite à zéro. De plus, il tire cinq cartes dans le deck : dans le jeu
de base, le deck est simplement modélisé par un tirage de cartes aléatoire dépendant
de la rareté de cette dernière.
Dans cette partie, nous allons donc introduire les fonctions permettant de changer
les caractéristiques de chaque joueur.

2.1 Les fonctions de base


2.1.1 L’effet des cartes
Tout d’abord, nous allons récapituler les actions de chaque carte jouée.

Kittycarte Coût d’idée Effet sur le joueur Effet sur l’adversaire


Kitty Think 5 gain : +1 gain : +0
Kitty Steal 10 gain : +1 gain : -1
Kitty Panacea 2 énergie : +10 gain : +0
Kitty Razor 2 énergie : +0 énergie : -10
Kitty Hell Is Others 100 énergie : +0 énergie : -30
Table 1 – Effet des cartes.

Ainsi, nous avons décidé de modéliser ces changements de gains et d’énergies à


l’aide de deux fonctions : action qui attribue les points d’énergies et de gains aux
joueurs en fonction de la carte tirée et cout qui donne le coût de la kittycarte.

4
La fonction cout prend en argument une kittycarte et renvoie son coût. La fonc-
tion action prend en argument une kittycarte et deux pointeurs sur la structure
joueur (le joueur à qui la kittycarte appartient et un joueur adversaire). Nous avons
choisi d’utiliser un pointeur sur joueur afin que les modifications sur le joueur dans
la fonction appelée soient répercutées sur le reste du programme.

2.1.2 Modélisation de la main


Comme nous l’avons vu précédemment, chaque joueur est muni d’une main de
carte. Ainsi, les cartes jouées sont choisies uniquement parmi celles applicables c’est-
à-dire en fonction du coût de la carte et du mana du joueur.
Pour faire cela, nous avons programmé une fonction choisir_carte_main qui
prend en argument un pointeur sur un joueur et qui retourne une kittycarte. En effet,
nous avons choisi de créer un tableau nb_carte_jouable de taille MAX_CARTE
contenant toutes les cartes jouables possibles. Si ce tableau est non vide, nous tirons
une carte aléatoirement parmi ces dernières sinon on tire une carte aléatoirement
dans la main du joueur. Ainsi, la complexité de cette fonction est linéaire en temps
et en espace car on passe MAX_CARTE fois dans la boucle for afin de vérifier si la
carte peut être jouée et on alloue un tableau de taille MAX_CARTE.

2.1.3 Mort d’un joueur


Un joueur est mort lorsqu’il n’a plus de points d’énergie. Ce dernier sera décalé
au fond du tableau de la structure plateau, le nb_joueur de la structure plateau
décrémente de un et les joueurs vivants derrière lui avancent d’une case. Ainsi, le
tableau des joueurs vivants sera tout le temps parcourut de 0 au nombre de joueurs
vivants.

2.2 Choix des différents modules


Afin de faciliter la lecture du code, nous avons séparé le code. Tout d’abord
nous avons créé un fichier header contenant toutes les définitions c’est-à-dire toutes
les variables globales, les différentes structures et l’énumération de kittycartes. Ainsi
nous avons inclus ce header dans tous les fichiers sources. En effet, nous avons séparé
nos fichiers sources en fonction des types d’argument que les fonctions prennent. Par
exemple, toutes les fonctions prenant une structure joueur se trouvent dans joueur.c
etc.

2.3 Les difficultés rencontrées


Ayant très peu d’expérience en codage dans le langage C, nous avons mis beau-
coup de temps à coder la base de jeu. Tout d’abord, nous avons rencontré des
problèmes du type syntaxe, par exemple l’initialisation des structures n’était pas
naturelle. Ensuite, nous avions codé beaucoup de fonctions sans utiliser les poin-
teurs. Or, cela est inconcevable car nous voulons que les modifications faites sur un
paramètre du jeu (par exemple un joueur) soient répercutées sur le reste du pro-
gramme. Pour finir, nous avons rencontré des erreurs de segmentation. Ainsi, nous
avons appris à utiliser la commande valgrind qui nous éclairait un peu plus sur le
problème en question.

5
3 Achievement 1
3.1 Structure du deck
Le deck a été modélisé par une structure liste_memento contenant une tableau
de struct cartes, un indice de début et un indice de fin du deck qui changent en
fonction de l’avancement du jeu. Le choix de cette modélisation a été fait de sorte
que la structure FIFO soit respectée et pour que la complexité ne soit pas très élevée
par rapport à d’autres solutions ; en effet, on aurait pu stocker les cartes jouées dans
un autre tableau, sauf que la manipulation de deux tableau implique l’utilisation
de deux boucles imbriquées, ce qui augmentera la complexité ( on aura donc une
complexité quadratique ), alors que dans notre cas la compléxité est linéaire.
Par conséquent la structure du joueur a dû être modifiée pour prendre en consi-
dération le nouveau modèle du deck, et ce en ajoutant un pointeur (*deck) sur la
structure liste mémento, ce qui permet au deck de garder l’état dans lequel il était
dans le dernier tour.

3.2 Déroulement du jeu


3.2.1 Modifications apportées
Puisque les cartes du deck ne sont plus réparties selon une certaine probabilité,
chaque joueur a un deck de 45 cartes dès le début du jeu et 5 cartes en main, ce
dernier devra donc être initialisé et rempli avant le début du jeu et mélangé quand
le joueur n’aura plus de cartes dans son deck, d’où la nécessité des fonctions initiali-
ser_deck, remplir_deck et mélanger_deck. Ainsi, quand le joueur pioche une carte,
le pointeur du début s’incrémente et indique le nouveau début du deck tandis que
l’indice de fin reste le même dans cette étape, et la carte est stockée dans le tableau
représentant la main du joueur.

Figure 4 – Représentation du deck initial.

6
Figure 5 – Représentation du deck après que le joueur ait pioché une carte.

Figure 6 – Représentation du deck une fois que le joueur a fini de jouer le premier
tour.

3.2.2 Influence sur les autres fichiers


La fonction d’initialisation du joueur dans le plateau a été modifiée pour prendre
en compte l’implantation de la nouvelle structure, ainsi que le fichier carte.c où une
fonction creer_carte a été ajoutée, cette dernière transforme un enum kittycarte en
un struct carte, cette fonction s’est imposée car plusieurs erreurs ont été signalées
lors de la compilation par rapport à des conflits de type. Pour respecter la struc-
ture FIFO, chaque carte jouée est placée en fin de deck grâce à la fonction ajou-
ter_carte_fin, celle-ci a été ajoutée après la fonction action dans le fichier main.c,
et c’est dans ce cas que l’indice de fin s’incrémente pour gérer les prochaines cartes
jouées.

3.3 Les difficultés rencontrées


Avant d’opter pour la structure liste_memento comme présentée auparavant, on
avait utilisé une structure de liste chaîné pour représenter le deck, on a donc utilisé
deux pointeurs sur cette structure (debut et fin) et une autre structure memento
contenant un pointeur suivant sur cette structure même, qui gère la liste chaînée,

7
sauf que l’on a appris par la suite de la part des encadrants que cette méthode
dépassait notre niveau en programmation et qu’on avait besoin des allocations de
la mémoire, il fallait donc utiliser des structures plus simples en manipulant des
tableaux. Néanmoins, ceci nous a permis de manipuler encore plus les pointeurs qui
nous paraissaient abstraits en cours de programmation impérative. Lors de la
compilation de deck_ach1, une erreur de segmentation a été signalée, on a donc
utilisé Valgrind pour essayer de comprendre l’erreur, on a remarqué ensuite qu’il
fallait initialiser le deck et les pointeurs. On a crée donc un tableau de struct carte
dont les indices représentent les identités des joueurs, et on a initialisé le pointeur
deck de sorte qu’il pointe vers la case du joueur correspondant.

3.4 Gestion du Makefile


Afin de pouvoir compiler séparément la version de base initiale et celle conte-
nant les changements de l’achievement 1, nous avons décidé de créer deux fichiers
différents : deck_base.c et deck_ach1.c. Cependant, ces deux fichiers contiennent
les mêmes prototypes afin de pouvoir utiliser un seul main. Ainsi, les fonctions non
utilisées dans deck_base et présentes dans deck_ach1 sont quand même déclarées
dans deck_base avec un corps vide (cf figure 7) afin que le main puisse être compiler
dans les deux cas.

Figure 7 – Fonction vide

4 Fonctions tests
Afin de valider chaque étape du jeu, il nous était demandé de créer un ficher test
pour vérifier le bon déroulement du jeu. Ainsi, pour chaque fonction utilisée dans le
fichier main.c nous avons créer des fonctions retournant des booléens. En effet, nous
avons testé l’égalité entre ce que la fonction à tester renvoie et ce qu’on est censé
obtenir.
Ces fonctions tests sont créées pour assurer le code. En effet, dans ces fonctions
on cherche à tester tous les cas possibles car notre code utilise des programmes du
type random qui ne testent donc pas forcément tous les cas possibles.

8
Conclusion
Nous nous sommes arrêtés à la fin de l’achievement 1 car nous avons

S-ar putea să vă placă și