This repository has been archived on 2019-08-09. You can view files and clone it, but cannot push or open issues or pull requests.
s1-tp/S1/Echecs/guiTk.py
Geoffrey Frogeye 87635bb8a6 [Echecs] Possibilité de redimensionner le canvas
Je pensais que je l'avais commité ce matin, mais les changements ne se
sont retrouvé que dans la branche tkResize...
2014-12-13 23:11:25 +01:00

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())