Puissance 4
1. Fonction utilitaires
1.1. Jouer un coup
def jouer_coup(state, col): assert 0 <= col < 7 and state["libres"][col] > 0 state["grille"][state["libres"][col]-1][col] = state["joueur"] state["joueur"] = 3 - state["joueur"] state["vides"] -= 1 state["libres"][col] -= 1
1.2. Annuler coup
def annuler_coup(state, col): state["grille"][state["libres"][col]][col] = 0 state["joueur"] = 3 - state["joueur"] state["vides"] += 1 state["libres"][col] += 1
1.3. Coup Gagnant
def coup_gagnant(state, col): g = state["grille"] jo = 3-state["joueur"] i, j = state["libres"][col], col # On parcourt les 7 cases encadrant i,j dans chaque direction # Le choix de la direction se fait par le choix du vecteur directeur for i_dir, j_dir in [(0,1), (1,0), (1,1), (1,-1)]: nb_cons = 0 # Nb de jeton consécutifs for d in range(-3,4): if (0 <= i+d*i_dir < 6 and 0 <= j+d*j_dir < 7 and g[i+d*i_dir][j+d*j_dir] == jo): nb_cons += 1 # Gagnant if nb_cons == 4: return True else: nb_cons = 0 return False
2. Stratégies
2.1. Stratégie aléatoire
import random as rd def strategie_alea(state): assert state["vides"] > 0 li = state["libres"] i_libres = [] for i in range(len(li)): if li[i] > 0: i_libres.append(i) return rd.choice(i_libres)
2.2. Partie
def partie(stratR, stratJ): state = {"grille": [ [0]*7 for i in range(6) ], "joueur": 1, "libres": [6]*7, "vides": 6*7 } strats = (stratR, stratJ) while state["vides"] > 0: st = strats[state["joueur"]-1] coup = st(state) jouer_coup(state, coup) if coup_gagnant(state, coup): return 3-state["joueur"] return 0
score = [0,0,0] for i in range(10000): score[partie(strategie_alea, strategie_alea)] += 1 rouge = score[1] / 100
2.3. Heuristique
def h(state): score = 0 gr = state["grille"] for i in range(6): for j in range(7): # la formule envoie (0,1,2) sur (0,1,-1) score += points[i][j] * (gr[i][j] % 2 - gr[i][j] // 2) return score
2.4. MinMax
def imin(l): i_min = 0 m = l[0] for i in range(1, len(l)): if m > l[i]: m = l[i] i_min = i return i_min, m
def imax(l): i_max = 0 m = l[0] for i in range(1, len(l)): if m < l[i]: m = l[i] i_max = i return i_max, m
def minmax(h, p, state): if p == 0: return None, h(state) if state["vides"] == 0: return None, 0 li = state["libres"] i_libres = [] for i in range(len(li)): if li[i] > 0: i_libres.append(i) if state["joueur"] == 1: scores = [] for coup in i_libres: jouer_coup(state, coup) if coup_gagnant(state, coup): scores.append(float("inf")) else: scores.append(minmax(h, p-1, state)[1]) annuler_coup(state, coup) i_coup, s = imax(scores) return i_libres[i_coup], s else: scores = [] for coup in i_libres: jouer_coup(state, coup) if coup_gagnant(state, coup): scores.append(-float("inf")) else: scores.append(minmax(h, p-1, state)[1]) annuler_coup(state, coup) i_coup, s = imin(scores) return i_libres[i_coup], s def strategie_minmax(h, p, state): coup = minmax(h, p, state) return coup[0]
score = [0,0,0] for i in range(50): score[partie(strategie_minmax_5, strategie_alea)] += 1 egalite = score[0] / 100
3. Intéraction
3.1. Interaction Joueur
def afficher_grille(state): gr = state["grille"] for i in range(6): s = "" for j in range(7): if gr[i][j] == 0 : s += ". " elif gr[i][j] == 1 : s += "X " else: s += "O " print(s) print("_____________") print("0 1 2 3 4 5 6") def strategie_input(state): afficher_grille(state) col = -1 while not (0 <= col < 7 and state["libres"][col] > 0): col = int(input("Colonne de jeux (0 à 6): ")) return col
Pour une meilleure experience visuelle on peut redéfinir la fonction partie
pour afficher quelques informations supplémentaires dans le jeu.
def partie(stratR, stratJ): state = {"grille": [ [0]*7 for i in range(6) ], "joueur": 1, "libres": [6]*7, "vides": 6*7 } strats = (stratR, stratJ) while state["vides"] > 0: st = strats[state["joueur"]-1] coup = st(state) if state["joueur"] == 2: print("L'IA joue ", coup) jouer_coup(state, coup) if coup_gagnant(state, coup): afficher_grille(state) print("Le joueur ", 3-state["joueur"], "a gagné.") return return 0 def play(): partie(strategie_input, strategie_minmax_5)