[Echecs] Redevenu ami avec PyLint

This commit is contained in:
Geoffrey Frogeye 2014-12-14 17:44:45 +01:00
parent a38bf44a9b
commit ab48ed3e69
2 changed files with 194 additions and 136 deletions

View file

@ -1,42 +1,51 @@
from tkinter import * from tkinter import *
from logique import LogiqueEchecs from logique import LogiqueEchecs
class PlateauTk: class PlateauTk:
""" """
Plateau de jeu de damier en canvas Tk Plateau de jeu de damier en canvas Tk
""" """
RATIO_PCE_CASE = .95 # Place que prend la pièce sur la case RATIO_PCE_CASE = .95 # Place que prend la pièce sur la case
TEMPS_ANIM = 200 # Temps en ms d'une animation TEMPS_ANIM = 200 # Temps en ms d'une animation
INTER_ANIM = 10 # Temps en ms entre deux actualisations d'animation INTER_ANIM = 10 # Temps en ms entre deux actualisations d'animation
COTE_TOUT_DEFAUT = 500 # Coté par défaut du plateau COTE_TOUT_DEFAUT = 500 # Coté par défaut du plateau
def __init__(self, fen, can, statut, logique): def __init__(self, fen, can, statut, logique):
""" """
Constructeur de PlateauTk Constructeur de PlateauTk
""" """
self.can = can # Canvas self.can = can # Canvas
self.fen = fen # Fenêtre Tk (nécessaire pour lancer un timeout pour l'animation) # Fenêtre Tk (nécessaire pour lancer un timeout pour l'animation)
self.statut = statut # Fonction qui envoie un message à l'utilisateur self.fen = fen
self.grilleDamier = [] # Tableau contenant les références aux cases du damier self.statut = statut # Fonction qui envoie un message à l'utilisateur
self.grillePieces = [] # Tableau contenant les références aux pièces # Tableau contenant les références aux cases du damier
self.photos = [] # Liste contenant les différentes photos utilisées (afin qu'elles ne soient pas recyclées) self.grilleDamier = []
self.imagesOriginales = {} # Dictionnaire associant chaque pièce à son image originale self.grillePieces = [] # Tableau contenant les références aux pièces
self.imagesRedim = {} # Dictionnaire associant chaque pièce à son image redimensionnée self.photos = [] # Liste contenant les différentes photos utilisées
self.animations = [] # Liste contenant les animations en cours # (afin qu'elles ne soient pas recyclées)
# Dictionnaire associant chaque pièce à son image originale
self.imagesOriginales = {}
# Dictionnaire associant chaque pièce à son image redimensionnée
self.imagesRedim = {}
self.animations = [] # Liste contenant les animations en cours
self.dEtape = True # Étape du déplacement (True : prendre la pièce, False : poser la pièce) # Étape du déplacement (True : prendre la pièce, False : poser la
self.dx1 = -1 # Coordonnées X de la pièce sélectionnée # pièce)
self.dy1 = -1 # Coordonnées Y de la pièce sélectionnée self.dEtape = True
self.dx2 = -1 # Coordonnées X de la destination self.dx1 = -1 # Coordonnées X de la pièce sélectionnée
self.dy2 = -1 # Coordonnées Y de la destination self.dy1 = -1 # Coordonnées Y de la pièce sélectionnée
self.mvtsPossibles = [] # Liste des mouvements possibles pour la pièce sélectionnée self.dx2 = -1 # Coordonnées X de la destination
self.coteCase = 0 # Coté d'une case self.dy2 = -1 # Coordonnées Y de la destination
# Liste des mouvements possibles pour la pièce sélectionnée
self.mvtsPossibles = []
self.coteCase = 0 # Coté d'une case
self.logique = logique # Logique du jeu self.logique = logique # Logique du jeu
self.importerImages() self.importerImages()
self.redimCan(self.COTE_TOUT_DEFAUT) self.redimCan(self.COTE_TOUT_DEFAUT)
@ -59,33 +68,34 @@ class PlateauTk:
self.cGrille() self.cGrille()
self.remplirGrille() self.remplirGrille()
def nomPiece(self, tPiece):
def nomPiece(self, piece):
""" """
Renvoi le nom de fichier de la pièce donnée Renvoi le nom de fichier de la pièce donnée
""" """
tPiece = self.logique.tPiece(piece)
if tPiece == self.logique.PCE_PION: if tPiece == self.logique.PCE_PION:
return 'pion' nom = 'pion'
elif tPiece == self.logique.PCE_TOUR: elif tPiece == self.logique.PCE_TOUR:
return 'tour' nom = 'tour'
elif tPiece == self.logique.PCE_CAVALIER: elif tPiece == self.logique.PCE_CAVALIER:
return 'cavalier' nom = 'cavalier'
elif tPiece == self.logique.PCE_FOU: elif tPiece == self.logique.PCE_FOU:
return 'fou' nom = 'fou'
elif tPiece == self.logique.PCE_DAME: elif tPiece == self.logique.PCE_DAME:
return 'dame' nom = 'dame'
elif tPiece == self.logique.PCE_ROI: elif tPiece == self.logique.PCE_ROI:
return 'roi' nom = 'roi'
else: else:
return False return False
return nom
def importerImage(self, piece, couleur): # TODO piece stocke déjà la couleur # TODO piece stocke déjà la couleur
def importerImage(self, piece, couleur):
""" """
Importe l'image de la pièce donnée Importe l'image de la pièce donnée
""" """
nom = 'sprites/'+self.nomPiece(piece)+couleur+'.gif' nom = 'sprites/' + \
self.imagesOriginales.update({piece:PhotoImage(file=nom)}) self.nomPiece(self.logique.tPiece(piece)) + couleur + '.gif'
self.imagesOriginales.update({piece: PhotoImage(file=nom)})
def importerImages(self): def importerImages(self):
""" """
@ -100,13 +110,15 @@ class PlateauTk:
""" """
Redimensionne l'image de la pièce donnée Redimensionne l'image de la pièce donnée
""" """
self.imagesRedim.update({piece:self.imagesOriginales[piece].subsample(sample)}) self.imagesRedim.update(
{piece: self.imagesOriginales[piece].subsample(sample)})
def redimImages(self): def redimImages(self):
""" """
Redimensionne l'image des pièces du jeu Redimensionne l'image des pièces du jeu
""" """
sample = int(504 // (self.coteCase * self.RATIO_PCE_CASE)) # TODO S'en sort pour être toujours plus grand sample = int(504 // (self.coteCase * self.RATIO_PCE_CASE)
) # TODO S'en sort pour être toujours plus grand
for piece in self.logique.BLANCS: for piece in self.logique.BLANCS:
self.redimImage(piece, sample) self.redimImage(piece, sample)
for piece in self.logique.NOIRS: for piece in self.logique.NOIRS:
@ -118,28 +130,29 @@ class PlateauTk:
""" """
Retourne la couleur hexadécimale de la case de couleur et de contexte donnée Retourne la couleur hexadécimale de la case de couleur et de contexte donnée
""" """
if contexte == 1: # Sélectionné if contexte == 1: # Sélectionné
return '#a0cefe' if blanc else '#478bd1' return '#a0cefe' if blanc else '#478bd1'
elif contexte == 2: # Possible / Victoire elif contexte == 2: # Possible / Victoire
return '#bafea0' if blanc else '#6ed147' return '#bafea0' if blanc else '#6ed147'
elif contexte == 3: # Impossible / Défaite elif contexte == 3: # Impossible / Défaite
return '#fea0ab' if blanc else '#d14758' return '#fea0ab' if blanc else '#d14758'
else: # Normal else: # Normal
return '#ffce9e' if blanc else '#d18b47' return '#ffce9e' if blanc else '#d18b47'
def cCase(self, x, y): def cCase(self, x, y):
""" """
Crée la case aux coordonnées données Crée la case aux coordonnées données
""" """
couleur = self.caseCouleur(self.logique.eCaseBlanche(x, y), 0) return self.can.create_rectangle(x * self.coteCase, y * self.coteCase,
return self.can.create_rectangle(x * self.coteCase, y * self.coteCase, (x + 1) * self.coteCase, (y + 1) * self.coteCase) (x + 1) * self.coteCase, (y + 1) * self.coteCase)
def coulCase(self, x, y, contexte=0): def coulCase(self, x, y, contexte=0):
""" """
Colorie la case aux coordonnées données selon le contexte donné Colorie la case aux coordonnées données selon le contexte donné
""" """
couleur = self.caseCouleur(self.logique.eCaseBlanche(x, y), contexte) couleur = self.caseCouleur(self.logique.eCaseBlanche(x, y), contexte)
self.can.itemconfig(self.grilleDamier[x][y], fill=couleur, outline=couleur) self.can.itemconfig(
self.grilleDamier[x][y], fill=couleur, outline=couleur)
def coulDamier(self, contexte=0): def coulDamier(self, contexte=0):
""" """
@ -154,7 +167,7 @@ class PlateauTk:
Génère le damier Génère le damier
""" """
self.grilleDamier = [] self.grilleDamier = []
for x in range(0, self.logique.CASES_COTE): # TODO Peut être amélioré for x in range(0, self.logique.CASES_COTE): # TODO Peut être amélioré
colonne = [] colonne = []
for y in range(0, self.logique.CASES_COTE): for y in range(0, self.logique.CASES_COTE):
colonne.append(self.cCase(x, y)) colonne.append(self.cCase(x, y))
@ -166,7 +179,8 @@ class PlateauTk:
Crée la pièce aux coordonnées données Crée la pièce aux coordonnées données
""" """
if self.logique.ePiece(piece): if self.logique.ePiece(piece):
self.grillePieces[x][y] = self.can.create_image((x + .5) * self.coteCase, (y + .5) * self.coteCase, image=self.imagesRedim[piece]) self.grillePieces[x][y] = self.can.create_image((x + .5) * self.coteCase,
(y + .5) * self.coteCase, image=self.imagesRedim[piece])
else: else:
self.grillePieces[x][y] = False self.grillePieces[x][y] = False
@ -208,7 +222,8 @@ class PlateauTk:
""" """
Change le statut indiquant au joueur en cours de jouer. Change le statut indiquant au joueur en cours de jouer.
""" """
self.statut('Aux ' + self.nomJoueur(self.logique.joueur, pluriel=True) + ' de sélectionner une pièce.') self.statut('Aux ' + self.nomJoueur(self.logique.joueur, pluriel=True) +
' de sélectionner une pièce.')
@staticmethod @staticmethod
def animationDCoords(i): def animationDCoords(i):
@ -216,8 +231,8 @@ class PlateauTk:
Retourne les coordonnées auxquelles doit se placer une pièce en cours d'animation Retourne les coordonnées auxquelles doit se placer une pièce en cours d'animation
""" """
# TODO Faire autre chose qu'une animation linéaire constante # TODO Faire autre chose qu'une animation linéaire constante
x = i['x1'] + (i['x2']-i['x1']) * (i['avancement']/i['total']) x = i['x1'] + (i['x2'] - i['x1']) * (i['avancement'] / i['total'])
y = i['y1'] + (i['y2']-i['y1']) * (i['avancement']/i['total']) y = i['y1'] + (i['y2'] - i['y1']) * (i['avancement'] / i['total'])
return [x, y] return [x, y]
def animation(self): def animation(self):
@ -245,7 +260,8 @@ class PlateauTk:
self.coulCase(i['x'], i['y'], 0) self.coulCase(i['x'], i['y'], 0)
self.animations = animationsNv self.animations = animationsNv
if len(animationsNv): # Si il y aura encore des animations à faire if len(animationsNv): # Si il y aura encore des animations à faire
self.fen.after(self.INTER_ANIM, self.animation) # On prévoit une image (boucle) # On prévoit une image (boucle)
self.fen.after(self.INTER_ANIM, self.animation)
def animer(self, animation): def animer(self, animation):
""" """
@ -264,9 +280,10 @@ class PlateauTk:
if len(self.animations): if len(self.animations):
for i in self.animations: for i in self.animations:
if i['type'] == 'd' and i['piece'] == piece: if i['type'] == 'd' and i['piece'] == piece:
# Si une animation pour cette pièce existe déjà, on la reprend et on la modifie # Si une animation pour cette pièce existe déjà, on la
# reprend et on la modifie
coords = self.animationDCoords(i) coords = self.animationDCoords(i)
i['x1'] = coords[0] # TODO Simplifier avec update() i['x1'] = coords[0] # TODO Simplifier avec update()
i['y1'] = coords[1] i['y1'] = coords[1]
i['x2'] = x2 i['x2'] = x2
i['y2'] = y2 i['y2'] = y2
@ -285,7 +302,7 @@ class PlateauTk:
'total': self.TEMPS_ANIM, 'total': self.TEMPS_ANIM,
'avancement': 0 'avancement': 0
} }
self.can.tag_raise(piece) # Mise au premier plan self.can.tag_raise(piece) # Mise au premier plan
self.animer(animation) self.animer(animation)
def animerF(self, piece): def animerF(self, piece):
@ -300,7 +317,7 @@ class PlateauTk:
} }
self.animer(animation) self.animer(animation)
def animerC(self, x ,y): def animerC(self, x, y):
""" """
Ajoute une animation pour l'effacement de la surbrillance d'une case Ajoute une animation pour l'effacement de la surbrillance d'une case
""" """
@ -317,12 +334,13 @@ class PlateauTk:
""" """
Indique à l'utilisateur la victoire et décore le plateau pour l'occasion Indique à l'utilisateur la victoire et décore le plateau pour l'occasion
""" """
self.statut('Victoire des ' + self.nomJoueur(self.logique.victorieux) + ' !') self.statut(
'Victoire des ' + self.nomJoueur(self.logique.victorieux) + ' !')
self.coulDamier() self.coulDamier()
for x in range(0, self.logique.CASES_COTE): for x in range(0, self.logique.CASES_COTE):
for y in range(0, self.logique.CASES_COTE): for y in range(0, self.logique.CASES_COTE):
piece = self.logique.grille[x][y] piece = self.logique.grille[x][y]
if self.logique.ePiece(piece): if self.logique.ePiece(piece):
if self.logique.ePieceNoir(piece) ^ self.logique.victorieux: if self.logique.ePieceNoir(piece) ^ self.logique.victorieux:
self.coulCase(x, y, 2) self.coulCase(x, y, 2)
else: else:
@ -334,16 +352,16 @@ class PlateauTk:
(Vérifie la possibilité du mouvement et crée les animations nécessaires) (Vérifie la possibilité du mouvement et crée les animations nécessaires)
""" """
test = self.logique.dPiece(x1, y1, x2, y2) test = self.logique.dPiece(x1, y1, x2, y2)
if test['valide'] == True: # Si déplacement possible if test['valide'] == True: # Si déplacement possible
for s in test['supprimer']: for s in test['supprimer']:
self.animerF(self.grillePieces[s[0]][s[1]]) self.animerF(self.grillePieces[s[0]][s[1]])
for d in test['deplacer']: for d in test['deplacer']:
self.grillePieces[d[2]][d[3]], self.grillePieces[d[0]][d[1]] = \ self.grillePieces[d[2]][d[3]], self.grillePieces[d[0]][d[1]] = \
self.grillePieces[d[0]][d[1]], False self.grillePieces[d[0]][d[1]], False
self.animerD((d[0] + .5) * self.coteCase, (d[1] + .5) * self.coteCase, \ self.animerD((d[0] + .5) * self.coteCase, (d[1] + .5) * self.coteCase,
(d[2] + .5) * self.coteCase, (d[3] + .5) * self.coteCase, \ (d[2] + .5) *
self.grillePieces[d[2]][d[3]]) self.coteCase, (d[3] + .5) * self.coteCase,
self.grillePieces[d[2]][d[3]])
else: else:
self.statut('Déplacment invalide ! (' + test['message'] + ')') self.statut('Déplacment invalide ! (' + test['message'] + ')')
return test['valide'] return test['valide']
@ -353,29 +371,34 @@ class PlateauTk:
Réagit en fonction d'un clic sur une case aux coordonnées données Réagit en fonction d'un clic sur une case aux coordonnées données
""" """
if not self.logique.partieFinie: if not self.logique.partieFinie:
if self.dEtape: # Prendre if self.dEtape: # Prendre
self.dx1, self.dy1 = x, y self.dx1, self.dy1 = x, y
self.coulDamier() # Effacement des surbrillances self.coulDamier() # Effacement des surbrillances
if self.logique.aSonTour(self.logique.grille[self.dx1][self.dy1]): # Si possible jouer # Si peut jouer
self.coulCase(self.dx1, self.dy1, 1) if self.logique.aSonTour(self.logique.grille[self.dx1][self.dy1]):
self.mvtPossibleSansEchecs = self.logique.mvtsPossibles(self.dx1, self.dy1) # Surbrillance bleue self.coulCase(self.dx1, self.dy1, 1)
for i in self.mvtPossibleSansEchecs: # Surbrillances vertes self.mvtsPossibles = \
self.logique.mvtsPossibles(
self.dx1, self.dy1) # Surbrillance bleue
for i in self.mvtsPossibles: # Surbrillances vertes
self.coulCase(i[0], i[1], 2) self.coulCase(i[0], i[1], 2)
self.statut('Cliquez où déposer la pièce.') self.statut('Cliquez où déposer la pièce.')
self.dEtape = not self.dEtape self.dEtape = not self.dEtape
else: # Si pas possible de jouer else: # Si ne peut jouer
self.coulCase(self.dx1, self.dy1, 3) self.coulCase(self.dx1, self.dy1, 3)
self.animerC(self.dx1, self.dy1) self.animerC(self.dx1, self.dy1)
else: # Poser else: # Poser
self.dx2, self.dy2 = x, y self.dx2, self.dy2 = x, y
if self.dPiece(self.dx1, self.dy1, self.dx2, self.dy2) or (self.dx1 == self.dx2 and self.dy1 == self.dy2): # Si déplacement fait / Annule dépalcement if self.dPiece(self.dx1, self.dy1, self.dx2, self.dy2) or \
self.coulDamier() # Effacer Surbrillance (self.dx1 == self.dx2 and self.dy1 == self.dy2):
# Si déplacement fait / annulé
self.coulDamier() # Effacer Surbrillance
self.dEtape = not self.dEtape self.dEtape = not self.dEtape
if self.logique.partieFinie: if self.logique.partieFinie:
self.victoire() self.victoire()
else: else:
self.statutPrendre() self.statutPrendre()
else: # Si mauvais déplacement else: # Si mauvais déplacement
self.coulCase(self.dx2, self.dy2, 3) self.coulCase(self.dx2, self.dy2, 3)
self.animerC(self.dx2, self.dy2) self.animerC(self.dx2, self.dy2)
@ -383,27 +406,29 @@ class PlateauTk:
""" """
Réagit en fonction d'un clic Réagit en fonction d'un clic
""" """
# if event.x in range(0, self.coteCase * self.logique.CASES_COTE) and event.y in range(0, self.coteCase * self.logique.CASES_COTE): # if event.x in range(0, self.coteCase * self.logique.CASES_COTE) \
# and event.y in range(0, self.coteCase * self.logique.CASES_COTE):
self.dClic(event.x // self.coteCase, event.y // self.coteCase) self.dClic(event.x // self.coteCase, event.y // self.coteCase)
class FenetreTk: class FenetreTk:
""" """
Fenêtre pour jouer à des jeux sur damier Fenêtre pour jouer à des jeux sur damier
""" """
PLACEHOLDER_DIMENSIONS = 300 # Coté du canvas vide du début PLACEHOLDER_DIMENSIONS = 300 # Coté du canvas vide du début
def __init__(self): def __init__(self):
""" """
Constructeur de FenetreTk Constructeur de FenetreTk
""" """
self.fen = None # Objet Fenêtre self.fen = None # Objet Fenêtre
self.can = None # Objet Canvas self.can = None # Objet Canvas
self.chaine = None # Objet Label de statut self.chaine = None # Objet Label de statut
self.plateau = None # Plateau de jeu self.plateau = None # Plateau de jeu
self.creerFen() self.creerFen()
self.fen.mainloop() self.fen.mainloop()
@ -414,16 +439,19 @@ class FenetreTk:
""" """
self.fen = Tk() self.fen = Tk()
self.fen.title("Jeu de plateau") self.fen.title("Jeu de plateau")
self.can = Canvas(self.fen, width=self.PLACEHOLDER_DIMENSIONS, height=self.PLACEHOLDER_DIMENSIONS, bg="ivory") self.can = Canvas(self.fen, width=self.PLACEHOLDER_DIMENSIONS,
height=self.PLACEHOLDER_DIMENSIONS, bg="ivory")
self.can.grid(row=0, column=1, columnspan=3) self.can.grid(row=0, column=1, columnspan=3)
self.chaine = Label(self.fen, text="Bienvenue !") self.chaine = Label(self.fen, text="Bienvenue !")
self.chaine.grid(row=2, column=2, padx=3, pady=3) self.chaine.grid(row=2, column=2, padx=3, pady=3)
Button(self.fen, text="Nv. Partie", command=self.nvPartie).grid(row=2, column=1, padx=3, pady=3) Button(self.fen, text="Nv. Partie", command=self.nvPartie)\
Button(self.fen, text="Quitter", command=self.fen.destroy).grid(row=2, column=3, padx=3, pady=3) .grid(row=2, column=1, padx=3, pady=3)
Button(self.fen, text="Quitter", command=self.fen.destroy)\
.grid(row=2, column=3, padx=3, pady=3)
def statut(self, texte, delai=0): def statut(self, texte, delai=0):
""" """
Change le message affiché. Change le message affiché.
""" """
self.chaine.config(text=texte) self.chaine.config(text=texte)
# TODO Messages permanents et messages temporaires # TODO Messages permanents et messages temporaires
@ -435,4 +463,5 @@ class FenetreTk:
Démarre une nouvelle partie. Démarre une nouvelle partie.
""" """
del self.plateau del self.plateau
self.plateau = PlateauTk(self.fen, self.can, self.statut, LogiqueEchecs()) self.plateau = PlateauTk(
self.fen, self.can, self.statut, LogiqueEchecs())

View file

@ -1,13 +1,34 @@
import copy import copy
class Logique: class Logique:
""" """
Logique des jeux sur damier Logique des jeux sur damier
(Ne peut être utilisé seul)
""" """
PCE_VIDE = 0 # Valeur à mettre sur la grille quand il n'y a pas de pièce PCE_VIDE = 0 # Valeur à mettre sur la grille quand il n'y a pas de pièce
BLANC = True # Valeur correspondant au joueur blanc BLANC = True # Valeur correspondant au joueur blanc
NOIR = False # Valeur correspondant au joueur noir NOIR = False # Valeur correspondant au joueur noir
# Valeurs devant être remplies par une classe héritante
CASES_COTE = 0 # Cases de coté
# Valeur à partir de laquelle sont comprises les pièces blanches
DECALAGE_BLANCS = 0
# Valeur à partir de laquelle sont comprises les pièces noires
DECALAGE_NOIRS = 0
BLANCS = range(0) # Intervalle contenant les pièces blanches
NOIRS = range(0) # Intervalle contenant les pièces noires
def __init__(self):
self.grille = [] # Grille de jeu
self.cGrille()
self.joueur = self.BLANC # Premier joueur
self.partieFinie = False
self.victorieux = None
@staticmethod @staticmethod
def eCaseBlanche(x, y): def eCaseBlanche(x, y):
@ -20,7 +41,7 @@ class Logique:
""" """
Crée le tableau self.grille. Crée le tableau self.grille.
""" """
for x in range(self.CASES_COTE): # TODO Peut être amélioré for x in range(self.CASES_COTE): # TODO Peut être amélioré
colonne = [] colonne = []
for y in range(self.CASES_COTE): for y in range(self.CASES_COTE):
colonne.append(self.PCE_VIDE) colonne.append(self.PCE_VIDE)
@ -28,7 +49,7 @@ class Logique:
def ePieceBlanc(self, piece): def ePieceBlanc(self, piece):
""" """
Indique si la pièce est une pièce blanche. Indique si la pièce est une pièce blanche.
""" """
return piece in self.BLANCS return piece in self.BLANCS
@ -40,7 +61,7 @@ class Logique:
def ePiece(self, piece): def ePiece(self, piece):
""" """
Indique si la pièce est une pièce. Indique si la pièce donnée est une pièce.
""" """
# return piece != self.PCE_VIDE # return piece != self.PCE_VIDE
return self.ePieceBlanc(piece) or self.ePieceNoir(piece) return self.ePieceBlanc(piece) or self.ePieceNoir(piece)
@ -61,15 +82,16 @@ class Logique:
Indique si la pièce donnée a le droit de jouer. Indique si la pièce donnée a le droit de jouer.
""" """
return (self.ePieceNoir(piece) and self.joueur == self.NOIR) or \ return (self.ePieceNoir(piece) and self.joueur == self.NOIR) or \
(self.ePieceBlanc(piece) and self.joueur == self.BLANC) (self.ePieceBlanc(piece) and self.joueur == self.BLANC)
class LogiqueEchecs(Logique): class LogiqueEchecs(Logique):
""" """
Logique du jeu d'Échecs Logique du jeu d'Échecs
""" """
CASES_COTE = 8 # Cases de coté CASES_COTE = 8 # Cases de coté
# Type de pièces # Type de pièces
PCE_PION = 1 PCE_PION = 1
@ -79,12 +101,15 @@ class LogiqueEchecs(Logique):
PCE_DAME = 5 PCE_DAME = 5
PCE_ROI = 6 PCE_ROI = 6
DECALAGE_BLANCS = 0 # Valeur à partir de laquelle sont compris les pièces blanches # Valeur à partir de laquelle sont comprises les pièces blanches
DECALAGE_NOIRS = 10 # Valeur à partir de laquelle sont compris les pièces noires DECALAGE_BLANCS = 0
# Valeur à partir de laquelle sont comprises les pièces noires
BLANCS = range(DECALAGE_BLANCS+PCE_PION, DECALAGE_BLANCS+PCE_ROI+1) # Intervalle contenant les pièces blancs DECALAGE_NOIRS = 10
NOIRS = range(DECALAGE_NOIRS+PCE_PION, DECALAGE_NOIRS+PCE_ROI+1) # Intervalle contenant les pièces noirs
BLANCS = range(DECALAGE_BLANCS + PCE_PION, DECALAGE_BLANCS + PCE_ROI + 1)
# Intervalle contenant les pièces blanches
NOIRS = range(DECALAGE_NOIRS + PCE_PION, DECALAGE_NOIRS + PCE_ROI + 1)
# Intervalle contenant les pièces noires
# Codes d'erreur de mouvement # Codes d'erreur de mouvement
MVT_INCONNU = 'Cause inconnue' MVT_INCONNU = 'Cause inconnue'
@ -102,18 +127,15 @@ class LogiqueEchecs(Logique):
""" """
Constructeur de LogiqueEchecs Constructeur de LogiqueEchecs
""" """
self.grille = [] # Grille de jeu Logique.__init__(self)
self.cGrille()
self.remplirGrille() self.remplirGrille()
self.joueur = self.BLANC # Premier joueur
self.partieFinie = False
self.victorieux = None
def remplirGrille(self): def remplirGrille(self):
""" """
Remplis la grille avec les pièces nécessaire à une nouvelle partie. Remplis la grille avec les pièces nécessaire à une nouvelle partie.
""" """
speciales = [self.PCE_TOUR, self.PCE_CAVALIER, self.PCE_FOU, self.PCE_ROI, self.PCE_DAME] speciales = [self.PCE_TOUR, self.PCE_CAVALIER,
self.PCE_FOU, self.PCE_ROI, self.PCE_DAME]
speciales += speciales[2::-1] speciales += speciales[2::-1]
for i in range(0, 8): for i in range(0, 8):
self.grille[i][0] = self.DECALAGE_NOIRS + speciales[i] self.grille[i][0] = self.DECALAGE_NOIRS + speciales[i]
@ -125,7 +147,7 @@ class LogiqueEchecs(Logique):
""" """
Vérifie si le déplacement est possible pour un pion. Vérifie si le déplacement est possible pour un pion.
""" """
if x1 == x2 and self.grille[x2][y2] <= 0: # Avance if x1 == x2 and self.grille[x2][y2] <= 0: # Avance
if self.joueur: if self.joueur:
if y2 == y1 - 1: if y2 == y1 - 1:
return self.MVT_OK return self.MVT_OK
@ -140,16 +162,16 @@ class LogiqueEchecs(Logique):
return self.MVT_OK return self.MVT_OK
else: else:
return self.MVT_N_AUTORISE return self.MVT_N_AUTORISE
elif abs(x1-x2) == 1: # Saut elif abs(x1 - x2) == 1: # Saut
if self.joueur: if self.joueur:
if y2 == y1 - 1 and \ if y2 == y1 - 1 and \
self.ePieceNoir(self.grille[x2][y2]): self.ePieceNoir(self.grille[x2][y2]):
return self.MVT_OK return self.MVT_OK
else: else:
return self.MVT_N_AUTORISE return self.MVT_N_AUTORISE
else: else:
if y2 == y1 + 1 and \ if y2 == y1 + 1 and \
self.ePieceBlanc(self.grille[x2][y2]): self.ePieceBlanc(self.grille[x2][y2]):
return self.MVT_OK return self.MVT_OK
else: else:
return self.MVT_N_AUTORISE return self.MVT_N_AUTORISE
@ -161,13 +183,13 @@ class LogiqueEchecs(Logique):
Vérifie si le déplacement est possible pour une tour. Vérifie si le déplacement est possible pour une tour.
""" """
if y1 == y2: if y1 == y2:
sens = (x2-x1)//abs(x2-x1) sens = (x2 - x1) // abs(x2 - x1)
for x in range(x1+sens, x2, sens): for x in range(x1 + sens, x2, sens):
if self.ePiece(self.grille[x][y1]): if self.ePiece(self.grille[x][y1]):
return self.MVT_OBSTRUCTION return self.MVT_OBSTRUCTION
elif x1 == x2: elif x1 == x2:
sens = (y2-y1)//abs(y2-y1) sens = (y2 - y1) // abs(y2 - y1)
for y in range(y1+sens, y2, sens): for y in range(y1 + sens, y2, sens):
if self.ePiece(self.grille[x1][y]): if self.ePiece(self.grille[x1][y]):
return self.MVT_OBSTRUCTION return self.MVT_OBSTRUCTION
else: else:
@ -178,23 +200,23 @@ class LogiqueEchecs(Logique):
""" """
Vérifie si le déplacement est possible pour un fou. Vérifie si le déplacement est possible pour un fou.
""" """
if abs(x2-x1) == abs(y2-y1): if abs(x2 - x1) == abs(y2 - y1):
sensX = (x2-x1)//abs(x2-x1) sensX = (x2 - x1) // abs(x2 - x1)
sensY = (y2-y1)//abs(y2-y1) sensY = (y2 - y1) // abs(y2 - y1)
x = x1 x = x1
y = y1 y = y1
dist = 0 dist = 0
distTot = abs(x2-x1) distTot = abs(x2 - x1)
while dist < distTot: while dist < distTot:
dist += 1 dist += 1
x += sensX x += sensX
y += sensY y += sensY
if self.ePiece(self.grille[x][y]): if self.ePiece(self.grille[x][y]):
if dist == distTot: if dist == distTot:
return self.MVT_OK # Saut return self.MVT_OK # Saut
else: else:
return self.MVT_OBSTRUCTION return self.MVT_OBSTRUCTION
return self.MVT_OK # Vide return self.MVT_OK # Vide
else: else:
return self.MVT_N_AUTORISE return self.MVT_N_AUTORISE
@ -202,23 +224,24 @@ class LogiqueEchecs(Logique):
""" """
Vérifie si le déplacement est possible pour un cavalier. Vérifie si le déplacement est possible pour un cavalier.
""" """
if (abs(x2-x1) == 2 and abs(y2-y1) == 1) or (abs(y2-y1) == 2 and abs(x2-x1) == 1): if (abs(x2 - x1) == 2 and abs(y2 - y1) == 1) or (abs(y2 - y1) == 2 and abs(x2 - x1) == 1):
return self.MVT_OK return self.MVT_OK
else: else:
return self.MVT_N_AUTORISE return self.MVT_N_AUTORISE
def deplPossible(self, x1, y1, x2, y2): # TODO Utiliser la gestion d'erreurs ? # TODO Utiliser la gestion d'erreurs ?
def deplPossible(self, x1, y1, x2, y2):
""" """
Vérifie si le déplacement est possible. Vérifie si le déplacement est possible.
""" """
piece = self.grille[x1][y1] piece = self.grille[x1][y1]
if self.aSonTour(piece): if self.aSonTour(piece):
if (x1 != x2 or y1 != y2): if x1 != x2 or y1 != y2:
if not self.aSonTour(self.grille[x2][y2]): if not self.aSonTour(self.grille[x2][y2]):
tPiece = self.tPiece(piece) tPiece = self.tPiece(piece)
if tPiece == self.PCE_PION: # Pion if tPiece == self.PCE_PION: # Pion
return self.deplPossiblePion(x1, y1, x2, y2) return self.deplPossiblePion(x1, y1, x2, y2)
elif tPiece == self.PCE_TOUR: # Tour elif tPiece == self.PCE_TOUR: # Tour
return self.deplPossibleTour(x1, y1, x2, y2) return self.deplPossibleTour(x1, y1, x2, y2)
elif tPiece == self.PCE_CAVALIER: elif tPiece == self.PCE_CAVALIER:
return self.deplPossibleCavalier(x1, y1, x2, y2) return self.deplPossibleCavalier(x1, y1, x2, y2)
@ -232,10 +255,10 @@ class LogiqueEchecs(Logique):
elif tour == self.MVT_OBSTRUCTION or fou == self.MVT_OBSTRUCTION: elif tour == self.MVT_OBSTRUCTION or fou == self.MVT_OBSTRUCTION:
return self.MVT_OBSTRUCTION return self.MVT_OBSTRUCTION
else: else:
return self.MVT_N_AUTORISE return self.MVT_N_AUTORISE
elif tPiece == self.PCE_ROI: elif tPiece == self.PCE_ROI:
if abs(x2-x1) <= 1 and abs(y2-y1) <= 1: if abs(x2 - x1) <= 1 and abs(y2 - y1) <= 1:
return self.MVT_OK return self.MVT_OK
else: else:
return self.MVT_N_AUTORISE return self.MVT_N_AUTORISE
else: else:
@ -247,34 +270,38 @@ class LogiqueEchecs(Logique):
else: else:
return self.MVT_SELECTION return self.MVT_SELECTION
return self.MVT_INCONNU return self.MVT_INCONNU
def mvtPossible(self, x1, y1, x2, y2): def mvtPossible(self, x1, y1, x2, y2):
""" """
Vérifie si le mouvement est possible. Vérifie si le mouvement est possible.
Contrairement aux fonctions de vérification de déplacement, celle-ci Contrairement aux fonctions de vérification de déplacement, celle-ci
vérifie si le mouvement est réalisable si le roi est en échec. vérifie si le mouvement est réalisable si le roi est en échec.
""" """
test = self.deplPossible(x1, y1, x2, y2) test = self.deplPossible(x1, y1, x2, y2)
if test == self.MVT_OK: if test == self.MVT_OK:
# On copie la partie actuelle pour tester le mouvement et vérifier l'échec # On copie la partie actuelle pour tester le mouvement et vérifier
copie = copy.deepcopy(self); # l'échec
copie = copy.deepcopy(self)
copie.dPieceSansEchec(x1, y1, x2, y2) copie.dPieceSansEchec(x1, y1, x2, y2)
mvtsPossiblesTousAdverses = [] mvtsPossiblesTousAdverses = []
# On cherche la position du roi # On cherche la position du roi
pieceRoi = self.PCE_ROI + self.DECALAGE_BLANCS if self.joueur else self.DECALAGE_NOIRS pieceRoi = self.PCE_ROI + \
self.DECALAGE_BLANCS if self.joueur else self.DECALAGE_NOIRS
roi = [-1, -1] roi = [-1, -1]
for x in range(0, self.CASES_COTE): for x in range(0, self.CASES_COTE):
for y in range(0, self.CASES_COTE): for y in range(0, self.CASES_COTE):
mvtsPossiblesTousAdverses += copie.mvtsPossiblesSansEchec(x, y) mvtsPossiblesTousAdverses += copie.mvtsPossiblesSansEchec(
x, y)
if copie.grille[x][y] == pieceRoi: if copie.grille[x][y] == pieceRoi:
roi = [x, y] roi = [x, y]
if roi in mvtsPossiblesTousAdverses: # Si le roi peut être sauté au tour adverse # Si le roi peut être sauté au tour adverse
if roi in mvtsPossiblesTousAdverses:
return self.MVT_ECHEC return self.MVT_ECHEC
else: else:
return test return test
else: else:
return test return test
def mvtsPossiblesSansEchec(self, x1, y1): def mvtsPossiblesSansEchec(self, x1, y1):
""" """
Donne la liste des déplacements possible pour la pièce donnée. Donne la liste des déplacements possible pour la pièce donnée.
@ -305,7 +332,8 @@ class LogiqueEchecs(Logique):
""" """
test = self.deplPossible(x1, y1, x2, y2) test = self.deplPossible(x1, y1, x2, y2)
if test == self.MVT_OK: if test == self.MVT_OK:
self.grille[x1][y1], self.grille[x2][y2] = self.PCE_VIDE, 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.joueur = not self.joueur
def vEchecMat(self): def vEchecMat(self):
@ -332,15 +360,16 @@ class LogiqueEchecs(Logique):
retour = { retour = {
'valide': False, 'valide': False,
'message': test, 'message': test,
'deplacer': [], # Pièces à déplacer 'deplacer': [], # Pièces à déplacer
'supprimer': [], # Pièces à supprimer 'supprimer': [], # Pièces à supprimer
} }
if test == self.MVT_OK: if test == self.MVT_OK:
retour['valide'] = True retour['valide'] = True
if self.ePiece(self.grille[x2][y2]): if self.ePiece(self.grille[x2][y2]):
retour['supprimer'].append([x2, y2]) retour['supprimer'].append([x2, y2])
retour['deplacer'].append([x1, y1, 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.grille[x1][y1], self.grille[x2][
y2] = self.PCE_VIDE, self.grille[x1][y1]
self.joueur = not self.joueur self.joueur = not self.joueur
self.vEchecMat() self.vEchecMat()
return retour return retour