Geoffrey Frogeye
87635bb8a6
Je pensais que je l'avais commité ce matin, mais les changements ne se sont retrouvé que dans la branche tkResize...
334 lines
12 KiB
Python
334 lines
12 KiB
Python
from tkinter import *
|
|
from logique import LogiqueEchecs
|
|
|
|
class PlateauTk:
|
|
|
|
RATIO_PCE_CASE = .95
|
|
TEMPS_ANIM = 200
|
|
INTER_ANIM = 10
|
|
|
|
COTE_TOUT_DEFAUT = 500
|
|
|
|
def __init__(self, fen, can, statut, logique):
|
|
|
|
self.can = can
|
|
self.fen = fen
|
|
self.statut = statut
|
|
self.chaine = None
|
|
self.grilleDamier = []
|
|
self.imagesOriginales = {}
|
|
self.imagesRedim = {}
|
|
self.photos = []
|
|
self.grillePions = []
|
|
self.animations = []
|
|
|
|
self.dEtape = True
|
|
self.dx1 = -1
|
|
self.dy1 = -1
|
|
self.dx2 = -1
|
|
self.dy2 = -1
|
|
self.mvtsPossibles = []
|
|
self.logique = logique
|
|
|
|
self.coteCase = 0
|
|
|
|
self.importerImages()
|
|
self.redimCan(self.COTE_TOUT_DEFAUT)
|
|
self.can.bind('<Button-1>', self.clic)
|
|
|
|
self.statutPrendre()
|
|
|
|
def redimCan(self, cote):
|
|
self.can.delete(ALL)
|
|
self.coteCase = cote // self.logique.CASES_COTE
|
|
cote = self.logique.CASES_COTE * self.coteCase
|
|
self.can.config(width=cote, height=cote)
|
|
for i in self.imagesRedim:
|
|
del i
|
|
self.redimImages()
|
|
self.cDamier()
|
|
self.cGrille()
|
|
self.remplirGrille(self.logique.grille)
|
|
|
|
|
|
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 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 // (self.coteCase * self.RATIO_PCE_CASE)) # TODO S'en sort pour être toujours plus grand
|
|
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 / Victoire
|
|
return '#bafea0' if blanc else '#6ed147'
|
|
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(self.logique.eCaseBlanche(x, y), 0)
|
|
return self.can.create_rectangle(x * self.coteCase, y * self.coteCase, (x + 1) * self.coteCase, (y + 1) * self.coteCase)
|
|
|
|
def coulCase(self, 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):
|
|
for x in range(0, self.logique.CASES_COTE):
|
|
for y in range(0, self.logique.CASES_COTE):
|
|
self.coulCase(x, y, 0)
|
|
|
|
def cDamier(self):
|
|
self.grilleDamier = []
|
|
for x in range(0, self.logique.CASES_COTE):
|
|
colonne = []
|
|
for y in range(0, self.logique.CASES_COTE):
|
|
colonne.append(self.cCase(x, y))
|
|
self.grilleDamier.append(colonne)
|
|
self.coulDamier()
|
|
|
|
def cPion(self, x, y, piece):
|
|
if piece > 0:
|
|
self.grillePions[x][y] = self.can.create_image((x + .5) * self.coteCase, (y + .5) * self.coteCase, image=self.imagesRedim[piece])
|
|
else:
|
|
self.grillePions[x][y] = False
|
|
|
|
def cGrille(self):
|
|
self.grillePions = []
|
|
for x in range(0, self.logique.CASES_COTE): # Crée self.grillePions
|
|
colonne = []
|
|
for y in range(0, self.logique.CASES_COTE):
|
|
colonne.append(False)
|
|
self.grillePions.append(colonne)
|
|
|
|
def remplirGrille(self, j_grilleF):
|
|
for x in range(0, self.logique.CASES_COTE): # Remplis self.grillePions
|
|
for y in range(0, self.logique.CASES_COTE):
|
|
self.cPion(x, y, j_grilleF[x][y])
|
|
|
|
# Interaction
|
|
def nomJoueur(self, joueur, pluriel=True):
|
|
if joueur == self.logique.BLANC:
|
|
nom = 'blanc'
|
|
elif joueur == self.logique.NOIR:
|
|
nom = 'noir'
|
|
else:
|
|
nom = 'inconnu'
|
|
if pluriel:
|
|
nom += 's'
|
|
return nom
|
|
|
|
def statutPrendre(self):
|
|
self.statut('Prendre (' + self.nomJoueur(self.logique.joueur) + ')')
|
|
|
|
@staticmethod
|
|
def animationDCoords(i):
|
|
x = i['x1'] + (i['x2']-i['x1']) * (i['avancement']/i['total'])
|
|
y = i['y1'] + (i['y2']-i['y1']) * (i['avancement']/i['total'])
|
|
return [x, y]
|
|
|
|
def animation(self):
|
|
animationsNv = []
|
|
for i in self.animations:
|
|
if i['avancement'] < i['total']:
|
|
if i['type'] == 'd':
|
|
coords = self.animationDCoords(i)
|
|
self.can.coords(i['pion'], coords[0], coords[1])
|
|
# elif i['type'] == 'f':
|
|
# TODO Opacité de i['pion']
|
|
# elif i['type'] == 'c':
|
|
# TODO Opacité de case
|
|
i['avancement'] += self.INTER_ANIM
|
|
animationsNv.append(i)
|
|
else:
|
|
if i['type'] == 'd':
|
|
self.can.coords(i['pion'], i['x2'], i['y2'])
|
|
elif i['type'] == 'f':
|
|
self.can.delete(i['pion'])
|
|
elif i['type'] == 'c':
|
|
self.coulCase(i['x'], i['y'], 0)
|
|
self.animations = animationsNv
|
|
if len(animationsNv):
|
|
self.fen.after(self.INTER_ANIM, self.animation)
|
|
|
|
def animer(self, animation):
|
|
etaitVide = len(self.animations) < 1
|
|
self.animations.append(animation)
|
|
if etaitVide:
|
|
self.animation()
|
|
|
|
def animerD(self, x1, y1, x2, y2, pion):
|
|
if len(self.animations):
|
|
for i in self.animations:
|
|
if i['type'] == 'd' and i['pion'] == pion:
|
|
# Si une animation pour ce pion existe déjà, on la reprend et on la modifie
|
|
coords = self.animationDCoords(i)
|
|
i['x1'] = coords[0]
|
|
i['y1'] = coords[1]
|
|
i['x2'] = x2
|
|
i['y2'] = y2
|
|
# i['total'] = i['total'] - i['avancement']
|
|
i['total'] = self.TEMPS_ANIM
|
|
i['avancement'] = 0
|
|
return
|
|
|
|
animation = {
|
|
'x1': x1,
|
|
'y1': y1,
|
|
'x2': x2,
|
|
'y2': y2,
|
|
'pion': pion,
|
|
'type': 'd',
|
|
'total': self.TEMPS_ANIM,
|
|
'avancement': 0
|
|
}
|
|
self.can.tag_raise(pion) # Mise au premier plan
|
|
self.animer(animation)
|
|
|
|
def animerF(self, pion): # Pion fade-out
|
|
animation = {
|
|
'pion': pion,
|
|
'type': 'f',
|
|
'total': self.TEMPS_ANIM,
|
|
'avancement': 0
|
|
}
|
|
self.animer(animation)
|
|
|
|
def animerC(self, x ,y):
|
|
animation = {
|
|
'type': 'c',
|
|
'x': x,
|
|
'y': y,
|
|
'total': self.TEMPS_ANIM,
|
|
'avancement': 0
|
|
}
|
|
self.animer(animation)
|
|
|
|
def victoire(self):
|
|
self.statut('Victoire des ' + self.nomJoueur(self.logique.victorieux) + ' !')
|
|
self.coulDamier()
|
|
for x in range(0, self.logique.CASES_COTE):
|
|
for y in range(0, self.logique.CASES_COTE):
|
|
pion = self.logique.grille[x][y]
|
|
if pion > 0:
|
|
if self.logique.ePionNoir(pion) ^ self.logique.victorieux:
|
|
self.coulCase(x, y, 2)
|
|
else:
|
|
self.coulCase(x, y, 3)
|
|
|
|
def dPion(self, x1, y1, x2, y2):
|
|
test = self.logique.dPion(x1, y1, x2, y2)
|
|
if test['valide'] == True: # Si déplacement possible
|
|
for s in test['supprimer']:
|
|
self.animerF(self.grillePions[s[0]][s[1]])
|
|
for d in test['deplacer']:
|
|
self.grillePions[d[2]][d[3]], self.grillePions[d[0]][d[1]] = \
|
|
self.grillePions[d[0]][d[1]], False
|
|
self.animerD((d[0] + .5) * self.coteCase, (d[1] + .5) * self.coteCase, \
|
|
(d[2] + .5) * self.coteCase, (d[3] + .5) * self.coteCase, \
|
|
self.grillePions[d[2]][d[3]])
|
|
|
|
else:
|
|
self.statut('Déplacment impossible ! (' + test['message'] + ')')
|
|
return test['valide']
|
|
|
|
def dClic(self, x, y):
|
|
if not self.logique.partieFinie:
|
|
if self.dEtape: # Prendre
|
|
self.dx1, self.dy1 = x, y
|
|
self.coulDamier() # Effacement des surbrillances
|
|
if self.logique.aSonTour(self.logique.grille[self.dx1][self.dy1]): # Si possible jouer
|
|
self.coulCase(self.dx1, self.dy1, 1)
|
|
self.mvtPossibleSansEchecs = self.logique.mvtsPossibles(self.dx1, self.dy1) # Surbrillance bleue
|
|
for i in self.mvtPossibleSansEchecs: # Surbrillances vertes
|
|
self.coulCase(i[0], i[1], 2)
|
|
self.statut('Poser')
|
|
self.dEtape = not self.dEtape
|
|
else: # Si pas possible de jouer
|
|
self.coulCase(self.dx1, self.dy1, 3)
|
|
self.animerC(self.dx1, self.dy1)
|
|
else: # Poser
|
|
self.dx2, self.dy2 = x, y
|
|
if self.dPion(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
|
|
self.coulDamier() # Effacer Surbrillance
|
|
self.dEtape = not self.dEtape
|
|
if self.logique.partieFinie:
|
|
self.victoire()
|
|
else:
|
|
self.statutPrendre()
|
|
else: # Si mauvais déplacement
|
|
self.coulCase(self.dx2, self.dy2, 3)
|
|
self.animerC(self.dx2, self.dy2)
|
|
|
|
def clic(self, event):
|
|
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)
|
|
|
|
|
|
class FenetreTk:
|
|
|
|
PLACEHOLDER_DIMENSIONS = 300
|
|
|
|
def __init__(self):
|
|
|
|
self.fen = None
|
|
self.can = None
|
|
self.chaine = ''
|
|
|
|
self.plateau = None
|
|
|
|
self.creerFen()
|
|
self.fen.mainloop()
|
|
|
|
def creerFen(self):
|
|
self.fen = Tk()
|
|
self.fen.title("Jeu de plateau")
|
|
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.chaine = Label(self.fen, text="Bienvenue !")
|
|
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="Quitter", command=self.fen.destroy).grid(row=2, column=3, padx=3, pady=3)
|
|
|
|
def statut(self, texte, delai=0):
|
|
self.chaine.config(text=texte)
|
|
# TODO Timeout effacer si parametre / Liste
|
|
|
|
def nvPartie(self):
|
|
self.plateau = PlateauTk(self.fen, self.can, self.statut, LogiqueEchecs())
|