250 likes | 362 Views
Spécification des règles du Jeu de Go en Coq. Travail d’Etude et de Recherche. Ngoc - Trang CAO 2007/2008. Sommaire. Représentation du Jeu de Go Parcours de Goban Identifier les groupes Calcul des libertés Reconnaître les « yeux » Les méthodes de décompte.
E N D
Spécification des règles du Jeu de Go en Coq Travail d’Etude et de Recherche Ngoc-Trang CAO 2007/2008
Sommaire • Représentation du Jeu de Go • Parcours de Goban • Identifier les groupes • Calcul des libertés • Reconnaître les « yeux » • Les méthodes de décompte
1. Représentation du Jeu de Go • La partie est représentée par une liste de tour de jeu. • Un tour de jeu est caractérisé par une couleur (noir ou blanc) et d’une action (un coup ou un passe).
1. Représentation du Jeu de Go Inductive couleur : Set := | noir | blanc | vide. Inductive tour : Set := | coup : couleur -> nat -> nat -> tour | pass : couleur -> tour. Inductive partie : Set := | pvide : nat -> partie | joue : tour -> partie -> partie.
1. Représentation du Jeu de Go • Cette représentation est intuitive et simple. • Elle suffit à représenter complètement une partie, mais n’est pas adaptée à l’analyse d’une configuration. • Une configuration de jeu est représentée par une fonction finie qui à chaque coordonnée indique son état.
1. Représentation du Jeu de Go (* fonction représentant le goban *) Definitiongob_fun := nat->nat->couleur. (* goban + sa taille *) Record goban : Set := mk_goban { size : nat; content : gob_fun }.
1. Représentation du Jeu de Go • A partir de la liste des coups, nous voulons construire l’état du goban à n’importe quel moment de la partie. • Une liste de coup vide correspond donc à une fonction qui renvoie « vide » pour toute intersection. • A chaque coup, nous surchargeons cette fonction en conséquences.
1. Représentation du Jeu de Go Fixpointgoban_of_game' (p:partie) (g:goban) {struct p}:= match p with | pvide n => mk_goban n (fun x y => vide) | joue t q => match t with | pass _ => goban_of_game' q g | coup c lig col => vide_vois (mod_cont (goban_of_game' q g) lig col c) lig col end end. Definitiongoban_of_game (p:partie) := goban_of_game' p (mk_goban 0 (fun x y => vide)).
2. Parcours de Goban • Coq n’accepte que des fonctions dont l’argument de récursion est à chaque appel, structurellement plus petit. • Le parcours du goban est décomposé en 2 fonctions récursives. • La première parcours une ligne entière de size-1 à 0. • Ensuite, la seconde fait appel à la première pour chaque ligne du goban.
2. Parcours de Goban (* type des fonctions qui renvoient des fonctions info *) Definitionfunc_info := goban->info->nat->nat->info. (* parcours d'une ligne de goban *) (* avec en parametre une fonction renvoyant une nouvelle info *) Fixpointiter_lig_info (g: goban) (f:info) (h:func_info) (x y :nat) {struct x}:(info) := match x with | 0 => h g f x y | S q => iter_lig_info g (h g f x y) h q y end. (* parcours du goban *) (* avec en parametre une fonction renvoyant une nouvelle info *) Fixpointiter_gob_info (g:goban) (f:info) (h:func_info) (y:nat) {struct y}:(info) := match y with | 0 => iter_lig_info g f h (g.(size)-1) y | S p => iter_gob_info g (iter_lig_info g f h (g.(size)-1) y) h p end.
3. Identifier les groupes • Chaque groupe du goban est numéroté (également les groupes vides). • L’appartenance d’une intersection à un groupe est « stockée » par une fonction de type : Definition info := nat->nat->nat. • Le but est de définir cette fonction en un seul parcours de goban.
3. Identifier les groupes • Tout d’abord, nous avons besoin d’une fonction initiale qui à chaque intersection associe un groupe différent. • Ensuite une fonction qui fusionne deux groupes : Definitionmerge (f:info) (a b : nat) := let max := max a b in let min := min a b in fun x y => if (beq_nat (f x y) max) then min else (f x y).
3. Identifier les groupes • La fonction de fusion de groupe appliquée à chaque voisin : Definitionmerge_voisN (g:goban) (f:info) (x y : nat) : info := ifnegb(beq_nat y (g.(size)-1)) then ifegc (g.(content) x y) (g.(content) x (S y)) then merge f (f x y) (f x (S y)) else f else f. Definitionmerge_vois (g:goban) (f:info) ( x y :nat) : info := merge_voisN g (merge_voisE g (merge_voisS g (merge_voisO g f x y) x y) x y) x y.
3. Identifier les groupes • Finalement, on applique cette fusion à toutes les intersections grâce au parcours du goban : Definitioninfo_grp (g:goban) := iter_gob_info g (init_gr g.(size)) merge_vois (g.(size)-1).
4. Calcul des libertés • Une liberté d’un groupe est une intersection libre connexe au groupe. • Le but est de lister les libertés d’un groupe. • Le principe est de parcourir de goban, lorsque l’on tombe sur le groupe concerné, on vérifie si ses voisins sont des libertés.
4. Calcul des libertés Recordliberte : Set := mk_lib { col : nat ; lig : nat }. Definitioneq_lib (a b : liberte) := match a, b with | mk_lib n m, mk_lib n' m' => beq_nat n n' && beq_nat m m' end. Fixpointapp_lib (a : liberte) (l : listliberte) {struct l} := match l with | nil => false | b :: l' => if (eq_lib a b) thentrueelseapp_lib a l' end. Definitionadd_lib (a : liberte) (l:listliberte) := if (app_lib a l) then l else a :: l.
5. Reconnaître les « yeux » • Un œil est une liberté dont les 4 voisins sont de la même couleur (noir ou blanc). • De plus, ils doivent être du même groupe sinon c’est un faux œil. • Pour vérifier si un groupe est vivant, il ne reste plus qu’à parcourir la liste de ses libertés et trouver au moins 2 yeux.
5. Reconnaître les « yeux » Definitionest_oeil (g:goban) (a:nat) (x y : nat) := match g.(content) x y with | vide => letgrp := info_grp g in (ifnegb(beq_nat x (g.(size)-1)) thenbeq_nat a (grp (S x) y) elsetrue) && (ifnegb(beq_nat x 0) thenbeq_nat a (grp (x-1) y) elsetrue) && (ifnegb(beq_nat y 0) thenbeq_nat a (grp x (y-1)) elsetrue) && (ifnegb(beq_nat y (g.(size)-1)) thenbeq_nat a (grp x (S y)) elsetrue) | _ => false end.
6. Les méthodes de décompte • A la fin de la partie, les pierres mortes sont retirées, on calcule le score de chaque joueur. • Le résultat est la différence des scores. • Les joueurs de Go utilisent 3 règles différentes de décompte du score : la règle Chinoise, Japonaise et Française.
6. Les méthodes de décompte • En règles Chinoise : le score de chaque joueur est la somme du nombre de ses pierres et du nombre d’intersections libres qu’il a entourées. • Les scores en règles Japonaise se compte autrement : c’est le nombre d’intersections libres contrôlées auquel on soustrait le nombre de prisonniers (c.à.d. les pierres capturées par l’adversaire durant la partie et les pierres mortes retirées à la fin).
6. Les méthodes de décompte En règles chinoises : Noir : 36 Blanc : 45 Donc N+9. En règles japonaises : Noir : 25 Blanc : 17 Donc N+8.
6. Les méthodes de décompte • Par l’exemple précédent, nous venons de montrer clairement la différence entre les règles chinoises et japonaises. • La règle Française utilise le même procédé de décompte que la Chinoise. • Les joueurs français étant habitué à la règle japonaise préfèrent compter « à la japonaise ».
6. Les méthodes de décompte • Pour avoir l’équivalence entre les deux, la règle Française dit en plus : • À chaque « passe », étant donné que le joueur ne pose pas la pierre sur le goban, il doit la donner en tant que prisonnier à son adversaire. • Blanc doit passer le dernier. • Avec ses conditions en plus, l’équivalence des deux méthodes de décompte est assurée.
Conclusion • Implémentation du jeu de Go en Coq. • Fonction d’analyse des groupes • Calcul des libertés • Détection des yeux • Preuves informelles des décomptes • A faire : • Implémentation des règles de décompte • Preuves concernant la capture
Les gens normaux jouent au Renju, le jeu d’Echecs est pour les Héros, le Go est réservé aux Dieux. Proverbe japonais.