Ceci est une ancienne révision du document !
En construction
Site de référence pour la définition: http://fr.wikipedia.org/wiki/Morpion_%28jeu%29
En résumé: on a une grille carrée composée de 3 x 3 = 9 cases. 2 joueurs s'affrontent. Chacun a des pions de forme différente, par exemple une croix ('X') pour l'un et un rond ('O') pour l'autre. Les joueurs jouent alternativement en mettant un pion dans une case vide. Le gagnant est le 1er joueur qui a aligné 3 de ses pions en ligne, en colonne ou en diagonale. Il est possible qu'il n'y ait pas de gagnant si aucun n'a réussi à aligner ses pions alors qu'il n'y a plus de case vide.
Exemple: le joueur qui a le pion 'X' a gagné:
X | O | X |
O | X | O |
X | O | X |
#!/usr/bin/python # -*- coding: utf-8 -*- from __future__ import division import threading import time import random ############################################################################## # Mise en place de la grille du jeu imax = 3 jmax = 3 grille=[] for i in xrange(0,imax): grille.append([]) for j in xrange(0,jmax): grille[i].append(' ') ############################################################################### def initcoef(): """créer un tableau de coefficients: 1.0 pour les cases vides, 0.0 sinon""" global grille,imax,jmax coef=[] for i in xrange(0,imax): coef.append([]) for j in xrange(0,jmax): if grille[i][j]==' ': coef[i].append(1.0) else: coef[i].append(0.0) return coef ############################################################################### def pondcoef(coef): """pondère les cases vides en fonction de leurs positions""" coef[1][1]*=3.0 coef[0][0]*=2.0 coef[2][2]*=2.0 coef[0][2]*=2.0 coef[2][0]*=2.0 return coef ############################################################################### def coupscoef(coef): global grille, imax, jmax # obtenir la liste des coups possibles par ordre décroissant des coef L=[] for i in xrange(0,imax): for j in xrange(0,jmax): if coef[i][j]>0: L.append([coef[i][j], i, j]) L.sort() L.reverse() # si plusieurs cases avec coef le + fort, sélectionner le 1er au hasard if len(L)!=0: c=L[0][0] im=0 for i in xrange(1,len(L)): if L[i][0]!=c: im=i-1 break k=random.randint(0,im) x=L.pop(k) L.insert(0,x) # renvoyer une liste ordonnee (coef décroissants) sans les coef R=[] for i,j,k in L: R.append([j,k]) return R ############################################################################### def coupsgagnants(pion): global grille L=[] p1=pion + pion + " " p2=pion + " " + pion p3=" " + pion + pion # 1ère ligne x = "".join(grille[0]) if x==p1: L.append([0,2]) if x==p2: L.append([0,1]) if x==p3: L.append([0,0]) # 2ème ligne x = "".join(grille[1]) if x==p1: L.append([1,2]) if x==p2: L.append([1,1]) if x==p3: L.append([1,0]) # 3ère ligne x = "".join(grille[2]) if x==p1: L.append([2,2]) if x==p2: L.append([2,1]) if x==p3: L.append([2,0]) z=zip(grille[0],grille[1],grille[2]) # 1ère colonne x = "".join(z[0]) if x==p1: L.append([2,0]) if x==p2: L.append([1,0]) if x==p3: L.append([0,0]) # 2ème colonne x = "".join(z[1]) if x==p1: L.append([2,1]) if x==p2: L.append([1,1]) if x==p3: L.append([0,1]) # 3ème colonne x = "".join(z[2]) if x==p1: L.append([2,2]) if x==p2: L.append([1,2]) if x==p3: L.append([0,2]) # 1ère diagonale x = grille[0][0] + grille[1][1] + grille[2][2] if x==p1: L.append([2,2]) if x==p2: L.append([1,1]) if x==p3: L.append([0,0]) # 2ème diagonale x = grille[0][2] + grille[1][1] + grille[2][0] if x==p1: L.append([2,0]) if x==p2: L.append([1,1]) if x==p3: L.append([0,2]) return L ############################################################################### def correction(LC,pionautre): """parmi les coups de la liste LC, mettre en avant un coup plus efficace s'il y en a un""" if len(LC)<=1: return LC kc=0 for k in range(0,len(LC)): ic=LC[k][0] jc=LC[k][1] # vérif ligne ic ch=grille[ic][0] + grille[ic][1] + grille[ic][2] if ch.find(pionautre)<0: # => la ligne ic n'a pas le pion de l'adversaire kc=k break # vérif colonne jc ch=grille[0][jc] + grille[1][jc] + grille[2][jc] if ch.find(pionautre)<0: # => la colonne jc n'a pas le pion de l'adversaire kc=k break # vérif 1ère diagonale si la case ic,jc en fait partie if ic==jc: ch=grille[0][0] + grille[1][1] + grille[2][2] if ch.find(pionautre)<0: # => la 1ère diagonale n'a pas le pion de l'adversaire kc=k break # vérif 2ème diagonale si la case ic,jc en fait partie if ic==(2-jc): ch=grille[0][2] + grille[1][1] + grille[2][0] if ch.find(pionautre)<0: # => la 2ème diagonale n'a pas le pion de l'adversaire kc=k break if kc>0: # on a trouvé un meilleur coup que le 1er: le mettre en 1ère position L=LC.pop(kc) LC.insert(0,L) return LC ############################################################################### def ajouer(pion): # recherche de qui est en train de jouer if pion=='X': pionautre='O' else: pionautre='X' # recherche des positions gagnantes s'il y en a LG = coupsgagnants(pion) print "coups gagnants: ", LG # recherche des positions perdantes (=gagnantes pour l'autre!) s'il y en a LP = coupsgagnants(pionautre) print "coups perdants: ", LP # recherche des positions recommandees avec les coefficients # initialise le tableau des coefficients c=initcoef() # ajoute les pondérations des cases c=pondcoef(c) # sélectionne tous les coups possibles dans l'ordre décroissant des coefficients LC=coupscoef(c) print u"coups recommandés avant correction: ", LC # met au début de cette liste, si possible, un coup efficace LC=correction(LC,pionautre) print u"coups recommandées: ", LC # restituer le meilleur coup if len(LG)!=0: return LG[0] if len(LP)!=0: return LP[0] return LC[0] ############################################################################### def grillepleine(): global grille,imax,jmax for i in xrange(0,imax): for j in xrange(0,jmax): if grille[i][j]==' ': return False return True ############################################################################### def jeugagne(): def _jeugagne(pion): global grille x = pion + pion + pion if \ "".join(grille[0])==x or \ "".join(grille[1])==x or \ "".join(grille[2])==x or \ grille[0][0]+grille[1][0]+grille[2][0]==x or \ grille[0][1]+grille[1][1]+grille[2][1]==x or \ grille[0][2]+grille[1][2]+grille[2][2]==x or \ grille[0][0]+grille[1][1]+grille[2][2]==x or \ grille[0][2]+grille[1][1]+grille[2][0]==x: return True else: return False if _jeugagne('X'): return 'X' if _jeugagne('O'): return 'O' return '' ############################################################################### class Joueur(threading.Thread): def __init__(self, nom, num, pion, typejoueur): threading.Thread.__init__(self) self.setName(nom) # nom du joueur. Ex: "joueur1", "joueur2", ... self.num = num # numéro du joueur. Ex: 0 pour joueur1, 1 pour joueur2, etc... self.pion = pion # forme de pion affecté self.typejoueur = typejoueur # type de joueur: 0 = ordinateur, 1 = humain self.stop = False # drapeau pour stopper le thread à la demande du programme principal def run(self): # accès aux variables globales global verrou # verrou d'accès aux variables globales global okjoue # drapeau donnée par le programme principal qui permet au joueur de jouer global cdcoups # compteur de coups global premier # désigne le numéro du joueur qui a joué en premier global nbjoueurs # nombre de joueurs du jeu while not self.stop: # tant que le jeu n'est pas terminé ##### => chaque joueur attend son tour pour jouer while True: # on prend le verrou d'accès aux variables globales verrou.acquire() if self.stop: # jeu terminé. on sort de la boucle, mais en conservant le blocage du verrou break if okjoue and (cdcoups+premier)%nbjoueurs==self.num: # = ça y est, on peut jouer, mais on conserve le verrou jusqu'à la fin du coup break # on libère le verrou pour que les autres joueurs accédent aussi aux variables globales verrou.release() ##### => le joueur en cours joue if not self.stop: if self.typejoueur==0: # c'est un joueur "ordinateur" qui joue if self.pion=='X': pionautre='O' else: pionautre='X' print self.getName() + " joue ('" + self.pion + "' contre '" + pionautre + "')" self.chx = ajouer(self.pion) print self.getName() + " joue case: ",self.chx grille[self.chx[0]][self.chx[1]]=self.pion time.sleep(0.1) else: # c'est un joueur "humain" qui joue if self.pion=='X': pionautre='O' else: pionautre='X' print self.getName() + " joue ('" + self.pion + "' contre '" + pionautre + "')" self.chx = ajouer(self.pion) self.coup = raw_input(self.getName() + " joue case "+str(self.chx)+": ") if self.coup!="": self.chx=eval(self.coup) grille[self.chx[0]][self.chx[1]]=self.pion time.sleep(0.1) ##### => fin du coup du joueur en cours # le joueur repasse la main au programme principal après chaque coup okjoue = False # on libère le verrou d'accès aux variables globales verrou.release() # et fin du thread si c'est demandé (sinon, attente du prochain coup) if self.stop: break def stopper(self): self.stop = True ############################################################################### print "Bonjour! En route pour le jeu de morpion!" ############################## => initialisation du jeu et des conditions de son démarrage # nombre de joueurs nbjoueurs = 2 # type de joueurs: 0=ordinateur, 1=humain; on doit avoir: len(typejoueurs)==nbjoueurs # par défaut: tous à 0 (=ordinateur joue contre lui-même): x = raw_input("Voulez-vous jouer vous-meme? (O/N) [O]") if x=="O" or x=="o" or x=="": typejoueurs=[0,1] print "vous serez joueur2" else: typejoueurs=[0,0] # forme du pion affecté à chaque joueur. On doit avoir: len(pions)==nbjoueurs pions = ['O','X'] # # définir celui qui commence, ou définir au hasard if typejoueurs[1]==1: premier=1 x=raw_input("Voulez-vous commencer la partie (O/N) [O]? ") if not (x=='O' or x=='o' or x==''): premier=0 else: premier = random.randint(0,nbjoueurs-1) print "=====> c'est joueur"+str(premier+1)+" qui commence" ############################## => initialisation du programme # création du verrou qui permettra le monopole d'accès aux variables globales (lecture-écriture) verrou = threading.Lock() # création du "compteur de coups" initialisé à -1 parce que c'est le programme principal qui commence cdcoups = -1 # drapeau initialisé à True pour que le programme principal reprenne la main après chaque coup # (initialisé à -1 parce que c'est le programme principal qui commence) okjoue = False # creation de la liste des joueurs (NB: le joueur numéro 0 est appelé "joueur1") joueurs = [] for i in xrange(0,nbjoueurs): j = Joueur("joueur%d" % (i+1), i, pions[i], typejoueurs[i]) j.setDaemon(True) joueurs.append(j) # lancement de tous les threads des joueurs for i in xrange(0,nbjoueurs): joueurs[i].start() ############################## # surveillance du jeu et attente condition de fin de partie tps=time.time() while True: # attente qu'un joueur ait joué while True: verrou.acquire() if not okjoue: cdcoups+=1 # on incrémente le compteur de coups du coup qui vient d'être joué # on sort de la boucle, mais le verrou reste bloqué pendant la surveillance break verrou.release() # détection du départ d'un nouveau tour numéro ((cdcoups//nbjoueurs)+1) par (cdcoups%nbjoueurs==0) ch="" if cdcoups%nbjoueurs==0: print print u"=====> début du tour " + str((cdcoups//nbjoueurs)+1) # affichage de la grille for i in xrange(0,imax): print grille[i] print # voir si un gagnant gagnant = jeugagne() if gagnant!="": print "le gagnant est: " + gagnant verrou.release() break # condition de fin de jeu if grillepleine(): print "pas de gagnant!" verrou.release() break # permet au joueur suivant de jouer okjoue = True verrou.release() # et on boucle pour attendre jusqu'à ce que le joueur suivant ait joué ############################# # fin du jeu print print "fin du jeu" # arrêt de tous les threads for i in xrange(0,nbjoueurs): joueurs[i].stopper() # attente jusqu'à ce que tous les threads soient terminés for i in xrange(0,nbjoueurs): joueurs[i].join() verrou.acquire() print "fin du thread " + joueurs[i].getName() verrou.release() print u"A bientôt pour un prochain jeu!"