import copy class Logique: """ Logique des jeux sur damier """ PCE_VIDE = 0 BLANC = True NOIR = False @staticmethod def eCaseBlanche(xD, yD): return xD % 2 == yD % 2 def cGrille(self): for x in range(self.CASES_COTE): colonne = [] for y in range(self.CASES_COTE): colonne.append(self.PCE_VIDE) self.grille.append(colonne) def cPion(self, x, y, piece): self.grille[x][y] = piece return True def ePionBlanc(self, pion): return pion in self.BLANCS def ePionNoir(self, pion): return pion in self.NOIRS def ePiece(self, piece): # return piece != self.PCE_VIDE return self.ePionBlanc(piece) or self.ePionNoir(piece) def tPiece(self, piece): if self.ePionBlanc(piece): return piece - self.DECALAGE_BLANCS elif self.ePionNoir(piece): return piece - self.DECALAGE_NOIRS else: return self.PCE_VIDE def aSonTour(self, pion): return (self.ePionNoir(pion) and self.joueur == self.NOIR) or \ (self.ePionBlanc(pion) and self.joueur == self.BLANC) class LogiqueEchecs(Logique): """ Logique du jeu d'Échecs """ CASES_COTE = 8 # Pièces PCE_PION = 1 PCE_TOUR = 2 PCE_CAVALIER = 3 PCE_FOU = 4 PCE_DAME = 5 PCE_ROI = 6 DECALAGE_BLANCS = 0 DECALAGE_NOIRS = 10 BLANCS = range(DECALAGE_BLANCS+PCE_PION, DECALAGE_BLANCS+PCE_ROI+1) NOIRS = range(DECALAGE_NOIRS+PCE_PION, DECALAGE_NOIRS+PCE_ROI+1) # Codes du mouvement MVT_INCONNU = 'Cause inconnue' MVT_OK = 'Valide' MVT_ROQUE = 'Roque' MVT_SELECTION = 'Mauvais tour' MVT_SUR_PLACE = 'Immobile' MVT_SAUT_AMI = 'Saut ami' MVT_PION_INC = 'Pion inconnu' MVT_N_AUTORISE = 'Non-autorisé' MVT_OBSTRUCTION = 'Pion en chemin' MVT_ECHEC = 'Échec au roi' def __init__(self): self.grille = [] self.cGrille() self.remplirGrille() self.joueur = self.BLANC self.partieFinie = False self.victorieux = None def remplirGrille(self): speciales = [self.PCE_TOUR, self.PCE_CAVALIER, self.PCE_FOU, self.PCE_ROI, self.PCE_DAME] speciales += speciales[4::-1] for i in range(0, 8): self.grille[i][0] = self.DECALAGE_NOIRS + speciales[i] self.grille[i][1] = self.DECALAGE_NOIRS + self.PCE_PION self.grille[i][6] = self.DECALAGE_BLANCS + self.PCE_PION self.grille[i][7] = self.DECALAGE_BLANCS + speciales[i] def mvtPossibleSansEchecPion(self, x1, y1, x2, y2): if x1 == x2 and self.grille[x2][y2] <= 0: # Avance if self.joueur: if y2 == y1 - 1: return self.MVT_OK elif y1 == 6 and y2 == 4 and self.grille[x1][5] == 0: return self.MVT_OK else: return self.MVT_N_AUTORISE else: if y2 == y1 + 1: return self.MVT_OK elif y1 == 1 and y2 == 3 and self.grille[x1][2] == 0: return self.MVT_OK else: return self.MVT_N_AUTORISE elif abs(x1-x2) == 1: # Saut if self.joueur: if y2 == y1 - 1 and \ self.ePionNoir(self.grille[x2][y2]): return self.MVT_OK else: return self.MVT_N_AUTORISE else: if y2 == y1 + 1 and \ self.ePionBlanc(self.grille[x2][y2]): return self.MVT_OK else: return self.MVT_N_AUTORISE else: return self.MVT_N_AUTORISE def mvtPossibleSansEchecTour(self, x1, y1, x2, y2): if y1 == y2: sens = (x2-x1)//abs(x2-x1) for x in range(x1+sens, x2, sens): if self.ePiece(self.grille[x][y1]): return self.MVT_OBSTRUCTION elif x1 == x2: sens = (y2-y1)//abs(y2-y1) for y in range(y1+sens, y2, sens): if self.ePiece(self.grille[x1][y]): return self.MVT_OBSTRUCTION else: return self.MVT_N_AUTORISE return self.MVT_OK def mvtPossibleSansEchecFou(self, x1, y1, x2, y2): if abs(x2-x1) == abs(y2-y1): sensX = (x2-x1)//abs(x2-x1) sensY = (y2-y1)//abs(y2-y1) x = x1 y = y1 dist = 0 distTot = abs(x2-x1) while dist < distTot: dist += 1 x += sensX y += sensY if self.ePiece(self.grille[x][y]): if dist == distTot: return self.MVT_OK # Saut else: return self.MVT_OBSTRUCTION return self.MVT_OK # Vide else: return self.MVT_N_AUTORISE def mvtPossibleSansEchecCavalier(self, x1, y1, x2, y2): if (abs(x2-x1) == 2 and abs(y2-y1) == 1) or (abs(y2-y1) == 2 and abs(x2-x1) == 1): return self.MVT_OK else: return self.MVT_N_AUTORISE def mvtPossibleSansEchec(self, x1, y1, x2, y2): pion = self.grille[x1][y1] if self.aSonTour(pion): if (x1 != x2 or y1 != y2): if not self.aSonTour(self.grille[x2][y2]): tPion = self.tPiece(pion) if tPion == self.PCE_PION: # Pion return self.mvtPossibleSansEchecPion(x1, y1, x2, y2) elif tPion == self.PCE_TOUR: # Tour return self.mvtPossibleSansEchecTour(x1, y1, x2, y2) elif tPion == self.PCE_CAVALIER: return self.mvtPossibleSansEchecCavalier(x1, y1, x2, y2) elif tPion == self.PCE_FOU: return self.mvtPossibleSansEchecFou(x1, y1, x2, y2) elif tPion == self.PCE_DAME: tour = self.mvtPossibleSansEchecTour(x1, y1, x2, y2) fou = self.mvtPossibleSansEchecFou(x1, y1, x2, y2) if tour == self.MVT_OK or fou == self.MVT_OK: return self.MVT_OK elif tour == self.MVT_OBSTRUCTION or fou == self.MVT_OBSTRUCTION: return self.MVT_OBSTRUCTION else: return self.MVT_N_AUTORISE elif tPion == self.PCE_ROI: if abs(x2-x1) <= 1 and abs(y2-y1) <= 1: return self.MVT_OK else: return self.MVT_N_AUTORISE else: return self.MVT_PION_INC else: return self.MVT_SAUT_AMI else: return self.MVT_SUR_PLACE else: return self.MVT_SELECTION return self.MVT_INCONNU def mvtPossible(self, x1, y1, x2, y2): test = self.mvtPossibleSansEchec(x1, y1, x2, y2) if test == self.MVT_OK: # On copie la partie actuelle pour tester le mouvement et vérifier l'échec copie = copy.deepcopy(self); copie.dPionSansEchec(x1, y1, x2, y2) mvtsPossiblesTousAdverses = [] pionRoi = self.PCE_ROI + self.DECALAGE_BLANCS if self.joueur else self.DECALAGE_NOIRS roi = [-1, -1] for x in range(0, self.CASES_COTE): for y in range(0, self.CASES_COTE): mvtsPossiblesTousAdverses += copie.mvtsPossiblesSansEchec(x, y) if copie.grille[x][y] == pionRoi: roi = [x, y] if roi in mvtsPossiblesTousAdverses: return self.MVT_ECHEC else: return test else: return test def mvtsPossiblesSansEchec(self, x1, y1): tableau = [] for x2 in range(0, self.CASES_COTE): for y2 in range(0, self.CASES_COTE): if self.mvtPossibleSansEchec(x1, y1, x2, y2) == self.MVT_OK: tableau.append([x2, y2]) return tableau def mvtsPossibles(self, x1, y1): tableau = [] for x2 in range(0, self.CASES_COTE): for y2 in range(0, self.CASES_COTE): if self.mvtPossible(x1, y1, x2, y2) == self.MVT_OK: tableau.append([x2, y2]) return tableau def dPionSansEchec(self, x1, y1, x2, y2): test = self.mvtPossibleSansEchec(x1, y1, x2, y2) if test == self.MVT_OK: self.grille[x1][y1], self.grille[x2][y2] = self.PCE_VIDE, self.grille[x1][y1] self.joueur = not self.joueur def vEchecMat(self): """ Vérifie si le joueur actuel est en échec et mat et prend les mesures nécessiares. (Ici vrai en cas de "pat") """ for x in range(0, self.CASES_COTE): for y in range(0, self.CASES_COTE): if len(self.mvtsPossibles(x, y)) > 0: return False self.partieFinie = True self.victorieux = not self.joueur return True def dPion(self, x1, y1, x2, y2): test = self.mvtPossible(x1, y1, x2, y2) retour = { 'valide': False, 'message': test, 'deplacer': [], # Pions à déplacer 'supprimer': [], # Pions à supprimer } if test == self.MVT_OK: retour['valide'] = True if self.ePiece(self.grille[x2][y2]): retour['supprimer'].append([x2, y2]) retour['deplacer'].append([x1, y1, x2, y2]) self.grille[x1][y1], self.grille[x2][y2] = self.PCE_VIDE, self.grille[x1][y1] self.joueur = not self.joueur self.vEchecMat() return retour