compte rendu tetris

Transcription

compte rendu tetris
PROJET : INTELLIGENCE
ARTIFICIELLE D’UN TETRIS
Présenté par :
Olivier FOULT
Guillaume CRESTA
Groupe G 21
TABLE DES MATIERES
Ce compte rendu comporte plusieurs parties comme indiqué ci – dessous.
Description de l’objet du projet
Les algorithmes de principe
Les fichiers utilisés
Quelques Programmes commentés
Makefile
Impressions générales et conclusion
p. 3
p. 4
p. 8
p. 10
p.11
p.12
L’objet du projet est de réaliser un tétris à intelligence artificielle. Cela va
permettre au tétris de jouer tout seul. Nous avons tenté de réaliser un programme
d’intelligence artificielle chargée de tester différents poids, pour chaque position
possible, afin de jouer de mieux en mieux au tétris. Par conséquent, afin de jouer
seul, on fait intervenir des poids fixé aléatoirement au départ (mais positif) ; ces
poids pouvant être le nombre de lignes, la hauteur maximale du tétris, les trous,
les lignes où est posé la pièce, l’homogénéité du tétris, la moyenne des hauteurs
de la pièce et la plus haute ligne de la pièce. Le but de ce tétris est que
l’ordinateur « apprenne » et s’améliore au fur et à mesure de la partie. Pour
cela, il va faire varier d’un delta aléatoire (positif ou négatif) les poids fixés au
départ. Si le nombre de lignes obtenu avec ce nouveau jeu de poids est supérieur
au meilleur score que l’on avait obtenu, alors le nouveau jeu de poids est
conservé, on recommence ainsi jusqu’à ce que le nombre de lignes n’augmente
plus. Le résultat après chaque test, est retourné sous forme texte.
Algo d’apprentissage
Nous avons choisis de prendre un maximum de 20 itérations maximales
pour chaque jeu de poids. Apres quoi le tetris s’arrêtera si il n’a pas trouve de
meilleur solution.
Tant que le compteur d’itérations est inférieur a 20
Choix de 3 voisins parmi les 7 poids présents.
Choix de l’implémentation entre -40 et 40 (a l’aide de la fonction
alea)
Pour chaque poids faire
Si la valeur du poids est positive alors
On joue au tetris avec 10000 pièces.
On sauvegarde le score total (nombre de lignes)
Remise a 0 de score total
Le tableau est remis dans sa forme initiale
Si l’un des score total est supérieur au score max alors
Score max=Score total
Si le score max a été implémente on implémente le tableau des
poids avec le poids correspondant
On remet le nombre d’itération a 0
On incrémente le compteur d’itérations
Lorsque 20 itérations successives sont jouées sans aucune améliorations, on stop
la boucle et on sauvegarde les poids.
On réitère le procédé 3 fois en repartant sur des tetris aléatoires à chaque fois
A la fin des 3 tetris on peut jouer avec l’un des différents jeux de poids.
Algo de jeu tetris
Tant qu’aucune piece n’est en haut du tetris et que le nombre de pièces jouées
est inférieur a 10000 faire
Choix d’une pièce aléatoire
Pour chaque rotation de la pièce faire
Appelle de la fonction recherche_piece qui recherche la meilleure
place pour la pièce
Sauvegarde du score s’ il est supérieur à tous les scores précédents
De la ligne
De la colonne
Et des positions de descente de la pièce
Si le score est différent de 0 c'
est-à-dire qu’une place valide a été trouvé
pour une pièce au moins alors
On place la pièce à l’emplacement ligne, colonne
On recherche le nombre de ligne(s) et on les supprime le cas
échéant
Incrémentation du nombre de pièces jouées
Renvoie le nombre de lignes faites et modifie le nombre de pièces jouées
Algo de test de collisions
Pour chaque ligne
Pour chaque colonne
Si la case est remplie à la fois par la pièce et par une des pieces déjà
présente dans le tetris
booleen = 1
Retourne la valeur inverse du booleen, c’est à dire si une case est déjà remplie,
donc qu’on ne peut pas insérer la pièce à cet endroit.
Algo de vérification de la position de la pièce
Tant que non bool et ligne inferieur à 4
Colonne = 0
Tant que colonne inférieur à 4 et non bool
Si la case est remplie par la pièce
Si la case d’en dessous est remplie par une pièce du tetris
Bool = 1
colonne=4
Incrementation de colonne
Incrementation de ligne
On retourne la valeur de bool, c'
est-à-dire que la place est valide (du moins elle
est posée sur une ancienne pièce)
Algo pour vérifié que la pièce n’est pas dans un trou non accessible
Tant que ligne est inférieur à 13 (on n’est pas en haut du tetris) et compteur
inférieur à 10
Si la pièce est valide pour la ligne d’au dessus et la même colonne
Compteur =0
Incrémentation de la ligne
On place 0 (la différence entre la colonne de départ et la colonne
actuelle) dans la liste chaînée
Sinon
Cas suivant la valeur de k
Cas ou k = 0: Si la pièce est valide pour la colonne de droite
On incrémente la colonne
On place 1 dans la liste chaînée
Sinon
K=non k
Cas ou k=1 : Si la pièce est valide pour la colonne de gauche
On décrémente la colonne
On place -1 dans la liste chaînée
Sinon
K=non k
On incrémente le compteur
On place la dernière valeur de la colonne dans la liste chaînée (la première des
valeurs à afficher lors de la descente de la pièce)
Si le compteur est différent de 0 (la pièce ne peut pas remonter jusqu’en haut)
On libère la liste chaînée
On retourne un pointeur sur la liste chaînée (qui sera à null si la pièce n’a pas pu
« remonter »)
Algo de recherche de trous
Pour chaque ligne (du tetris)
Pour chaque colonne (du tetris)
Si l’emplacement est vide
Compteur = ligne
Tant que compteur < 16 (hauteur du tetris)
Incrémentation du compteur
Si l’emplacement ligne : ligne, colonne : compteur est
occupé
Incrémentation du nombre de trous
Compteur = 17 (pour sortir)
On retourne le nombre de cases du tetris moins le nombre de trous (plus il y a de
trous moins le score est élevé)
Makefile
C’est le makefile du projet qui comporte la commande « make » qui compile
le projet et permet d’enlever le moindre warning : grâce à la commande : CC=
gcc -ansi -Wall -pedantic -02).
alea.h/alea.c
Ici se trouve uniquement la fonction alea qui permet de générer un nombre
aléatoire allant de 1 à N.
main.h
C’est ici que figure les différents types de structures utilisées. Il regroupe de
plus tous les autres .h .
modif_tab.h/ modif_tab.c
Ici se trouve la fonction recherche_ligne qui comme son nom l’indique
permet de rechercher les lignes dans le tétris, elle peut appeler si on lui demande
la fonction supprime_ligne pour la suppression des lignes dans le tétris, la
fonction homogénéité permettant de calculer l’homogénéité de la surface du
tétris, la fonction hauteur qui permet de rechercher la hauteur maximale du
tétris, la fonction trou permettant de rechercher le nombre de « trous » dans le
tétris, la fonction moy_piece permettant de calculer de la moyenne des hauteurs
de la pièce et la fonction haut_max_piece qui recherche la plus haute ligne de la
pièce.
piece.c/piece.h
Dans ce fichier, on peut trouver creation_piece permettant de créer une
pièce du tétris (comme dans le jeu initial) et on crée toutes les pièces
représentant ses rotations. Chaque pièce est représentée par un tableau de 16
cases. Chaque case est remplie à 1 si la case appartient à la pièce, et à 0 sinon.
La fonction affichage_piece permet d’afficher une pièce du tétris, la fonction
placement nous permet de placer la pièce à l’endroit : ligne, colonne, la fonction
recherche_piece permet de rechercher la meilleur place d’une pièce dans le
tétris en calculant le score de chaque pièce pour tous les endroits valide du tetris.
Et la fonction supprime_piece de supprimer la pièce à l’endroit : ligne, colonne
(utile si on a trouvé une meilleure solution).
pro1.c / pro1.h
Ici se trouve la fonction affichage permettant l’affichage du tableau
contenant le tétris, la fonction creation pour créer et initialiser le tableau tétris et
la fonction princ pour le tétris en lui-même.
tetris.h / tetris.c
C’est ici que figure la procédure d’affichage du tableau affichage_tab des
poids qui sont le nombre de lignes, la hauteur maximale du tétris, les trous, les
lignes où est posé la pièce, l’homogénéité du tétris, la moyenne des hauteurs de
la pièce et la plus haute ligne de la pièce ; la procédure random qui donne au
tableau de poids des valeurs aléatoires ; et, le main du programme qui appelle le
tetris avec des poids qu’il aura choisi au préalable. C’est cette fonction qui
détermine l’ « intelligence » du tétris, elle choisit les voisins, l’implémentation,
et vérifie que 10000 pièces sont jouées pour chaque jeu de poids.
verif.h / verif.c
Dans ce fichier se situent les fonctions valide qui permet de tester les
collisions entre la pièce et les pièces déjà présentes dans le tétris, verif1 qui
permet de vérifier que la pièce est posée sur une autre pièce, verif2 permet de
voir si la pièce ne figure pas dans un trou bouché, allocation qui insère un
élément dir_t en tête de la liste chaînée et lui affecte la valeur val, et lib qui
permet de libérer la liste chainée de données dir_t pointée par la tête.
La structure direction
typedef struct direction {
int val;
struct direction *suiv;
}dir_t;
La structure direction sert pour l’affichage de la descente de la pièce (si le
choix de l’utilisateur l’a demandé). La liste chaînée indique pour chaque ligne si
la colonne a été modifiée. Elle permet nottamment de pouvoir insérer des pièces
dans des « trous ».
La structure place
typedef struct place {
int piece;
int ligne;
int colonne;
int score;
dir_t *dir;
}place_t;
Cette structure est renvoyée par la fonction recherche_piece, elle sert a
donné à la fonction tetris la meilleur valeur de score trouvée ainsi que la colonne
et la ligne qui lui corresponde. Elle renvoie aussi la liste chaînée permettant de
faire descendre la pièce.
La stucture voisinage
typedef struct voisinage {
int voisin;
int score;
int implementation;
}voisinage_t;
Cette structure permet de sauvegarder pour chaque voisin choisi le score atteint
et l’implémentation effectuée si jamais ce voisinage était concluant et que le
programme devait ré implémenter le poids.
CC = gcc -ansi -Wall -pedantic -O2
tetris: pro1.o piece.o modif_tab.o alea.o verif.o tetris.o
$(CC) pro1.o piece.o modif_tab.o alea.o verif.o tetris.o -o tetris
pro1.o: main.h pro1.c
$(CC) -c pro1.c
piece.o: main.h piece.c
$(CC) -c piece.c
modif_tab.o: main.h modif_tab.c
$(CC) -c modif_tab.c
alea.o: main.h alea.c
$(CC) -c alea.c
verif.o: main.h verif.c
$(CC) -c verif.c
tetris.c: main.h tetris.c
$(CC) -c tetris.c
Les jeux de poids semblent toujours converger vers une solution plus ou
moins identique. Néanmoins pour aboutir à ce résultat l’implémentation est
longue et laborieuse. Le hasard ne se dirigeant pas toujours vers la bonne
solution. C’est pour cela que nous avons choisi de pouvoir implémenter chaque
valeur de poids dans une large bande (à savoir -40,40) ainsi on peut avoir des
sauts importants. Cela permet de se sortir parfois de solutions ou tous les voisins
« proches » sont moins bons mais qui sont de « mauvaises » solutions. Le tetris
ne joue pas un nombre de jeux déterminés mais un nombre de pièces déterminé
ce qui limite la part de hasard dans le jeu. Cela n’exclut pas pour autant la part
de hasard donnée aux pièces qui sont tirées aléatoirement. Des écarts peuvent
subsister sur le nombre de lignes finales sur des jeux de poids identiques.
On constate qu’avec les poids finaux du tetris permette au programme de
jouer de façon très impressionnante, lui permettant de faire facilement plusieurs
milliers de lignes.
Nous avons rencontré un léger problème de gestion de mémoire dans la
structure dir_t malgré les différentes et nombreuses libérations que nous avons
pu effectuées.
Poids obtenu avec le programme tetris :
Nombre de lignes
Hauteur max du tetris
Trous
Ligne ou est posée la pièce
Homogénéité du Tetris
Moyenne des hauteurs de la pièce
Plus haute ligne de la pièce
tab[0]
tab[1]
tab[2]
tab[3]
tab[4]
tab[5]
tab[6]
************
tetris final
************
tetris initial : (poids aléatoires)
tab[0]= 53
tab[1]= 83
tab[2]= 71
tab[3]= 36
tab[4]= 73
tab[5]= 70
tab[6]= 97
***
fin
***
************
score max= 2856
************
Iteration 20
tab[0]= 139
tab[1]= 13
tab[2]= 171
tab[3]= 43
tab[4]= 14
tab[5]= 28
tab[6]= 36
Remarque :
Le score max est obtenu avec 10000 pièces jouées. Le score pourrait être
meilleur si on le laissait finir sa partie. Le score représente le nombre de lignes
faites (et non le score réel du tetris).
Nous n’avons pas eu assez de temps pour faire une bonne partie graphique du
tétris. Nous avons tenté de nous rapprocher des poids les mieux adapté sans pour
cela arriver à des résultats super. Cependant, on a pu s’apercevoir que lorsqu’il
joue, l’ordinateur progresse de plus en plus.

Documents pareils