Séparation Logique / LogiqueEchecs et clarifications avec constantes

This commit is contained in:
Geoffrey Frogeye 2014-12-12 21:11:22 +01:00
parent 246f65993e
commit abfd04e7fc
3 changed files with 185 additions and 142 deletions

5
S1/Echecs/app.py Normal file → Executable file
View file

@ -1,5 +1,8 @@
#! /usr/bin/env python3
from logique import LogiqueEchecs
from guiTk import PlateauTk
p = PlateauTk(LogiqueEchecs())
if __name__ == '__main__':
p = PlateauTk(LogiqueEchecs())

View file

@ -15,8 +15,8 @@ class PlateauTk:
self.can = None
self.chaine = None
self.grilleDamier = []
self.imagesOriginales = []
self.imagesRedim = []
self.imagesOriginales = {}
self.imagesRedim = {}
self.photos = []
self.grillePions = []
self.animations = []
@ -58,58 +58,62 @@ class PlateauTk:
self.chaine.config(text=texte)
# TODO Timeout effacer si parametre / Liste
def nomPiece(self, piece):
tPiece = self.logique.tPiece(piece)
if tPiece == self.logique.PCE_PION:
return 'pion'
elif tPiece == self.logique.PCE_TOUR:
return 'tour'
elif tPiece == self.logique.PCE_CAVALIER:
return 'cavalier'
elif tPiece == self.logique.PCE_FOU:
return 'fou'
elif tPiece == self.logique.PCE_DAME:
return 'dame'
elif tPiece == self.logique.PCE_ROI:
return 'roi'
else:
return False
def importerImage(self, piece, couleur):
nom = 'sprites/'+self.nomPiece(piece)+couleur+'.gif'
self.imagesOriginales.update({piece:PhotoImage(file=nom)})
def importerImages(self):
for piece in range(0, 21):
nom = 'sprites/'
if piece % 10 == 1:
nom += 'pion'
elif piece % 10 == 2:
nom += 'tour'
elif piece % 10 == 3:
nom += 'cavalier'
elif piece % 10 == 4:
nom += 'fou'
elif piece % 10 == 5:
nom += 'dame'
elif piece % 10 == 6:
nom += 'roi'
else:
self.imagesOriginales.append('')
continue
if piece < 10:
nom += 'B'
else:
nom += 'N'
nom += '.gif'
self.imagesOriginales.append(PhotoImage(file=nom))
for piece in self.logique.BLANCS:
self.importerImage(piece, 'B')
for piece in self.logique.NOIRS:
self.importerImage(piece, 'N')
def redimImage(self, piece, sample):
self.imagesRedim.update({piece:self.imagesOriginales[piece].subsample(sample)})
def redimImages(self):
sample = int(504 / (PlateauTk.COTE_CASE - PlateauTk.MARGE_PIONS))
for piece in range(0, 21):
if self.imagesOriginales[piece] != '':
self.imagesRedim.append(self.imagesOriginales[piece].
subsample(sample))
else:
self.imagesRedim.append('')
for piece in self.logique.BLANCS:
self.redimImage(piece, sample)
for piece in self.logique.NOIRS:
self.redimImage(piece, sample)
# Dessin
@staticmethod
def caseCouleur(blanc, contexte):
if contexte == 1: # Sélectionné
return '#a0cefe' if blanc else '#478bd1'
elif contexte == 2: # Possible
elif contexte == 2: # Possible / Victoire
return '#bafea0' if blanc else '#6ed147'
elif contexte == 3: # Impossible
elif contexte == 3: # Impossible / Défaite
return '#fea0ab' if blanc else '#d14758'
else: # Normal
return '#ffce9e' if blanc else '#d18b47'
def cCase(self, x, y):
couleur = self.caseCouleur(not self.logique.eNoir(x, y), 0)
couleur = self.caseCouleur(self.logique.eCaseBlanche(x, y), 0)
return self.can.create_rectangle(x * PlateauTk.COTE_CASE, y * PlateauTk.COTE_CASE, (x + 1) * PlateauTk.COTE_CASE, (y + 1) * PlateauTk.COTE_CASE)
def coulCase(self, x, y, contexte):
couleur = self.caseCouleur(not self.logique.eNoir(x, y), contexte)
couleur = self.caseCouleur(self.logique.eCaseBlanche(x, y), contexte)
self.can.itemconfig(self.grilleDamier[x][y], fill=couleur, outline=couleur)
def coulDamier(self):
@ -147,12 +151,13 @@ class PlateauTk:
self.cPion(x, y, j_grilleF[x][y])
# Interaction
@staticmethod
def nomJoueur(joueur, pluriel=True):
if joueur:
def nomJoueur(self, joueur, pluriel=True):
if joueur == self.logique.BLANCS:
nom = 'blanc'
else:
elif joueur == self.logique.NOIRS:
nom = 'noir'
else:
nom = 'inconnu'
if pluriel:
nom += 's'
return nom
@ -283,7 +288,7 @@ class PlateauTk:
self.coulCase(i[0], i[1], 2)
self.statut('Poser')
self.dEtape = not self.dEtape
else: # Si pas pssible jouer
else: # Si pas possible de jouer
self.coulCase(self.dx1, self.dy1, 3)
self.animerC(self.dx1, self.dy1)
else: # Poser

View file

@ -1,9 +1,75 @@
import copy
class LogiqueEchecs:
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'
@ -20,94 +86,65 @@ class LogiqueEchecs:
self.grille = []
self.cGrille()
self.remplirGrille()
self.joueur = True
self.joueur = self.BLANC
self.partieFinie = False
self.victorieux = None
@staticmethod
def eNoir(xD, yD):
return xD % 2 != yD % 2
def cGrille(self):
for x in range(LogiqueEchecs.CASES_COTE):
colonne = []
for y in range(LogiqueEchecs.CASES_COTE):
colonne.append(0)
self.grille.append(colonne)
def remplirGrille(self):
speciales = [2, 3, 4, 6, 5, 4, 3, 2]
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] = speciales[i] + 10
self.grille[i][1] = 11
self.grille[i][6] = 1
self.grille[i][7] = speciales[i]
def cPion(self, x, y, piece):
"""
"""
self.grille[x][y] = piece
return True
@staticmethod
def ePionBlanc(pion):
return pion in range(1, 7)
@staticmethod
def ePionNoir(pion):
return pion in range(11, 17)
def aSonTour(self, pion):
return (self.ePionNoir(pion) and self.joueur == False) or \
(self.ePionBlanc(pion) and self.joueur == True)
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 LogiqueEchecs.MVT_OK
return self.MVT_OK
elif y1 == 6 and y2 == 4 and self.grille[x1][5] == 0:
return LogiqueEchecs.MVT_OK
return self.MVT_OK
else:
return LogiqueEchecs.MVT_N_AUTORISE
return self.MVT_N_AUTORISE
else:
if y2 == y1 + 1:
return LogiqueEchecs.MVT_OK
return self.MVT_OK
elif y1 == 1 and y2 == 3 and self.grille[x1][2] == 0:
return LogiqueEchecs.MVT_OK
return self.MVT_OK
else:
return LogiqueEchecs.MVT_N_AUTORISE
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 LogiqueEchecs.MVT_OK
return self.MVT_OK
else:
return LogiqueEchecs.MVT_N_AUTORISE
return self.MVT_N_AUTORISE
else:
if y2 == y1 + 1 and \
self.ePionBlanc(self.grille[x2][y2]):
return LogiqueEchecs.MVT_OK
return self.MVT_OK
else:
return LogiqueEchecs.MVT_N_AUTORISE
return self.MVT_N_AUTORISE
else:
return LogiqueEchecs.MVT_N_AUTORISE
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.grille[x][y1] > 0:
return LogiqueEchecs.MVT_OBSTRUCTION
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.grille[x1][y] > 0:
return LogiqueEchecs.MVT_OBSTRUCTION
if self.ePiece(self.grille[x1][y]):
return self.MVT_OBSTRUCTION
else:
return LogiqueEchecs.MVT_N_AUTORISE
return LogiqueEchecs.MVT_OK
return self.MVT_N_AUTORISE
return self.MVT_OK
def mvtPossibleSansEchecFou(self, x1, y1, x2, y2):
if abs(x2-x1) == abs(y2-y1):
@ -121,77 +158,75 @@ class LogiqueEchecs:
dist += 1
x += sensX
y += sensY
if self.grille[x][y] > 0:
if self.ePiece(self.grille[x][y]):
if dist == distTot:
return LogiqueEchecs.MVT_OK # Saut
return self.MVT_OK # Saut
else:
return LogiqueEchecs.MVT_OBSTRUCTION
return LogiqueEchecs.MVT_OK # Vide
return self.MVT_OBSTRUCTION
return self.MVT_OK # Vide
else:
return LogiqueEchecs.MVT_N_AUTORISE
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 LogiqueEchecs.MVT_OK
return self.MVT_OK
else:
return LogiqueEchecs.MVT_N_AUTORISE
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 = pion % 10
if tPion == 1: # Pion
tPion = self.tPiece(pion)
if tPion == self.PCE_PION: # Pion
return self.mvtPossibleSansEchecPion(x1, y1, x2, y2)
elif tPion == 2: # Tour
elif tPion == self.PCE_TOUR: # Tour
return self.mvtPossibleSansEchecTour(x1, y1, x2, y2)
elif tPion == 3: # Cavalier
elif tPion == self.PCE_CAVALIER:
return self.mvtPossibleSansEchecCavalier(x1, y1, x2, y2)
elif tPion == 4: # Fou
elif tPion == self.PCE_FOU:
return self.mvtPossibleSansEchecFou(x1, y1, x2, y2)
elif tPion == 5: # Dame
elif tPion == self.PCE_DAME:
tour = self.mvtPossibleSansEchecTour(x1, y1, x2, y2)
fou = self.mvtPossibleSansEchecFou(x1, y1, x2, y2)
if tour == LogiqueEchecs.MVT_OK or fou == LogiqueEchecs.MVT_OK:
return LogiqueEchecs.MVT_OK
elif tour == LogiqueEchecs.MVT_OBSTRUCTION or fou == LogiqueEchecs.MVT_OBSTRUCTION:
return LogiqueEchecs.MVT_OBSTRUCTION
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 LogiqueEchecs.MVT_N_AUTORISE
elif tPion == 6: # Roi
return self.MVT_N_AUTORISE
elif tPion == self.PCE_ROI:
if abs(x2-x1) <= 1 and abs(y2-y1) <= 1:
return LogiqueEchecs.MVT_OK
return self.MVT_OK
else:
return LogiqueEchecs.MVT_N_AUTORISE
return self.MVT_N_AUTORISE
else:
return LogiqueEchecs.MVT_PION_INC
return self.MVT_PION_INC
else:
return LogiqueEchecs.MVT_SAUT_AMI
return self.MVT_SAUT_AMI
else:
return LogiqueEchecs.MVT_SUR_PLACE
return self.MVT_SUR_PLACE
else:
return LogiqueEchecs.MVT_SELECTION
return LogiqueEchecs.MVT_INCONNU
return self.MVT_SELECTION
return self.MVT_INCONNU
def mvtPossible(self, x1, y1, x2, y2):
test = self.mvtPossibleSansEchec(x1, y1, x2, y2)
if test == LogiqueEchecs.MVT_OK:
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 = 6
if not self.joueur:
pionRoi += 10
pionRoi = self.PCE_ROI + self.DECALAGE_BLANCS if self.joueur else self.DECALAGE_NOIRS
roi = [-1, -1]
for x in range(0, LogiqueEchecs.CASES_COTE):
for y in range(0, LogiqueEchecs.CASES_COTE):
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 LogiqueEchecs.MVT_ECHEC
return self.MVT_ECHEC
else:
return test
else:
@ -199,33 +234,33 @@ class LogiqueEchecs:
def mvtsPossiblesSansEchec(self, x1, y1):
tableau = []
for x2 in range(0, LogiqueEchecs.CASES_COTE):
for y2 in range(0, LogiqueEchecs.CASES_COTE):
if self.mvtPossibleSansEchec(x1, y1, x2, y2) == LogiqueEchecs.MVT_OK:
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, LogiqueEchecs.CASES_COTE):
for y2 in range(0, LogiqueEchecs.CASES_COTE):
if self.mvtPossible(x1, y1, x2, y2) == LogiqueEchecs.MVT_OK:
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 == LogiqueEchecs.MVT_OK:
self.grille[x1][y1], self.grille[x2][y2] = 0, self.grille[x1][y1]
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.
(CÀD Le joueur actuel ne peut effectuer aucun mouvement)
(Ici vrai en cas de "pat")
"""
for x in range(0, LogiqueEchecs.CASES_COTE):
for y in range(0, LogiqueEchecs.CASES_COTE):
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
@ -240,12 +275,12 @@ class LogiqueEchecs:
'deplacer': [], # Pions à déplacer
'supprimer': [], # Pions à supprimer
}
if test == LogiqueEchecs.MVT_OK:
if test == self.MVT_OK:
retour['valide'] = True
if self.grille[x2][y2] > 0:
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] = 0, self.grille[x1][y1]
self.grille[x1][y1], self.grille[x2][y2] = self.PCE_VIDE, self.grille[x1][y1]
self.joueur = not self.joueur
self.vEchecMat()
return retour