begin process at 2012 02 05 00:34:37
  Trouver un code source :
 
dans
 
Accueil > 

Code

 > 

Jeux

 > BILLARD FRANÇAIS

BILLARD FRANÇAIS


 Information sur la source

Note :
9,33 / 10 - par 6 personnes
9,33 / 10

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10
Catégorie :Jeux Classé sous :billard, collisions, button, label, scale Niveau :Débutant Date de création :18/08/2005 Date de mise à jour :23/12/2005 01:36:54 Vu / téléchargé :6 198 / 405

Auteur : HCD

Ecrire un message privé
Commentaire sur cette source (5)
Ajouter un commentaire et/ou une note

 Description

Trois boules : blanche, rouge et grise sur un tapis vert ... et deux joueurs.
Après avoir placé les boules sur le billard et réglé la direction, la vitesse,
l'effet et la hauteur de tir, le premier joueur pourra "continuer", "rejouer le coup" ou
"passer la main", en fonction des résultats de son score.
L'algorithme de choc passe par le calcul du recul des boules après intersection de
leurs  contours, pour revenir au strict contact, puis par la détermination des nouveaux
vecteurs vitesses selon les lois de la mécanique des chocs inélastiques.
Ce script devrait intéresser les débutants qui cherchent à mettre en oeuvre les interfaces
graphiques Tkinter, avec les widgets Canvas, Button, Text, Scale et Label.

Source

  • #! /usr/bin/env python
  • # -*- coding: Latin-1 -*-
  • # <<< Billard >>>
  • # REMERCIEMENTS : ce projet est très largement inspiré des exemples fournis par Mr Gérard Swinnen dans la deuxième édition de son ouvrage intitulé "Apprendre à programmer avec Python".
  • from Tkinter import *
  • from math import *
  • # CONVENTIONS
  • # boule BLANCHE....(coordonnées:x1,y1):B1
  • # boule ROUGE......(coordonnées:x2,y2):B2
  • # boule GRISE......(coordonnées:x3,y3):B3
  • # bille bleue......(coordonnées:x4,y4):b4(Réglage de l'effet latéral et de la hauteur de tir)
  • # cercle blanc.....(coordonnées:x5,y5):b5(Réglage de l'orientation et de la vitesse de tir)
  • # pupitre de simulation : indice "S"
  • ########## Commande "préparer le jeu" ####################################
  • def jouer():
  • "Préparer le jeu"
  • global flag,texte
  • if flag==0:flag=1
  • jouer;config_init() # mise en place de la configuration initiale (boules,flèches,réglages)
  • can.bind("<Button-1>", mouseDown) # commandes avec le clic gauche de la souris
  • can.bind("<Button1-Motion>", mouseMove)
  • can.bind("<Button1-ButtonRelease>", mouseUp)
  • T.pack(),J.pack_forget() # gestion des boutons de commande
  • can.delete(texte)
  • ########## Commandes de réglage du tir ###################################
  • def mouseDown( event):
  • "Opérations à effectuer quand le bouton gauche de la souris est enfoncé"
  • global selObject,X,Y,x5,y5,v,o
  • can.currObject=None
  • X,Y=event.x,event.y # coordonnées du clic
  • D1=hypot(X-x1-r,Y-y1-r) # distance entre le clic et le centre de B1
  • D2=hypot(X-x2-r,Y-y2-r) # idem B2
  • D3=hypot(X-x3-r,Y-y3-r) # idem B3
  • D4=hypot(X-x4-R,Y-y4-R) # idem bille bleue
  • D5=hypot(X-x5-R,Y-y5-R) # idem cercle blanc
  • X5,Y5=x5-7L/8+R,y5-H-h/2+R
  • H5=hypot(X5,Y5)
  • if D1<r:selObject=b1 # sélection de B1 si le clic est à l'intérieur de B1
  • if D2<r:selObject=b2 # idem B2
  • if D3<r:selObject=b3 # idem B3
  • if D4<R:selObject=b4 # idem bille bleue
  • if D5<4*R:selObject=b5 # plage de sélection du cercle blanc: cercle de rayon 4R
  • if selObject==b5: # procédure de réglage fin, par clic sussessifs à proximité
  • dx,dy=(X-x5-R)/40,(Y-y5-R)/40 # pas = 1/40 ème de la distance du clic au centre du cercle
  • x5,y5=x5+dx,y5+dy
  • can.move(selObject,dx,dy) # déplacement du cercle blanc
  • C5=can.coords(b5)
  • x5,y5=C5[0],C5[1]
  • o=-atan2(y5-H-h/2+R,x5-7*L/8+R) # récupération de l'angle de tir (o)
  • wo=round(float(o*180/pi),1)
  • can.orientation.config(text='%s'%wo) # valeur d'affichage de (o)
  • v=1+14*hypot(x5+R-7*L/8-2*R*cos(o),y5+R-H-h/2+2*R*sin(o))/(3*h/8-3*R) # récupération de la vitessede tir (v)
  • wv=round(float(v),1)
  • can.vitesse.config(text='%s'%wv) # valeur d'affichage de (v)
  • if B1==1:fl(flèche1,o,x1,y1)
  • if B3==1:fl(flèche3,o,x3,y3)
  • can.coords(curseur5,7*L/8+R*cos(o),H+h/2-R*sin(o),x5+R-R*cos(o),y5+R+R*sin(o))
  • can.itemconfig(selObject,width=2) # le contour de l'objet sélectionné double d'épaisseur
  • def mouseMove(event):
  • "Opérations à effectuer quand la souris se déplace, bouton gauche enfoncé"
  • global O,X,Y
  • global x1,y1,x2,y2,x3,y3,x4,y4,x5,y5
  • global e,ha,v,o,o4
  • XX,YY=event.x,event.y
  • dx,dy=XX-X,YY-Y
  • if selObject==b1:
  • if dx+x1>0 and dx+x1<L-2*r and dy+y1>0 and dy+y1<H-2*r:
  • can.move(selObject,dx,dy);X,Y=XX,YY # déplacement de B1
  • C1=can.coords(b1)
  • x1,y1=C1[0],C1[1] # récupération des coordonnées du coin supérieur gauche
  • if B1==1:fl(flèche1,pi,x1,y1) # déplacement de la flèche de B1
  • if selObject==b2 :
  • if dx+x2>0 and dx+x2<L-2*r and dy+y2>0 and dy+y2<H-2*r:
  • can.move(selObject,dx,dy);X,Y=XX,YY # déplacement de B2
  • C2=can.coords(b2)
  • x2,y2=C2[0],C2[1]
  • if selObject==b3 :
  • if dx+x3>0 and dx+x3<L-2*r and dy+y3>0 and dy+y3<H-2*r:
  • can.move(selObject,dx,dy);X,Y=XX,YY # déplacement de B3
  • C3=can.coords(b3)
  • x3,y3=C3[0],C3[1]
  • if B3==1:fl(flèche3,pi,x3,y3) # déplacement de la flèche de B3
  • if selObject==b4:
  • DX4,DY4=dx+x4-L/8+R,dy+y4-H-h/2+R
  • HD4=hypot(DX4,DY4)
  • if HD4<R4-R:
  • can.move(selObject,dx,dy);X,Y=XX,YY # déplacement de la bille bleue
  • C4=can.coords(b4)
  • x4,y4=C4[0],C4[1]
  • o4=atan2(DY4,DX4)
  • e=(x4-L/8+R)*2/(R4-R)*pi/180 # calcul de l'effet (-2<e<+2)
  • we=round(float(e*180/pi),1);can.effet.config(text='%s'%we)
  • ha=-2*(y4-H-h/2+R)/(R4-R) # calcul de la hauteur (-2<h<+2)
  • wha=round(float(ha),1);can.hauteur.config(text='%s'%wha)
  • can.coords(curseur4,L/8+R4*cos(o4),H+h/2+R4*sin(o4),L/8-R4*cos(o4),H+h/2-R4*sin(o4))
  • if selObject==b5:
  • DX5,DY5=dx+x5-7*L/8+R,dy+y5-H-h/2+R
  • HD5=hypot(DX5,DY5)
  • if HD5<3*h/8-R and HD5>2*R:
  • can.move(selObject,dx,dy);X,Y=XX,YY # déplacement du cercle blanc dans l'espace d'orientation et de vitesse
  • C5=can.coords(b5)
  • x5,y5=C5[0],C5[1]
  • o=-atan2(y5-H-h/2+R,x5-7*L/8+R) # récupération de l'angle de tir (o)
  • wo=round(float(o*180/pi),1)
  • can.orientation.config(text='%s'%wo)
  • v=1+14*hypot(x5+R-7*L/8-2*R*cos(o),y5+R-H-h/2+2*R*sin(o))/(3*h/8-3*R)# récupération de la vitesse de tir (v)
  • wv=round(float(v),1)
  • can.vitesse.config(text='%s'%wv)
  • can.coords(curseur5,7*L/8+R*cos(o),H+h/2-R*sin(o),x5+R-R*cos(o),y5+R+R*sin(o))
  • if B1==1:fl(flèche1,o,x1,y1)
  • if B3==1:fl(flèche3,o,x3,y3)
  • def mouseUp(event):
  • "Opérations à effectuer quand le bouton gauche de la souris est relâché"
  • global selObject
  • can.itemconfig(selObject,width=1) # le contour de l'objet sélectionné revient à son épaisseur initiale
  • if selObject==b1:selObject=None
  • if selObject==b2:selObject=None
  • if selObject==b3:selObject=None
  • if selObject==b4:selObject=None
  • if selObject==b5:selObject=None
  • ########## Commande "tirer" ##############################################
  • def tirer():
  • "tirer "
  • global T1,T3,t1,t3,S1,S3,E1,E3,R1,R3,PM1,PM3
  • global x1,y1,x3,y3,dx1,dy1,dx3,dy3
  • global xx1,yy1,xx2,yy2,xx3,yy3
  • global dxx1,dyy1,dxx2,dyy2,dxx3,dyy3
  • global xx4,yy4,xx5,yy5
  • global ee,hh,oo,vv,oo4
  • if B1==1:
  • T1=1;t1+=1 # indicateur et compteur de tir
  • dx1,dy1=v*cos(o),-v*sin(o) # coordonnées du vecteur vitesse
  • can.coords(flèche1,x1+r,y1+r,x1+r,y1+r) # origine de la flèche
  • can.itemconfig(b4,fill='white',outline='white') # effacement de la bille bleue
  • can.itemconfig(curseur4,fill='white') # effacement du diamètre de la bille bleue
  • if B3==1:
  • T3=1;t3+=1
  • dx3,dy3=v*cos(o),-v*sin(o)
  • can.coords(flèche3,x3+r,y3+r,x3+r,y3+r) # idem
  • can.itemconfig(b4,fill='grey',outline='grey') # idem
  • can.itemconfig(curseur4,fill='grey')
  • xx1,yy1,xx2,yy2,xx3,yy3=x1,y1,x2,y2,x3,y3 # mémorisation de la position des trois boules
  • dxx1,dyy1,dxx2,dyy2,dxx3,dyy3=dx1,dy1,dx2,dy2,dx3,dy3 # mémorisation de la vitesse des trois boules
  • xx4,yy4,xx5,yy5=x4,y4,x5,y5 # mémorisation de la position de la bille et du cercle
  • ee,hh,oo,vv,oo4=e,ha,o,v,o4 # mémorisation des réglages du tir
  • S1,S3,E1,E3,R1,R3,PM1,PM3,CT1,CT3=0,0,0,0,0,0,0,0,0,0 # mise à zéro des indicateurs
  • T.pack_forget();FI.pack() # gestion des boutons de commande
  • can.itemconfig(texte1,fill="brown")
  • can.delete(texte2);can.delete(texte3)
  • can.itemconfig(b5,outline='dark green') # effacement du cercle blanc
  • can.itemconfig(curseur5,fill='dark green') # effacement de la flèche
  • move() # appel de la fonction "mouvement" des boules
  • ###### Commandes "continuer/rejouer/passer la main/figer/relancer" #######
  • def continuer():
  • "continuer"
  • global flag,CT1,CT3,B1,B3
  • global x1,y1,x2,y2,x3,y3,x4,y4,x5,y5
  • global e,ha,o,v,o4,o6
  • if flag==0:flag=1
  • e,ha,o,v,o4=0,0,pi,8,pi/2 # réglages de départ
  • x4,y4,x5,y5=x4o,y4o,x5o,y5o # coordonnées de départ de la bille et du cercle
  • effacer_simulation()
  • continuer;config() # mise en place de la configuration
  • if S1==1:CT1=1;B1,B3=1,0;fl(flèche1,o,x1,y1)
  • if S3==1:CT3=1;B1,B3=0,1;fl(flèche3,o,x3,y3)
  • T.pack();CT.pack_forget();RJ.pack_forget()
  • effacer_texteR()
  • def rejouer():
  • "rejouer le coup"
  • global flag,R1,R3,r1,r3
  • global x1,y1,x2,y2,x3,y3
  • global e,ha,o,v,o4
  • if flag==0:flag=1
  • e,ha,o,v,o4 =ee,hh,oo,vv,oo4 # récupération des réglages avant tir
  • x1,y1,x2,y2,x3,y3=xx1,yy1,xx2,yy2,xx3,yy3 # récupération des positions avant tir des boules
  • x4,y4,x5,y5=xx4,yy4,xx5,yy5 # récupération des positions avant tir de la bille et du cercle
  • rejouer;config() # mise en place de la configuration
  • if B1==1 :R1=1;fl(flèche1,o,x1,y1);r1+=1
  • if B3==1 :R3=1;fl(flèche3,o,x3,y3);r3+=1
  • T.pack();RJ.pack_forget();PM.pack_forget();CT.pack_forget()
  • effacer_texteR()
  • def passer():
  • "passer la main"
  • global flag,PM1,PM3,B1,B3
  • global x1,y1,x2,y2,x3,y3,x4,y4,x5,y5
  • global e,ha,o,v,o4
  • if flag==0:flag=1
  • e,ha,o,v,o4=0,0,pi,8,pi/2 # réglages de départ
  • x4,y4,x5,y5=x4o,y4o,x5o,y5o # coordonnées de départ de la bille et du cercle
  • effacer_simulation()
  • passer;config() # mise en place de la configuration
  • if E1==1:PM1=1;B1,B3=0,1;fl(flèche3,o,x3,y3) # changement de boule (B3 prend la main)
  • if E3==1:PM3=1;B1,B3=1,0;fl(flèche1,o,x1,y1)
  • if B3==1:can.itemconfig(REG4,fill='grey');can.itemconfig(REG5B,fill='grey')
  • if B1==1:can.itemconfig(REG4,fill='white');can.itemconfig(REG5B,fill='white')
  • T.pack();RJ.pack_forget();PM.pack_forget();CT.pack_forget()
  • effacer_texteR()
  • def stop():
  • "Figer le jeu"
  • global flag,figer
  • figer=1;flag=0
  • dxx1,dyy1,dxx2,dyy2,dxx3,dyy3=dx1,dy1,dx2,dy2,dx3,dy3 # mémorisation de la vitesse des trois boules
  • RL.pack();FI.pack_forget()
  • def go():
  • "Relancer le jeu"
  • global flag,figer
  • flag=1;figer=0
  • dx1,dy1,dx2,dy2,dx3,dy3=dxx1,dyy1,dxx2,dyy2,dxx3,dyy3 # récupération de la vitesse avant arrêt des trois boules
  • FI.pack();RL.pack_forget();RJ.pack_forget();PM.pack_forget()
  • move() # redémarrage du mouvement d'ensemble
  • ########## Commande "score" ##############################################
  • def score():
  • "Détermination du score"
  • global score1,score3,texte1S,texte1E,texte3S,texte3E,S1,S3,E1,E3
  • if B1==1:
  • if figer==1:RJ.pack_forget();PM.pack_forget()
  • else:
  • if point1==1:
  • S1=1;score1+=1 # Constat de succès : le score de B1 augmente d'un point
  • texte1S=can3.create_text(2*h/3,h/4,text='La BLANCHE continue\nou\nrejoue le coup',fill ="red",font ="Arial 8")
  • CT.pack();RJ.pack();FI.pack_forget()
  • if point1==0:
  • E1=1;score1+=0 # Constat d'échec
  • texte1E=can3.create_text(2*h/3,h/4,text='La BLANCHE rejoue le coup\nou\npasse la main',fill ="red",font ="Arial 8")
  • RJ.pack();PM.pack();FI.pack_forget()
  • if R1==1:score1+=-1
  • can.score1.config(text='%s'%score1)
  • if B3==1:
  • if figer==1:RJ.pack_forget();PM.pack_forget()
  • else:
  • if point3==1:
  • S3=1;score3+=1
  • texte3S=can3.create_text(2*h/3,h/4,text='La GRISE continue\nou\nrejoue le coup',fill ="red",font ="Arial 8")
  • CT.pack();RJ.pack();FI.pack_forget()
  • if point3==0:
  • E3=1;score3+=0
  • texte3E=can3.create_text(2*h/3,h/4,text='La GRISE rejoue le coup\nou\npasse la main',fill ="red",font ="Arial 8")
  • RJ.pack();PM.pack();FI.pack_forget()
  • if R3==1:score3+=-1
  • can.score3.config(text='%s'%score3)
  • ########## Fonction "mouvement" ##########################################
  • def move():
  • "mouvement des trois boules au fur et à mesure des chocs"
  • global flag
  • global x1,y1,x2,y2,x3,y3
  • global dx1,dy1,dx2,dy2,dx3,dy3
  • global c12,c23,c31,point1,point3
  • global T1,T3,RT1,RT3,RN1,RN3,rt
  • global sim1,sim3
  • x1,y1,x2,y2,x3,y3=x1+dx1,y1+dy1,x2+dx2,y2+dy2,x3+dx3,y3+dy3 # création du mouvement
  • dx1,dy1,dx2,dy2,dx3,dy3=k*dx1,k*dy1,k*dx2,k*dy2,k*dx3,k*dy3 # freinage du tapis (k)
  • if hypot(dx1,dy1)<s:dx1,dy1=0,0 # arrêt de B1 lorsque la vitesse de B1 devient trop faible (<s)
  • if hypot(dx2,dy2)<s:dx2,dy2=0,0 # idem B2
  • if hypot(dx3,dy3)<s:dx3,dy3=0,0 # idem B3
  • X12,Y12,X23,Y23,X31,Y31=x2-x1,y2-y1,x3-x2,y3-y2,x1-x3,y1-y3
  • Z12,Z23,Z31=hypot(X12,Y12),hypot(X23,Y23),hypot(X31,Y31)
  • dx12,dy12,dx23,dy23,dx31,dy31=dx2-dx1,dy2-dy1,dx3-dx2,dy3-dy2,dx1-dx3,dy1-dy3
  • dz12,dz23,dz31=hypot(dx12,dy12),hypot(dx23,dy23),hypot(dx31,dy31)
  • k12,K12,k23,K23,k31,K31=dz12*dz12,X12*dx12+Y12*dy12,dz23*dz23,X23*dx23+Y23*dy23,dz31*dz31,X31*dx31+Y31*dy31
  • u12,u23,u31=Z12-2*r,Z23-2*r,Z31-2*r
  • # Choc de B1 sur B2 :
  • if u12<=0: # la distance entre centres est <= à la somme des rayons
  • # algorithme de recul des deux boules :
  • c12+=1 # compteur de chocs B1/B2
  • m12=(K12+sqrt(K12*K12-k12*(Z12*Z12-4*r*r)))/k12
  • x1,y1,x2,y2=x1-m12*dx1,y1-m12*dy1,x2-m12*dx2,y2-m12*dy2 # recul des deux boules sur leurs directions initales
  • # algorithme de modification des vecteurs vitesse après le choc:
  • A12,B12,C12,D12=(X12*dx1+Y12*dy1)/Z12,(-Y12*dx1+X12*dy1)/Z12,(X12*dx2+Y12*dy2)/Z12,(-Y12*dx2+X12*dy2)/Z12
  • dx1,dy1,dx2,dy2=(-Y12*B12+X12*C12)/Z12,(X12*B12+Y12*C12)/Z12,(-Y12*D12+X12*A12)/Z12,(X12*D12+Y12*A12)/Z12
  • if T1==1 or T3==1 and RT1==0 and RN1 ==0:
  • effet_choc(dx1,dy1,dx2,dy2)
  • dx1,dy1,dx2,dy2=dxAE,dyAE,dxBE,dyBE # vitesse corrigée de l'effet
  • if B1==1 or B3==1 and c12==1:
  • hauteur(dxx1,dyy1,dxx2,dyy2) # vitesse corrigée de la hauteur de tir
  • dx1,dy1,dx2,dy2=dx1+dxACR,dy1+dyACR,dx2+dxBCR,dy2+dyBCR
  • # Choc de B2 sur B3 :
  • if u23<=0:
  • c23+=1 # compteur de chocs B2/B3
  • m23=(K23+sqrt(K23*K23-k23*(Z23*Z23-4*r*r)))/k23
  • x2,y2,x3,y3=x2-m23*dx2,y2-m23*dy2,x3-m23*dx3,y3-m23*dy3
  • A23,B23,C23,D23=(X23*dx2+Y23*dy2)/Z23,(-Y23*dx2+X23*dy2)/Z23,(X23*dx3+Y23*dy3)/Z23,(-Y23*dx3+X23*dy3)/Z23
  • effet_choc(dx2,dy2,dx3,dy3)
  • dx2,dy2,dx3,dy3=dxAE,dyAE,dxBE,dyBE
  • dx2,dy2,dx3,dy3=(-Y23*B23+X23*C23)/Z23,(X23*B23+Y23*C23)/Z23,(-Y23*D23+X23*A23)/Z23,(X23*D23+Y23*A23)/Z23
  • if B3==1 and c23==1:
  • hauteur(dxx3,dyy3,dxx2,dyy2)
  • dx3,dy3,dx2,dy2=dx3+dxACR,dy3+dyACR,dx2+dxBCR,dy2+dyBCR
  • # Choc de B3 sur B1 :
  • if u31<=0:
  • c31+=1 # compteur de chocs B3/B1
  • m31=(K31+sqrt(K31*K31-k31*(Z31*Z31-4*r*r)))/k31
  • x3,y3,x1,y1=x3-m31*dx3,y3-m31*dy3,x1-m31*dx1,y1-m31*dy1
  • A31,B31,C31,D31=(X31*dx3+Y31*dy3)/Z31,(-Y31*dx3+X31*dy3)/Z31,(X31*dx1+Y31*dy1)/Z31,(-Y31*dx1+X31*dy1)/Z31
  • dx3,dy3,dx1,dy1=(-Y31*B31+X31*C31)/Z31,(X31*B31+Y31*C31)/Z31,(-Y31*D31+X31*A31)/Z31,(X31*D31+Y31*A31)/Z31
  • if T3==1 or T1==1 and RT3==0 and RN3==0:
  • effet_choc(dx3,dy3,dx1,dy1)
  • dx3,dy3,dx1,dy1=dxAE,dyAE,dxBE,dyBE
  • if B3==1 or B3==1 and c31==1:
  • hauteur(dxx3,dyy3,dxx1,dyy1)
  • dx3,dy3,dx1,dy1=dx3+dxACR,dy3+dyACR,dx1+dxBCR,dy1+dyBCR
  • if c12*c31>0:point1=1 # succès=1 point
  • else:point1=0 # échec
  • if c23*c31>0:point3=1
  • else:point3=0
  • if x1>L-2*r or x1<0 or y1>H-2*r or y1<0: # Rebonds de la BLANCHE sur les bandes:
  • if T1==1 and c12==0 and c31==0:
  • rebond_tir(x1,y1,dx1,dy1)
  • x1,y1,dx1,dy1,RT1=xR,yR,dxR,dyR,RT
  • else :
  • rebond_normal(x1,y1,dx1,dy1)
  • x1,y1,dx1,dy1,RN1=xR,yR,dxR,dyR,RN
  • T1=0
  • if x2>L-2*r or x2<0 or y2>H-2*r or y2<0: # Rebonds de la ROUGE sur les bandes:
  • rebond_normal(x2,y2,dx2,dy2)
  • x2,y2,dx2,dy2=xR,yR,dxR,dyR
  • if x3>L-2*r or x3<0 or y3>H-2*r or y3<0: # Rebonds de la GRISE sur les bandes:
  • if T3==1 and c31==0 and c23==0:
  • rebond_tir(x3,y3,dx3,dy3)
  • x3,y3,dx3,dy3,RT3=xR,yR,dxR,dyR,RT
  • T3=0
  • else:
  • rebond_normal(x3,y3,dx3,dy3)
  • x3,y3,dx3,dy3,RN3=xR,yR,dxR,dyR,RN
  • Cboule(b1,x1,y1,r);Cboule(b2,x2,y2,r);Cboule(b3,x3,y3,r) # Nouvelles coordonnées de B1,B2,B3
  • CbouleS(b1S,x1,y1,RS);CbouleS(b2S,x2,y2,RS);CbouleS(b3S,x3,y3,RS)
  • if B1==1:sm(x1,y1,dx1,dy1);sim1=sim;can.itemconfig(sim1,fill='white')
  • if B3==1:sm(x3,y3,dx3,dy3);sim3=sim;can.itemconfig(sim3,fill='grey')
  • # Algorithmes à l'arrêt des trois boules
  • if flag==0:
  • c12+=-c12 # mise à zéro des compteurs de choc
  • c23+=-c23
  • c31+=-c31
  • score() # appel de la commande "score"
  • rt=0
  • if flag>0:
  • root.after(10,move) # déclenchement du mouvement des boules et des flèches
  • if dx1==0 and dy1==0 and dx2==0 and dy2==0 and dx3==0 and dy3==0:flag=0 # arrêt complet
  • ########## Procédures diverses ###########################################
  • def config_init():
  • "Mise en place de la configuration de départ (à partir des 'données initiales)"
  • global B1,B3,b1,b2,b3,b4,b5,b1S,b2S,b3S
  • B1,B3=1,0 # Sélection de la boule à tirer (B1)
  • boule(x1,y1,r,color='white');b1=b # Mise en place de B1
  • boule(x2,y2,r,color='red');b2=b # idem B2
  • boule(x3,y3,r,color='grey');b3=b # idem B3
  • bouleS(x1,y1,RS,color='white');b1S=bS # idem B1/Pupitre
  • bouleS(x2,y2,RS,color='red');b2S=bS # idem B2/Pupitre
  • bouleS(x3,y3,RS,color='grey');b3S=bS # idem B3/Pupitre
  • boule(x4,y4,R,color='blue');b4=b # Mise en place de la bille bleue commandant "effet" et "hauteur"
  • boule(x5,y5,R,color='dark green');b5=b # Mise en place du cercle des commandant "orientation" et "vitesse"
  • can.itemconfig(b5,outline='white') # couleur blanche pour le contour
  • can.itemconfig(curseur4,fill='blue') # couleur blanche pour le contour
  • can.itemconfig(curseur5,fill='white') # couleur blanche pour le contour
  • if B1==1:fl(flèche1,o,x1,y1) # Mise en place de la flèche liée à B1
  • if B3==1:fl(flèche3,o,x3,y3) # Mise en place de la flèche liée à B3
  • def config():
  • "Mise en place de la configuration courante"
  • Cboule(b1,x1,y1,r);Cboule(b2,x2,y2,r);Cboule(b3,x3,y3,r) # nouvelles coordonnées de B1,B2,B3
  • CbouleS(b1S,x1,y1,RS);CbouleS(b2S,x2,y2,RS);CbouleS(b3S,x3,y3,RS)# idem B1,B2,B3 /Pupitre
  • Cboule(b4,x4,y4,R);Cboule(b5,x5,y5,R) # idem bille bleue et cercle blanc
  • can.itemconfig(b4,fill='blue',outline='blue')
  • can.itemconfig(b5,outline='white')
  • can.itemconfig(curseur4,fill='blue')
  • can.itemconfig(curseur5,fill='white')
  • if continuer or passer:
  • wo=round(float(o*180/pi),1);can.orientation.config(text='%s'%wo)
  • wv=round(float(v),1);can.vitesse.config(text='%s'%wv)
  • we=round(float(e*180/pi),1);can.effet.config(text='%s'%we)
  • wha=round(float(ha),1);can.hauteur.config(text='%s'%wha)
  • can.coords(curseur4,L/8,H+h/2+R4,L/8,H+h/2-R4)
  • can.coords(curseur5,7*L/8-R,H+h/2,7*L/8-3*h/16+R/2,H+h/2)
  • if rejouer:
  • can.coords(curseur4,L/8+R4*cos(o4),H+h/2+R4*sin(o4),L/8-R4*cos(o4),H+h/2-R4*sin(o4))
  • can.coords(curseur5,7*L/8+R*cos(o),H+h/2-R*sin(o),x5+R-R*cos(o),y5+R+R*sin(o))
  • can.itemconfig(texte1,fill="white")
  • def effet_choc(dxA,dyA,dxB,dyB):
  • "Correction au choc pour tenir compte de l'effet latéral"
  • global dxAE,dyAE,dxBE,dyBE,e
  • e=(x4-L/8+R)*2/(R4-R)*pi/180
  • dxAE=dxA*cos(e)+dyA*sin(e)
  • dyAE=-dxA*sin(e)+dyA*cos(e)
  • dxBE=dxB*cos(e)+dyB*sin(e)
  • dyBE=-dxB*sin(e)+dyB*cos(e)
  • we=round(float(e*180/pi),1)
  • can.effet.config(text='%s'%we)
  • def hauteur(dxA,dyA,dxB,dyB):
  • "Correction au choc pour tenir compte de la hauteur du coup"
  • global dxACR,dyACR,dxBCR,dyBCR,ha
  • ha=-2*(y4-H-h/2+R)/(R4-R)
  • dxACR=dxA*ha/10
  • dyACR=dyA*ha/10
  • dxBCR=dxB*abs(ha/10)
  • dyBCR=dyB*abs(ha/10)
  • wha=round(float(ha),1)
  • can.hauteur.config(text='%s'%wha)
  • def rebond_tir(x,y,dx,dy):
  • "Rebond sur les bandes pour le premier tir"
  • global xR,yR,dxR,dyR,RT,rt
  • RT=1;rt+=1
  • if rt==1:m=(x4-L/8+R)*2/(R4-R)*(1+(v-1)/20)
  • else:m=0
  • if x>L-2*r: # bande droite
  • dxs,dys=dx+abs(m),dy+m
  • xR,yR,dxR,dyR=L-2*r,y,-dxs*hypot(dx,dy)/hypot(dxs,dys)*n,dys*hypot(dx,dy)/hypot(dxs,dys)*n
  • if y>H-2*r: # bande inférieure
  • dxs,dys=dx-m,dy+abs(m)
  • xR,yR,dxR,dyR=x,H-2*r,dxs*hypot(dx,dy)/hypot(dxs,dys)*n,-dys*hypot(dx,dy)/hypot(dxs,dys)*n
  • if x<0: # bande gauche
  • dxs,dys=dx-abs(m),dy-m
  • xR,yR,dxR,dyR=0,y,-dxs*hypot(dx,dy)/hypot(dxs,dys)*n,dys*hypot(dx,dy)/hypot(dxs,dys)*n
  • if y<0: # bande supérieure
  • dxs,dys=dx+m,dy+abs(m)
  • xR,yR,dxR,dyR=x,0,dxs*hypot(dx,dy)/hypot(dxs,dys)*n,-dys*hypot(dx,dy)/hypot(dxs,dys)*n
  • def rebond_normal(x,y,dx,dy):
  • "Rebond sur les bandes pour les coups suivants"
  • global xR,yR,dxR,dyR,RN
  • RN=1
  • if x>L-2*r:xR,yR,dxR,dyR=L-2*r,y,-dx*n,dy*n # bande droite
  • if y>H-2*r:xR,yR,dxR,dyR=x,H-2*r,dx*n,-dy*n # bande inférieur
  • if x<0:xR,yR,dxR,dyR=0,y,-dx*n,dy*n # bande gauche
  • if y<0:xR,yR,dxR,dyR=x,0,dx*n,-dy*n # bande supérieure
  • def fl(flèche,a,x,y):
  • "calcul de la longueur et mise en place de la flèche de tir"
  • global xf,yf,lf
  • SG=pi-atan(float(y+r)/float(x+r)) # le coin supérieur gauche du billard est vu par la boule sous l'angle SG
  • SD=atan(float(y+r)/float(L-x-r)) # le coin supérieur droit du billard est vu par la boule sous l'angle SD
  • ID=atan(-float(H-y-r)/float(L-x-r)) # le coin inférieur droit du billard est vu par la boule sous l'angle ID
  • IG=-pi-atan(-float(H-y-r)/float(x+r)) # le coin inférieur gauche du billard est vu par la boule sous l'angle IG
  • if a==0:lf=L-x-r # limitation de lf par la bande droite (cas limite)
  • if a==pi or a==-pi:lf=x+r # limitation de lf par la bande gauche (cas limite)
  • if a<SG and a>SD:lf=(y+r)/sin(a) # limitation de lf par la bande supérieure
  • if a<=SD and a>ID:lf=(L-x-r)/cos(a) # limitation de lf par la bande droite
  • if a<=ID and a>IG:lf=-(H-y-r)/sin(a) # limitation de lf par la bande inférieure
  • if a>=SG and a<pi:lf=-(x+r)/cos(a) # limitation de lf par la bande gauche
  • if a<IG and a>-pi:lf=-(x+r)/cos(a)
  • xf,yf=x+r+lf*cos(a),y+r-lf*sin(a) # extrémité de la flèche sur la bande
  • can.coords(flèche,x+r,y+r,xf,yf) # la flèche accompagne la boule pendant le déplacement
  • if B1==1:can.itemconfig(flèche,fill='white')
  • if B3==1:can.itemconfig(flèche,fill='grey')
  • def sm(x,y,dx,dy):
  • "Simulation du parcours de la boule tirée"
  • global sim
  • sim=can.create_line(3*h*x/2/L+L/2-3*h/4+RS,3*h*y/4/H+H+h/8+RS,3*h*(x+dx)/2/L+L/2-3*h/4+RS,3*h*(y+dy)/4/H+H+h/8+RS)
  • def effacer_simulation():
  • "effacer la trajectoire de la boule"
  • global b1S,b2S,b3S
  • REG66=can.create_rectangle(L/2-3*h/4,H+h/8,L/2+3*h/4,H+7*h/8,width=2,fill='dark green')
  • bouleS(x1,y1,RS,color='white');b1S=bS # remise en place de B1/Pupitre
  • bouleS(x2,y2,RS,color='red');b2S=bS # idem B2/Pupitre
  • bouleS(x3,y3,RS,color='grey');b3S=bS # idem B3/Pupitre
  • def effacer_texteR():
  • "Effacement des textes liés au résultat du tir"
  • can3.delete(texte1S);can3.delete(texte1E);can3.delete(texte3S);can3.delete(texte3E)
  • def boule(x,y,r,color):
  • "Coordonnées de la boule"
  • global b
  • b=can.create_oval(x,y,x+2*r,y+2*r,width=1,fill=color)
  • def Cboule(b,x,y,r):
  • "Coordonnées de la boule"
  • can.coords(b,x,y,x+2*r,y+2*r)
  • def bouleS(x,y,r,color):
  • "Coordonnées de la boule"
  • global bS
  • X,Y=3*h*x/2/L+L/2-3*h/4,3*h*y/4/H+H+h/8 # changement de système de coordonnées (billard vers simulation)
  • bS=can.create_oval(X,Y,X+2*RS,Y+2*RS,width=1,fill=color)
  • def CbouleS(bS,x,y,r):
  • "Coordonnées de la boule"
  • X,Y=3*h*x/2/L+L/2-3*h/4,3*h*y/4/H+H+h/8 # changement de système de coordonnées (billard vers simulation)
  • can.coords(bS,X,Y,X+2*RS,Y+2*RS)
  • def presentation():
  • "Fenêtre-message contenant la description sommaire du principe du jeu"
  • msg =Toplevel()
  • Message(msg, bg ="dark green", fg ="white", width =450,font ="Arial 8",
  • text =" PRESENTATION\n\n"\
  • "Au lancement du jeu, trois boules (BLANCHE, ROUGE et GRISE), apparaissent.La BLANCHE commence.\n\n"\
  • "La première étape, si l'on souhaite un jeu différent, consiste à déplacer les boules (abscisses et ordonnées), vers de nouvelles positions.\n\n"\
  • "La seconde vise à choisir la direction, la vitesse,l'effet latéral et la hauteur de tir de la boule BLANCHE.\n"\
  • "Une flèche de tir apparait, dont la longueur est ajustée aux dimensions du billard.\n\n"\
  • "Les boules étant en place, la touche <Tir !> met en mouvement la boule BLANCHE dans la direction choisie.\n"\
  • "Aux premiers chocs, les autres boules se mettent à leur tour en mouvement.\n"\
  • "La vitesse des boules se réduit à chaque itération, pour simuler le freinage du tapis, ainsi qu'à chaque choc (y/c avec les bandes).\n\n"\
  • "A l' arrêt des boules, le score de la boule BLANCHE est comptabilisé.\n"\
  • "En cas de succès, la BLANCHE gagne un point.Elle peut alors <Continuer !> ou <Rejouer le coup !> (pour améliorer les positions finales).\n"\
  • "En cas d' échec, elle peut aussi rejouer le coup,et, sinon, <Passer la main !> à la GRISE.\n\n"\
  • "La touche <Figer !> permet d'interrompre le mouvement à tout moment, et la touche <Relancer !> de le redémarrer.\n\n\n"\
  • "ALGORITHME\n\n"\
  • "Lorsque la boule BLANCHE approche, par exemple, de la boule GRISE, l'algorithme compare la distance entre leurs centres à la somme de leurs rayons.\n"\
  • "Quand l'écart devient négatif, il y a intersection des deux contours.\n\n"\
  • "L'algorithme calcule alors le recul en position des deux boules sur leurs directions initiales et en proportion de leurs vitesses, pour revenir au strict contact.\n\n"\
  • "La sortie du choc, en direction et en vitesse, se fait ensuite selon les lois de la mécanique des chocs inélastiques entre solides.\n"\
  • "Elle prend en compte (de façon très simplifiée) l'effet latéral et la hauteur de tir imprimés au moment du tir.\n\n"\
  • "Un coefficient (n) de réduction de la vitesse intervient à chaque choc, y/c avec les bandes.\n"
  • "Un ralentissement (k) a lieu également à chaque itération.\n").pack(padx =10, pady =10)
  • def processus():
  • ""
  • msg =Toplevel()
  • Message(msg, bg ="dark green", fg ="white", width =450,font ="Arial 8",
  • text="PROCESSUS à suivre\n\n"\
  • "1. Cliquer sur <Préparer le jeu !>\n\n"\
  • "2. Régler vitesse et orientation\n"\
  • "en déplaçant le cercle blanc\n"\
  • "(réglage fin par clics successifs)\n\n"\
  • "3. Régler effet latéral et hauteur\n"\
  • "en déplaçant la bille bleue\n\n"\
  • "4. Appuyer sur la touche <Tirer !>\n\n"\
  • "5. En cas de succès, <Continuer !>\n"\
  • "ou <Rejouer !> : pour améliorer\n\n"\
  • "6. Si échec, <Passer la main !>\n"\
  • "ou <Rejouer !>: pour réessayer\n\n"\
  • "7. Possibilité de <Figer !> le mouvement\n"\
  • "puis de <Relancer !>\n\n\n"\
  • "Echelle du jeu:\n"\
  • "Elle est peut être modifiée en\n"\
  • "intervenant dans le menu <Règle du jeu>.\n"\
  • "Valeurs possibles: de 0.5 à 1.0\n"\
  • "(valeur actuelle=0.5)\n").pack(padx =10, pady =10)
  • def aPropos():
  • "Fenêtre-message indiquant l'auteur"
  • msg =Toplevel()
  • Message(msg, width =200, aspect =100, justify =CENTER,
  • text ="Billard français \n\nHCD, Octobre 2005.\n"\
  • "Python version 2.4.2\nTk version 8.4").pack(padx =10, pady =10)
  • def scale(E):
  • "Changement d'échelle"
  • global L,H,h,r,rr,R,R4,R6,RS
  • global x1,y1,x2,y2,x3,y3
  • global x4o,y4o,x5o,y5o,x4,y4,x5,y5
  • E=float(E)
  • L,H,h,r,rr,R,R4,R6,RS=E*L,E*H,E*h,E*r,E*rr,E*R,E*R4,E*R6,E*RS
  • x1,y1,x2,y2,x3,y3=E*x1,E*y1,E*x2,E*y2,E*x3,E*y3
  • can.config(height=H+h,width=L)
  • can2.config(width=h)
  • can3.config(height=h/3,width=h)
  • x4o,y4o,x5o,y5o=E*x4o,E*y4o,E*x5o,E*y5o
  • x4,y4,x5,y5=E*x4,E*y4,E*x5,E*y5
  • can.coords(Pupitre,E*4,H,L,H+h)
  • can.coords(texte,E*L/2,E*L/3)
  • can.coords(t1,L/8,H+h-E*10)
  • can.coords(t2,L/2,H+h-E*10)
  • can.coords(t3,7*L/8,H+h-E*10)
  • can.coords(texte1,L/2,H+E*7.5)
  • can.coords(texte2,L/8,H+E*7.5)
  • can.coords(texte3,7*L/8,H+E*7.5)
  • can.coords(REG4,L/8-R4,H+h/2-R4,L/8+R4,H+h/2+R4)
  • can.coords(curseur4,L/8,H+h/2+R4,L/8,H+h/2-R4)
  • can.coords(REG6,L/2-3*h/4,H+h/8,L/2+3*h/4,H+7*h/8)
  • can.coords(REG5,7*L/8-R6,H+h/2-R6,7*L/8+R6,H+h/2+R6)
  • can.coords(REG5B,7*L/8-R,H+h/2-R,7*L/8+R,H+h/2+R)
  • can.coords(curseur5,7*L/8-R,H+h/2,7*L/8-3*h/16+R/2,H+h/2)
  • can.coords(pA,L/4-rr,H/2-rr,L/4+rr,H/2+rr)
  • can.coords(pB,L/2-rr,H/2-rr,L/2+rr,H/2+rr)
  • can.coords(pC,3*L/4-rr,H/2-rr,3*L/4+rr,H/2+rr)
  • can.coords(pD,3*L/4-rr,H/3-rr,3*L/4+rr,H/3+rr)
  • can.coords(pE,3*L/4-rr,2*H/3-rr,3*L/4+rr,2*H/3+rr)
  • can3.coords(texte1S,2*h/3,h/4)
  • can3.coords(texte1E,2*h/3,h/4)
  • can3.coords(texte3S,2*h/3,h/4)
  • can3.coords(texte3E,2*h/3,h/4)
  • EE=1.0
  • def echelle():
  • "Choix de l'échelle"
  • éch=Toplevel()
  • curE=Scale(éch,length=200,label="Echelle du jeu",orient=HORIZONTAL,from_=0.95,to=1.05,resolution=0.05,command=scale)
  • curE.set(1.0) # position initiale du curseur
  • curE.pack()
  • ######## Programme principal ############################################
  • # Création du widget principal :
  • root = Tk()
  • root.title('>>>>>>> BILLARD <<<<<<<')
  • # données initiales:
  • flag=0 # compteur
  • # Billard
  • L=600 # longueur du billard
  • H=L/2 # largeur du billard
  • r,rr=10,1 # rayons des boules et des marques du tapis
  • k,s=0.996,0.5 # coefficient de freinage du tapis, vitesse d'arrêt du mouvement
  • n=0.8 # coefficient de réduction de la vitesse lors d'un choc
  • x1,y1,x2,y2,x3,y3=3*L/4-r,H/2-r,L/2-r,H/2-r,L/4-r,H/2-r # coordonnées courantes des boules
  • dx1,dy1,dx2,dy2,dx3,dy3=0,0,0,0,0,0 # composantes courantes des vecteurs vitesse des boules
  • c12,c23,c31=0,0,0 # compteurs de choc
  • point1,point3,score1,score3=0,0,0,0 # compteurs de point et de score
  • R1,R3,T1,T3,PM1,PM3,CT1,CT3=0,0,0,0,0,0,0,0 # indicateurs (rejouer,tirer,passer la main,continuer)
  • RN1,RN3,RT1,RT3=0,0,0,0 # indicateurs de rebond sur les bandes et après choc
  • j,j1,j3,t1,t3,r1,r3,rt,t=0,0,0,0,0,0,0,0,0 # compteurs de lancements de jeux et de tirs
  • texte1E,texte1S,texte3E,texte3S=0,0,0,0
  • S1,S3,E1,E3=0,0,0,0 # résultats (S=succès,E=échec)
  • e,ha,o,v,o4=0,0,pi,8,pi/2 # réglages initiaux
  • figer=0
  • tA=0
  • # Pupitre de réglage du tir
  • h=H/2 # hauteur du pupitre de réglage
  • R,R4,R6,RS=4,25,3*h/8,3*h*r/4/H # rayons du système de réglage
  • x4o,y4o,x5o,y5o=L/8-R,H+h/2-R,7*L/8-3*h/16-3*R/2,H+h/2-R
  • x4,y4,x5,y5=L/8-R,H+h/2-R,7*L/8-3*h/16-3*R/2,H+h/2-R
  • # création des widgets "dépendants" :
  • can=Canvas(root,bg='dark green',height=H+h,width=L,highlightbackground='brown')
  • can.grid(row=1,column=0,rowspan=2)
  • can2=Canvas(root,bg='brown',highlightbackground='brown')
  • can2.grid(row=1,column=1,sticky=N)
  • can3=Canvas(root,bg='white',height=h/3,width=h)
  • can3.grid(row=2,column=1,padx=0,pady=0,ipadx=10,ipady=10,sticky=N+S)
  • # Pupitre de commande
  • Pupitre=can.create_rectangle(4,H,L,H+h,width=2,fill='brown')
  • t1=can.create_text(L/8,H+h-10,text='Effet et hauteur de tir',fill="white")
  • t2=can.create_text(L/2,H+h-10,text='Simulation',fill="white")
  • t3=can.create_text(7*L/8,H+h-10,text='Vitesse et orientation de tir',fill="white")
  • texte1=can.create_text(L/2,H+7.5,text='Régler le tir, puis "Tirer !"',fill="white")
  • texte2=can.create_text(L/8,H+7.5,text='Déplacer la bille bleue',fill="white")
  • texte3=can.create_text(7*L/8,H+7.5,text='Déplacer le cercle blanc',fill="white")
  • REG4=can.create_oval(L/8-R4,H+h/2-R4,L/8+R4,H+h/2+R4,width=1,fill='white')
  • curseur4=can.create_line(L/8,H+h/2+R4,L/8,H+h/2-R4,width=1,fill='white')
  • REG6=can.create_rectangle(L/2-3*h/4,H+h/8,L/2+3*h/4,H+7*h/8,width=2,fill='dark green')
  • REG5=can.create_oval(7*L/8-R6,H+h/2-R6,7*L/8+R6,H+h/2+R6,width=1,fill='dark green')
  • REG5B=can.create_oval(7*L/8-R,H+h/2-R,7*L/8+R,H+h/2+R,width=1,fill='white')
  • curseur5=can.create_line(7*L/8-R,H+h/2,7*L/8-3*h/16+R/2,H+h/2,width=1,fill='dark green',arrow=LAST)
  • # création des cinq points gris sur le tapis et des deux flèches
  • pA=can.create_oval(L/4-rr,H/2-rr,L/4+rr,H/2+rr,width=0,fill='light grey')
  • pB=can.create_oval(L/2-rr,H/2-rr,L/2+rr,H/2+rr,width=0, fill='light grey')
  • pC=can.create_oval(3*L/4-rr,H/2-rr,3*L/4+rr,H/2+rr,width=0,fill='light grey')
  • pD=can.create_oval(3*L/4-rr,H/3-rr,3*L/4+rr,H/3+rr,width=0,fill='light grey')
  • pE=can.create_oval(3*L/4-rr,2*H/3-rr,3*L/4+rr,2*H/3+rr,width=0,fill='light grey')
  • flèche1=can.create_line(0,0,0,0,arrow=LAST)
  • flèche3=can.create_line(0,0,0,0,arrow=LAST)
  • # Message d'introduction
  • texte=can.create_text(L/2,L/3,text='Cliquer sur le bouton "Règle du jeu"\n\nou\n\ndirectement sur "Préparer le jeu"',fill="white")
  • # Menu <Règle du jeu>
  • RdJ = Menubutton(can2, text ='Règle du jeu',height=2,width=25,relief=GROOVE,bg="dark green",fg="white")
  • RdJ.pack(padx=5,pady=5,side=BOTTOM,anchor=SW)
  • me1 = Menu(RdJ)
  • me1.add_command(label='Présentation',underline=0,command=presentation)
  • me1.add_command(label='Processus',underline=0,command=processus)
  • me1.add_command(label='Echelle',underline=0,command=echelle)
  • me1.add_command(label='A propos ...',underline=0,command=aPropos)
  • RdJ.configure(menu=me1)
  • # Affichage des réglages et des scores:
  • # hauteur:
  • can.hauteur=Label(can2,text='0',fg='white',bg='brown')
  • can.hauteur.pack(side=BOTTOM)
  • Label(can2,text="hauteur",fg='white',bg='brown').pack(side=BOTTOM)
  • # effet:
  • can.effet=Label(can2,text='0',fg='white',bg='brown')
  • can.effet.pack(side=BOTTOM)
  • Label(can2,text="effet",fg='white',bg='brown').pack(side=BOTTOM)
  • # vitesse:
  • can.vitesse=Label(can2,text='0',fg='white',bg='brown')
  • can.vitesse.pack(side=BOTTOM)
  • Label(can2,text="vitesse",fg='white',bg='brown').pack(side=BOTTOM)
  • # orientation:
  • can.orientation=Label(can2,text='0',fg='white',bg='brown')
  • can.orientation.pack(side=BOTTOM)
  • Label(can2,text="orientation",fg='white',bg='brown').pack(side=BOTTOM)
  • # Score B3:
  • can.score3=Label(can2,text='0',fg='white',bg='brown')
  • can.score3.pack(side=BOTTOM)
  • Label(can2,text="score GRISE",fg='white',bg='brown').pack(side=BOTTOM)
  • # Score B1:
  • can.score1=Label(can2,text='0',fg='white',bg='brown')
  • can.score1.pack(side=BOTTOM)
  • Label(can2,text="score BLANCHE",fg='white',bg='brown').pack(side=BOTTOM)
  • # Boutons de commande
  • # 'Continuer ?':
  • CT=Button(can2,text='Continuer? ',height=2,width=25,relief=GROOVE,bg="white",activebackground="dark green",activeforeground="white",command=continuer)
  • CT.pack(padx=5,pady=5,side=BOTTOM,anchor=SW)
  • CT.pack_forget()
  • # 'Passer la main ?':
  • PM=Button(can2,text='Passer la main? ',height=2,width=25,relief=GROOVE,bg="white",activebackground="dark green",activeforeground="white",command=passer)
  • PM.pack(padx=5,pady=5,side=BOTTOM,anchor=SW)
  • PM.pack_forget()
  • # 'Rejouer le coup ?':
  • RJ=Button(can2,text='Rejouer le coup ?',height=2,width=25,relief=GROOVE,bg="white",activebackground="dark green",activeforeground="white",command=rejouer)
  • RJ.pack(padx=5,pady=5,side=BOTTOM,anchor=SW)
  • RJ.pack_forget()
  • # bouton d'arrêt du mouvement:
  • FI=Button(can2,text='Figer le mouvement',height=2,width=25,relief=GROOVE,bg="white",activebackground="dark green",activeforeground="white",command=stop)
  • FI.pack(padx=5,pady=5,side=BOTTOM,anchor=SW)
  • FI.pack_forget()
  • # bouton de redémarrage du mouvement:
  • RL=Button(can2,text='Relancer le mouvement',height=2,width=25,relief=GROOVE,bg="white",activebackground="dark green",activeforeground="white",command=go)
  • RL.pack(padx=5,pady=5,side=BOTTOM,anchor=SW)
  • RL.pack_forget()
  • # 'Tirer !':
  • T=Button(can2,text='Tirer !',height=2,width=25,relief=GROOVE,bg="white",activebackground="dark green",activeforeground="white",command=tirer)
  • T.pack(padx=5,pady=5,side=BOTTOM,anchor=SW)
  • T.pack_forget()
  • # 'Préparer le tir !':
  • J=Button(can2,text='Préparer le jeu !',height=2,width=25,relief=GROOVE,bg="white",activebackground="dark green",activeforeground="white",command=jouer)
  • J.pack(padx=5,pady=5,side=BOTTOM,anchor=SW)
  • root.mainloop()
#! /usr/bin/env python
# -*- coding: Latin-1 -*-

# <<<     Billard     >>>

# REMERCIEMENTS : ce projet est très largement inspiré des exemples fournis par Mr Gérard Swinnen dans la deuxième édition de son ouvrage intitulé "Apprendre à programmer avec Python".


from Tkinter import *
from math import *

# CONVENTIONS
# boule BLANCHE....(coordonnées:x1,y1):B1  
# boule ROUGE......(coordonnées:x2,y2):B2
# boule GRISE......(coordonnées:x3,y3):B3
# bille bleue......(coordonnées:x4,y4):b4(Réglage de l'effet latéral et de la hauteur de tir)
# cercle blanc.....(coordonnées:x5,y5):b5(Réglage de l'orientation et de la vitesse de tir)
# pupitre de simulation : indice "S"

########## Commande "préparer le jeu" ####################################

def jouer():
    "Préparer le jeu"
    global flag,texte
    if flag==0:flag=1
    jouer;config_init()                                         # mise en place de la configuration initiale (boules,flèches,réglages)
    can.bind("<Button-1>", mouseDown)                           # commandes avec le clic gauche de la souris
    can.bind("<Button1-Motion>", mouseMove)
    can.bind("<Button1-ButtonRelease>", mouseUp)
    T.pack(),J.pack_forget()                                    # gestion des boutons de commande
    can.delete(texte)

########## Commandes de réglage du tir ###################################

def mouseDown( event):
    "Opérations à effectuer quand le bouton gauche de la souris est enfoncé"
    global selObject,X,Y,x5,y5,v,o
    can.currObject=None
    X,Y=event.x,event.y                                         # coordonnées du clic                                        
    D1=hypot(X-x1-r,Y-y1-r)                                     # distance entre le clic et le centre de B1
    D2=hypot(X-x2-r,Y-y2-r)                                     # idem B2
    D3=hypot(X-x3-r,Y-y3-r)                                     # idem B3
    D4=hypot(X-x4-R,Y-y4-R)                                     # idem bille bleue
    D5=hypot(X-x5-R,Y-y5-R)                                     # idem cercle blanc
    X5,Y5=x5-7L/8+R,y5-H-h/2+R
    H5=hypot(X5,Y5)
    if D1<r:selObject=b1                                        # sélection de B1 si le clic est à l'intérieur de B1
    if D2<r:selObject=b2                                        # idem B2
    if D3<r:selObject=b3                                        # idem B3
    if D4<R:selObject=b4                                        # idem bille bleue
    if D5<4*R:selObject=b5                                      # plage de sélection du cercle blanc: cercle de rayon 4R
    if selObject==b5:                                           # procédure de réglage fin, par clic sussessifs à proximité
        dx,dy=(X-x5-R)/40,(Y-y5-R)/40                           # pas = 1/40 ème de la distance du clic au centre du cercle
        x5,y5=x5+dx,y5+dy
        can.move(selObject,dx,dy)                               # déplacement du cercle blanc   
        C5=can.coords(b5)                               
        x5,y5=C5[0],C5[1]
        o=-atan2(y5-H-h/2+R,x5-7*L/8+R)                         # récupération de l'angle de tir (o)       
        wo=round(float(o*180/pi),1)
        can.orientation.config(text='%s'%wo)                    # valeur d'affichage de (o)
        v=1+14*hypot(x5+R-7*L/8-2*R*cos(o),y5+R-H-h/2+2*R*sin(o))/(3*h/8-3*R) # récupération de la vitessede tir (v)
        wv=round(float(v),1)
        can.vitesse.config(text='%s'%wv)                        # valeur d'affichage de (v)
        if B1==1:fl(flèche1,o,x1,y1)
        if B3==1:fl(flèche3,o,x3,y3)
        can.coords(curseur5,7*L/8+R*cos(o),H+h/2-R*sin(o),x5+R-R*cos(o),y5+R+R*sin(o))
    can.itemconfig(selObject,width=2)                           # le contour de l'objet sélectionné double d'épaisseur

def mouseMove(event):
    "Opérations à effectuer quand la souris se déplace, bouton gauche enfoncé"
    global O,X,Y
    global x1,y1,x2,y2,x3,y3,x4,y4,x5,y5                          
    global e,ha,v,o,o4
    XX,YY=event.x,event.y
    dx,dy=XX-X,YY-Y
    if selObject==b1:  
        if dx+x1>0 and dx+x1<L-2*r and dy+y1>0 and dy+y1<H-2*r:
            can.move(selObject,dx,dy);X,Y=XX,YY                 # déplacement de B1
            C1=can.coords(b1)                                   
            x1,y1=C1[0],C1[1]                                   # récupération des coordonnées du coin supérieur gauche
            if B1==1:fl(flèche1,pi,x1,y1)                       # déplacement de la flèche de B1
    if selObject==b2 :
        if dx+x2>0 and dx+x2<L-2*r and dy+y2>0 and dy+y2<H-2*r:
            can.move(selObject,dx,dy);X,Y=XX,YY                 # déplacement de B2
            C2=can.coords(b2)                                   
            x2,y2=C2[0],C2[1]
    if selObject==b3 :
        if dx+x3>0 and dx+x3<L-2*r and dy+y3>0 and dy+y3<H-2*r:
            can.move(selObject,dx,dy);X,Y=XX,YY                 # déplacement de B3
            C3=can.coords(b3)                                   
            x3,y3=C3[0],C3[1]
            if B3==1:fl(flèche3,pi,x3,y3)                       # déplacement de la flèche de B3
    if selObject==b4: 
        DX4,DY4=dx+x4-L/8+R,dy+y4-H-h/2+R
        HD4=hypot(DX4,DY4)
        if HD4<R4-R:
            can.move(selObject,dx,dy);X,Y=XX,YY                 # déplacement de la bille bleue 
            C4=can.coords(b4)                               
            x4,y4=C4[0],C4[1]
            o4=atan2(DY4,DX4)
            e=(x4-L/8+R)*2/(R4-R)*pi/180                        # calcul de l'effet (-2<e<+2)
            we=round(float(e*180/pi),1);can.effet.config(text='%s'%we)
            ha=-2*(y4-H-h/2+R)/(R4-R)                           # calcul de la hauteur (-2<h<+2)
            wha=round(float(ha),1);can.hauteur.config(text='%s'%wha)
            can.coords(curseur4,L/8+R4*cos(o4),H+h/2+R4*sin(o4),L/8-R4*cos(o4),H+h/2-R4*sin(o4))
    if selObject==b5: 
        DX5,DY5=dx+x5-7*L/8+R,dy+y5-H-h/2+R
        HD5=hypot(DX5,DY5)
        if HD5<3*h/8-R and HD5>2*R:
            can.move(selObject,dx,dy);X,Y=XX,YY                 # déplacement du cercle blanc dans l'espace d'orientation et de vitesse
            C5=can.coords(b5)                               
            x5,y5=C5[0],C5[1]
            o=-atan2(y5-H-h/2+R,x5-7*L/8+R)                     # récupération de l'angle de tir (o)       
            wo=round(float(o*180/pi),1)
            can.orientation.config(text='%s'%wo)
            v=1+14*hypot(x5+R-7*L/8-2*R*cos(o),y5+R-H-h/2+2*R*sin(o))/(3*h/8-3*R)# récupération de la vitesse de tir (v)
            wv=round(float(v),1)
            can.vitesse.config(text='%s'%wv)
            can.coords(curseur5,7*L/8+R*cos(o),H+h/2-R*sin(o),x5+R-R*cos(o),y5+R+R*sin(o))
            if B1==1:fl(flèche1,o,x1,y1)
            if B3==1:fl(flèche3,o,x3,y3)

def mouseUp(event):
    "Opérations à effectuer quand le bouton gauche de la souris est relâché"
    global selObject
    can.itemconfig(selObject,width=1)                           # le contour de l'objet sélectionné revient à son épaisseur initiale
    if selObject==b1:selObject=None
    if selObject==b2:selObject=None
    if selObject==b3:selObject=None
    if selObject==b4:selObject=None
    if selObject==b5:selObject=None

########## Commande "tirer" ##############################################    
 
def tirer():
    "tirer "
    global T1,T3,t1,t3,S1,S3,E1,E3,R1,R3,PM1,PM3
    global x1,y1,x3,y3,dx1,dy1,dx3,dy3                       
    global xx1,yy1,xx2,yy2,xx3,yy3
    global dxx1,dyy1,dxx2,dyy2,dxx3,dyy3
    global xx4,yy4,xx5,yy5
    global ee,hh,oo,vv,oo4
    if B1==1:                  
        T1=1;t1+=1                                              # indicateur et compteur de tir
        dx1,dy1=v*cos(o),-v*sin(o)                              # coordonnées du vecteur vitesse
        can.coords(flèche1,x1+r,y1+r,x1+r,y1+r)                 # origine de la flèche
        can.itemconfig(b4,fill='white',outline='white')         # effacement de la bille bleue
        can.itemconfig(curseur4,fill='white')                   # effacement du diamètre de la bille bleue
    if B3==1:                                                   
        T3=1;t3+=1
        dx3,dy3=v*cos(o),-v*sin(o)
        can.coords(flèche3,x3+r,y3+r,x3+r,y3+r)                 # idem
        can.itemconfig(b4,fill='grey',outline='grey')           # idem
        can.itemconfig(curseur4,fill='grey')
    xx1,yy1,xx2,yy2,xx3,yy3=x1,y1,x2,y2,x3,y3                   # mémorisation de la position des trois boules
    dxx1,dyy1,dxx2,dyy2,dxx3,dyy3=dx1,dy1,dx2,dy2,dx3,dy3       # mémorisation de la vitesse des trois boules
    xx4,yy4,xx5,yy5=x4,y4,x5,y5                                 # mémorisation de la position de la bille et du cercle
    ee,hh,oo,vv,oo4=e,ha,o,v,o4                                 # mémorisation des réglages du tir
    S1,S3,E1,E3,R1,R3,PM1,PM3,CT1,CT3=0,0,0,0,0,0,0,0,0,0       # mise à zéro des indicateurs
    T.pack_forget();FI.pack()                                   # gestion des boutons de commande
    can.itemconfig(texte1,fill="brown")
    can.delete(texte2);can.delete(texte3)
    can.itemconfig(b5,outline='dark green')                     # effacement du cercle blanc
    can.itemconfig(curseur5,fill='dark green')                  # effacement de la flèche
    move()                                                      # appel de la fonction "mouvement" des boules
                       
###### Commandes "continuer/rejouer/passer la main/figer/relancer" #######    

def continuer():
    "continuer"
    global flag,CT1,CT3,B1,B3
    global x1,y1,x2,y2,x3,y3,x4,y4,x5,y5
    global e,ha,o,v,o4,o6                            
    if flag==0:flag=1
    e,ha,o,v,o4=0,0,pi,8,pi/2                                   # réglages de départ
    x4,y4,x5,y5=x4o,y4o,x5o,y5o                                 # coordonnées de départ de la bille et du cercle
    effacer_simulation()
    continuer;config()                                          # mise en place de la configuration
    if S1==1:CT1=1;B1,B3=1,0;fl(flèche1,o,x1,y1)            
    if S3==1:CT3=1;B1,B3=0,1;fl(flèche3,o,x3,y3)
    T.pack();CT.pack_forget();RJ.pack_forget()
    effacer_texteR() 
    
def rejouer():
    "rejouer le coup"
    global flag,R1,R3,r1,r3
    global x1,y1,x2,y2,x3,y3
    global e,ha,o,v,o4                                  
    if flag==0:flag=1
    e,ha,o,v,o4 =ee,hh,oo,vv,oo4                                # récupération des réglages avant tir
    x1,y1,x2,y2,x3,y3=xx1,yy1,xx2,yy2,xx3,yy3                   # récupération des positions avant tir des boules 
    x4,y4,x5,y5=xx4,yy4,xx5,yy5                                 # récupération des positions avant tir de la bille et du cercle
    rejouer;config()                                            # mise en place de la configuration
    if B1==1 :R1=1;fl(flèche1,o,x1,y1);r1+=1                  
    if B3==1 :R3=1;fl(flèche3,o,x3,y3);r3+=1
    T.pack();RJ.pack_forget();PM.pack_forget();CT.pack_forget()
    effacer_texteR() 

def passer():
    "passer la main"
    global flag,PM1,PM3,B1,B3
    global x1,y1,x2,y2,x3,y3,x4,y4,x5,y5
    global e,ha,o,v,o4                                  
    if flag==0:flag=1
    e,ha,o,v,o4=0,0,pi,8,pi/2                                   # réglages de départ
    x4,y4,x5,y5=x4o,y4o,x5o,y5o                                 # coordonnées de départ de la bille et du cercle
    effacer_simulation()
    passer;config()                                             # mise en place de la configuration
    if E1==1:PM1=1;B1,B3=0,1;fl(flèche3,o,x3,y3)                # changement de boule (B3 prend la main)
    if E3==1:PM3=1;B1,B3=1,0;fl(flèche1,o,x1,y1)
    if B3==1:can.itemconfig(REG4,fill='grey');can.itemconfig(REG5B,fill='grey')
    if B1==1:can.itemconfig(REG4,fill='white');can.itemconfig(REG5B,fill='white')
    T.pack();RJ.pack_forget();PM.pack_forget();CT.pack_forget()
    effacer_texteR() 

def stop():
    "Figer le jeu"
    global flag,figer
    figer=1;flag=0
    dxx1,dyy1,dxx2,dyy2,dxx3,dyy3=dx1,dy1,dx2,dy2,dx3,dy3       # mémorisation de la vitesse des trois boules
    RL.pack();FI.pack_forget()

def go():
    "Relancer le jeu"
    global flag,figer
    flag=1;figer=0
    dx1,dy1,dx2,dy2,dx3,dy3=dxx1,dyy1,dxx2,dyy2,dxx3,dyy3       # récupération de la vitesse  avant arrêt des trois boules
    FI.pack();RL.pack_forget();RJ.pack_forget();PM.pack_forget()
    move()                                                      # redémarrage du mouvement d'ensemble

########## Commande "score" ##############################################

def score():
    "Détermination du score" 
    global score1,score3,texte1S,texte1E,texte3S,texte3E,S1,S3,E1,E3
    if B1==1:
        if figer==1:RJ.pack_forget();PM.pack_forget()
        else:
            if point1==1:                                                
                S1=1;score1+=1                                  # Constat de succès : le score de B1 augmente d'un point
                texte1S=can3.create_text(2*h/3,h/4,text='La BLANCHE continue\nou\nrejoue le coup',fill ="red",font ="Arial 8")
                CT.pack();RJ.pack();FI.pack_forget()
            if point1==0:                                              
                E1=1;score1+=0                                  # Constat d'échec                                               
                texte1E=can3.create_text(2*h/3,h/4,text='La BLANCHE rejoue le coup\nou\npasse la main',fill ="red",font ="Arial 8")
                RJ.pack();PM.pack();FI.pack_forget()
                if R1==1:score1+=-1
            can.score1.config(text='%s'%score1) 
            
    if B3==1:
        if figer==1:RJ.pack_forget();PM.pack_forget()
        else:
            if point3==1:                               
                S3=1;score3+=1  
                texte3S=can3.create_text(2*h/3,h/4,text='La GRISE continue\nou\nrejoue le coup',fill ="red",font ="Arial 8")
                CT.pack();RJ.pack();FI.pack_forget()             
            if point3==0:                              
                E3=1;score3+=0  
                texte3E=can3.create_text(2*h/3,h/4,text='La GRISE rejoue le coup\nou\npasse la main',fill ="red",font ="Arial 8")
                RJ.pack();PM.pack();FI.pack_forget()
                if R3==1:score3+=-1
            can.score3.config(text='%s'%score3)
       

########## Fonction "mouvement" ##########################################

def move():
    "mouvement des trois boules au fur et à mesure des chocs"
    global flag
    global x1,y1,x2,y2,x3,y3
    global dx1,dy1,dx2,dy2,dx3,dy3
    global c12,c23,c31,point1,point3
    global T1,T3,RT1,RT3,RN1,RN3,rt
    global sim1,sim3

    x1,y1,x2,y2,x3,y3=x1+dx1,y1+dy1,x2+dx2,y2+dy2,x3+dx3,y3+dy3 # création du mouvement
    dx1,dy1,dx2,dy2,dx3,dy3=k*dx1,k*dy1,k*dx2,k*dy2,k*dx3,k*dy3 # freinage du tapis (k)

    if hypot(dx1,dy1)<s:dx1,dy1=0,0                             # arrêt de B1 lorsque la vitesse de B1 devient trop faible (<s)
    if hypot(dx2,dy2)<s:dx2,dy2=0,0                             # idem B2
    if hypot(dx3,dy3)<s:dx3,dy3=0,0                             # idem B3 
                                                                
    X12,Y12,X23,Y23,X31,Y31=x2-x1,y2-y1,x3-x2,y3-y2,x1-x3,y1-y3
    Z12,Z23,Z31=hypot(X12,Y12),hypot(X23,Y23),hypot(X31,Y31)
    dx12,dy12,dx23,dy23,dx31,dy31=dx2-dx1,dy2-dy1,dx3-dx2,dy3-dy2,dx1-dx3,dy1-dy3
    dz12,dz23,dz31=hypot(dx12,dy12),hypot(dx23,dy23),hypot(dx31,dy31)
    k12,K12,k23,K23,k31,K31=dz12*dz12,X12*dx12+Y12*dy12,dz23*dz23,X23*dx23+Y23*dy23,dz31*dz31,X31*dx31+Y31*dy31 
    u12,u23,u31=Z12-2*r,Z23-2*r,Z31-2*r

    # Choc de B1 sur B2 :    
    if u12<=0:                                                  # la distance entre centres est <= à la somme des rayons
        # algorithme de recul des deux boules :
        c12+=1                                                  # compteur de chocs B1/B2
        m12=(K12+sqrt(K12*K12-k12*(Z12*Z12-4*r*r)))/k12                   
        x1,y1,x2,y2=x1-m12*dx1,y1-m12*dy1,x2-m12*dx2,y2-m12*dy2 # recul des deux boules sur leurs directions initales
        # algorithme de modification des vecteurs vitesse après le choc:
        A12,B12,C12,D12=(X12*dx1+Y12*dy1)/Z12,(-Y12*dx1+X12*dy1)/Z12,(X12*dx2+Y12*dy2)/Z12,(-Y12*dx2+X12*dy2)/Z12
        dx1,dy1,dx2,dy2=(-Y12*B12+X12*C12)/Z12,(X12*B12+Y12*C12)/Z12,(-Y12*D12+X12*A12)/Z12,(X12*D12+Y12*A12)/Z12
        if T1==1 or T3==1 and RT1==0 and RN1 ==0:
            effet_choc(dx1,dy1,dx2,dy2)
            dx1,dy1,dx2,dy2=dxAE,dyAE,dxBE,dyBE                 # vitesse corrigée de l'effet
        if B1==1 or B3==1 and c12==1:
            hauteur(dxx1,dyy1,dxx2,dyy2)                        # vitesse corrigée de la hauteur de tir
            dx1,dy1,dx2,dy2=dx1+dxACR,dy1+dyACR,dx2+dxBCR,dy2+dyBCR
    # Choc de B2 sur B3 :    
    if u23<=0:
        c23+=1                                                  # compteur de chocs B2/B3
        m23=(K23+sqrt(K23*K23-k23*(Z23*Z23-4*r*r)))/k23       
        x2,y2,x3,y3=x2-m23*dx2,y2-m23*dy2,x3-m23*dx3,y3-m23*dy3
        A23,B23,C23,D23=(X23*dx2+Y23*dy2)/Z23,(-Y23*dx2+X23*dy2)/Z23,(X23*dx3+Y23*dy3)/Z23,(-Y23*dx3+X23*dy3)/Z23
        effet_choc(dx2,dy2,dx3,dy3)
        dx2,dy2,dx3,dy3=dxAE,dyAE,dxBE,dyBE
        dx2,dy2,dx3,dy3=(-Y23*B23+X23*C23)/Z23,(X23*B23+Y23*C23)/Z23,(-Y23*D23+X23*A23)/Z23,(X23*D23+Y23*A23)/Z23    
        if B3==1 and c23==1:
            hauteur(dxx3,dyy3,dxx2,dyy2)
            dx3,dy3,dx2,dy2=dx3+dxACR,dy3+dyACR,dx2+dxBCR,dy2+dyBCR
    # Choc de B3 sur B1 :   
    if u31<=0:
        c31+=1                                                  # compteur de chocs B3/B1
        m31=(K31+sqrt(K31*K31-k31*(Z31*Z31-4*r*r)))/k31      
        x3,y3,x1,y1=x3-m31*dx3,y3-m31*dy3,x1-m31*dx1,y1-m31*dy1
        A31,B31,C31,D31=(X31*dx3+Y31*dy3)/Z31,(-Y31*dx3+X31*dy3)/Z31,(X31*dx1+Y31*dy1)/Z31,(-Y31*dx1+X31*dy1)/Z31
        dx3,dy3,dx1,dy1=(-Y31*B31+X31*C31)/Z31,(X31*B31+Y31*C31)/Z31,(-Y31*D31+X31*A31)/Z31,(X31*D31+Y31*A31)/Z31
        if T3==1 or T1==1 and RT3==0 and RN3==0:
            effet_choc(dx3,dy3,dx1,dy1)
            dx3,dy3,dx1,dy1=dxAE,dyAE,dxBE,dyBE
        if B3==1 or B3==1 and c31==1:
            hauteur(dxx3,dyy3,dxx1,dyy1)
            dx3,dy3,dx1,dy1=dx3+dxACR,dy3+dyACR,dx1+dxBCR,dy1+dyBCR
      
    if c12*c31>0:point1=1                                       # succès=1 point 
    else:point1=0                                               # échec
    if c23*c31>0:point3=1                                      
    else:point3=0                                               
    
    if x1>L-2*r or x1<0 or y1>H-2*r or y1<0:                    # Rebonds de la BLANCHE sur les bandes: 
        if T1==1 and c12==0 and c31==0:
            rebond_tir(x1,y1,dx1,dy1)
            x1,y1,dx1,dy1,RT1=xR,yR,dxR,dyR,RT
        else :
            rebond_normal(x1,y1,dx1,dy1)
            x1,y1,dx1,dy1,RN1=xR,yR,dxR,dyR,RN
            T1=0
    if x2>L-2*r or x2<0 or y2>H-2*r or y2<0:                    # Rebonds de la ROUGE sur les bandes:  
        rebond_normal(x2,y2,dx2,dy2)
        x2,y2,dx2,dy2=xR,yR,dxR,dyR
    if x3>L-2*r or x3<0 or y3>H-2*r or y3<0:                    # Rebonds de la GRISE sur les bandes:   
        if T3==1 and c31==0 and c23==0:
            rebond_tir(x3,y3,dx3,dy3)
            x3,y3,dx3,dy3,RT3=xR,yR,dxR,dyR,RT
            T3=0
        else:
            rebond_normal(x3,y3,dx3,dy3)
            x3,y3,dx3,dy3,RN3=xR,yR,dxR,dyR,RN

    Cboule(b1,x1,y1,r);Cboule(b2,x2,y2,r);Cboule(b3,x3,y3,r)    # Nouvelles coordonnées de B1,B2,B3
    CbouleS(b1S,x1,y1,RS);CbouleS(b2S,x2,y2,RS);CbouleS(b3S,x3,y3,RS)

    if B1==1:sm(x1,y1,dx1,dy1);sim1=sim;can.itemconfig(sim1,fill='white')
    if B3==1:sm(x3,y3,dx3,dy3);sim3=sim;can.itemconfig(sim3,fill='grey')

    # Algorithmes à l'arrêt des trois boules
    if flag==0:
        c12+=-c12                                               # mise à zéro des compteurs de choc
        c23+=-c23
        c31+=-c31
        score()                                                 # appel de la commande "score"
        rt=0
    if flag>0:
        root.after(10,move)                                      # déclenchement du mouvement des boules et des flèches       
    if dx1==0 and dy1==0 and dx2==0 and dy2==0 and dx3==0 and dy3==0:flag=0     # arrêt complet
        
########## Procédures diverses ###########################################

def config_init():
    "Mise en place de la configuration de départ (à partir des 'données initiales)"
    global B1,B3,b1,b2,b3,b4,b5,b1S,b2S,b3S
    B1,B3=1,0                                                   # Sélection de la boule à tirer (B1)
    boule(x1,y1,r,color='white');b1=b                           # Mise en place de B1
    boule(x2,y2,r,color='red');b2=b                             # idem B2
    boule(x3,y3,r,color='grey');b3=b                            # idem B3
    bouleS(x1,y1,RS,color='white');b1S=bS                       # idem B1/Pupitre
    bouleS(x2,y2,RS,color='red');b2S=bS                         # idem B2/Pupitre
    bouleS(x3,y3,RS,color='grey');b3S=bS                        # idem B3/Pupitre
    boule(x4,y4,R,color='blue');b4=b                            # Mise en place de la bille bleue commandant "effet" et "hauteur"
    boule(x5,y5,R,color='dark green');b5=b                      # Mise en place du cercle des commandant "orientation" et "vitesse"
    can.itemconfig(b5,outline='white')                          # couleur blanche pour le contour
    can.itemconfig(curseur4,fill='blue')                        # couleur blanche pour le contour
    can.itemconfig(curseur5,fill='white')                       # couleur blanche pour le contour

    if B1==1:fl(flèche1,o,x1,y1)                                # Mise en place de la flèche liée à B1
    if B3==1:fl(flèche3,o,x3,y3)                                # Mise en place de la flèche liée à B3

def config():
    "Mise en place de la configuration courante"
    Cboule(b1,x1,y1,r);Cboule(b2,x2,y2,r);Cboule(b3,x3,y3,r)    # nouvelles coordonnées de B1,B2,B3
    CbouleS(b1S,x1,y1,RS);CbouleS(b2S,x2,y2,RS);CbouleS(b3S,x3,y3,RS)# idem B1,B2,B3 /Pupitre
    Cboule(b4,x4,y4,R);Cboule(b5,x5,y5,R)                       # idem bille bleue et cercle blanc
    can.itemconfig(b4,fill='blue',outline='blue')
    can.itemconfig(b5,outline='white')
    can.itemconfig(curseur4,fill='blue')
    can.itemconfig(curseur5,fill='white')
    if continuer or passer:
        wo=round(float(o*180/pi),1);can.orientation.config(text='%s'%wo)
        wv=round(float(v),1);can.vitesse.config(text='%s'%wv)
        we=round(float(e*180/pi),1);can.effet.config(text='%s'%we)
        wha=round(float(ha),1);can.hauteur.config(text='%s'%wha)
        can.coords(curseur4,L/8,H+h/2+R4,L/8,H+h/2-R4)
        can.coords(curseur5,7*L/8-R,H+h/2,7*L/8-3*h/16+R/2,H+h/2)
    if rejouer:
        can.coords(curseur4,L/8+R4*cos(o4),H+h/2+R4*sin(o4),L/8-R4*cos(o4),H+h/2-R4*sin(o4))
        can.coords(curseur5,7*L/8+R*cos(o),H+h/2-R*sin(o),x5+R-R*cos(o),y5+R+R*sin(o))
    can.itemconfig(texte1,fill="white")

def effet_choc(dxA,dyA,dxB,dyB):
    "Correction au choc pour tenir compte de l'effet latéral"
    global dxAE,dyAE,dxBE,dyBE,e
    e=(x4-L/8+R)*2/(R4-R)*pi/180
    dxAE=dxA*cos(e)+dyA*sin(e)
    dyAE=-dxA*sin(e)+dyA*cos(e)
    dxBE=dxB*cos(e)+dyB*sin(e)
    dyBE=-dxB*sin(e)+dyB*cos(e)
    we=round(float(e*180/pi),1)
    can.effet.config(text='%s'%we)

def hauteur(dxA,dyA,dxB,dyB):
    "Correction au choc pour tenir compte de la hauteur du coup"
    global dxACR,dyACR,dxBCR,dyBCR,ha
    ha=-2*(y4-H-h/2+R)/(R4-R)
    dxACR=dxA*ha/10
    dyACR=dyA*ha/10
    dxBCR=dxB*abs(ha/10)
    dyBCR=dyB*abs(ha/10)
    wha=round(float(ha),1)
    can.hauteur.config(text='%s'%wha)
    
def rebond_tir(x,y,dx,dy):
    "Rebond sur les bandes pour le premier tir"
    global xR,yR,dxR,dyR,RT,rt
    RT=1;rt+=1
    if rt==1:m=(x4-L/8+R)*2/(R4-R)*(1+(v-1)/20)
    else:m=0
    if x>L-2*r:                                                 # bande droite
        dxs,dys=dx+abs(m),dy+m
        xR,yR,dxR,dyR=L-2*r,y,-dxs*hypot(dx,dy)/hypot(dxs,dys)*n,dys*hypot(dx,dy)/hypot(dxs,dys)*n
    if y>H-2*r:                                                 # bande inférieure
        dxs,dys=dx-m,dy+abs(m)
        xR,yR,dxR,dyR=x,H-2*r,dxs*hypot(dx,dy)/hypot(dxs,dys)*n,-dys*hypot(dx,dy)/hypot(dxs,dys)*n
    if x<0:                                                     # bande gauche
        dxs,dys=dx-abs(m),dy-m
        xR,yR,dxR,dyR=0,y,-dxs*hypot(dx,dy)/hypot(dxs,dys)*n,dys*hypot(dx,dy)/hypot(dxs,dys)*n
    if y<0:                                                     # bande supérieure
        dxs,dys=dx+m,dy+abs(m)
        xR,yR,dxR,dyR=x,0,dxs*hypot(dx,dy)/hypot(dxs,dys)*n,-dys*hypot(dx,dy)/hypot(dxs,dys)*n

def rebond_normal(x,y,dx,dy):    
    "Rebond sur les bandes pour les coups suivants"
    global xR,yR,dxR,dyR,RN
    RN=1
    if x>L-2*r:xR,yR,dxR,dyR=L-2*r,y,-dx*n,dy*n                 # bande droite
    if y>H-2*r:xR,yR,dxR,dyR=x,H-2*r,dx*n,-dy*n                 # bande inférieur
    if x<0:xR,yR,dxR,dyR=0,y,-dx*n,dy*n                         # bande gauche
    if y<0:xR,yR,dxR,dyR=x,0,dx*n,-dy*n                         # bande supérieure

def fl(flèche,a,x,y):
    "calcul de la longueur et mise en place de la flèche de tir"
    global xf,yf,lf                                                  
    SG=pi-atan(float(y+r)/float(x+r))                           # le coin supérieur gauche du billard est vu par la boule sous l'angle SG 
    SD=atan(float(y+r)/float(L-x-r))                            # le coin supérieur droit du billard est vu par la boule sous l'angle SD
    ID=atan(-float(H-y-r)/float(L-x-r))                         # le coin inférieur droit du billard est vu par la boule sous l'angle ID
    IG=-pi-atan(-float(H-y-r)/float(x+r))                       # le coin inférieur gauche du billard est vu par la boule sous l'angle IG
    if a==0:lf=L-x-r                                            # limitation de lf par la bande droite (cas limite)
    if a==pi or a==-pi:lf=x+r                                   # limitation de lf par la bande gauche (cas limite)
    if a<SG and a>SD:lf=(y+r)/sin(a)                            # limitation de lf par la bande supérieure
    if a<=SD and a>ID:lf=(L-x-r)/cos(a)                         # limitation de lf par la bande droite
    if a<=ID and a>IG:lf=-(H-y-r)/sin(a)                        # limitation de lf par la bande inférieure
    if a>=SG and a<pi:lf=-(x+r)/cos(a)                          # limitation de lf par la bande gauche
    if a<IG and a>-pi:lf=-(x+r)/cos(a)
    xf,yf=x+r+lf*cos(a),y+r-lf*sin(a)                           # extrémité de la flèche sur la bande
    can.coords(flèche,x+r,y+r,xf,yf)                            # la flèche accompagne la boule pendant le déplacement
    if B1==1:can.itemconfig(flèche,fill='white')
    if B3==1:can.itemconfig(flèche,fill='grey')

def sm(x,y,dx,dy):
    "Simulation du parcours de la boule tirée"
    global sim
    sim=can.create_line(3*h*x/2/L+L/2-3*h/4+RS,3*h*y/4/H+H+h/8+RS,3*h*(x+dx)/2/L+L/2-3*h/4+RS,3*h*(y+dy)/4/H+H+h/8+RS)

def effacer_simulation():
    "effacer la trajectoire de la boule"
    global b1S,b2S,b3S
    REG66=can.create_rectangle(L/2-3*h/4,H+h/8,L/2+3*h/4,H+7*h/8,width=2,fill='dark green')
    bouleS(x1,y1,RS,color='white');b1S=bS                       # remise en place de B1/Pupitre
    bouleS(x2,y2,RS,color='red');b2S=bS                         # idem B2/Pupitre
    bouleS(x3,y3,RS,color='grey');b3S=bS                        # idem B3/Pupitre

def effacer_texteR():
    "Effacement des textes liés au résultat du tir"
    can3.delete(texte1S);can3.delete(texte1E);can3.delete(texte3S);can3.delete(texte3E)

def boule(x,y,r,color):
    "Coordonnées de la boule"
    global b
    b=can.create_oval(x,y,x+2*r,y+2*r,width=1,fill=color)

def Cboule(b,x,y,r):
    "Coordonnées de la boule"
    can.coords(b,x,y,x+2*r,y+2*r)

def bouleS(x,y,r,color):
    "Coordonnées de la boule"
    global bS
    X,Y=3*h*x/2/L+L/2-3*h/4,3*h*y/4/H+H+h/8                     # changement de système de coordonnées (billard vers simulation)
    bS=can.create_oval(X,Y,X+2*RS,Y+2*RS,width=1,fill=color)

def CbouleS(bS,x,y,r):
    "Coordonnées de la boule"
    X,Y=3*h*x/2/L+L/2-3*h/4,3*h*y/4/H+H+h/8                     # changement de système de coordonnées (billard vers simulation)
    can.coords(bS,X,Y,X+2*RS,Y+2*RS)

def presentation():
    "Fenêtre-message contenant la description sommaire du principe du jeu" 
    msg =Toplevel()
    Message(msg, bg ="dark green", fg ="white", width =450,font ="Arial 8", 
        text =" PRESENTATION\n\n"\
        "Au lancement du jeu, trois boules (BLANCHE, ROUGE et GRISE), apparaissent.La BLANCHE commence.\n\n"\
        "La première étape, si l'on souhaite un jeu différent, consiste à déplacer les boules (abscisses et ordonnées), vers de nouvelles positions.\n\n"\
        "La seconde vise à choisir la direction, la vitesse,l'effet latéral et la hauteur de tir de la boule BLANCHE.\n"\
        "Une flèche de tir apparait, dont la longueur est ajustée aux dimensions du billard.\n\n"\
        "Les boules étant en place, la touche <Tir !> met en mouvement la boule BLANCHE dans la direction choisie.\n"\
        "Aux premiers chocs, les autres boules se mettent à leur tour en mouvement.\n"\
        "La vitesse des boules se réduit à chaque itération, pour simuler le freinage du tapis, ainsi qu'à chaque choc (y/c avec les bandes).\n\n"\
        "A l' arrêt des boules, le score de la boule BLANCHE est comptabilisé.\n"\
        "En cas de succès, la BLANCHE gagne un point.Elle peut alors <Continuer !> ou <Rejouer le coup !> (pour améliorer les positions finales).\n"\
        "En cas d' échec, elle peut aussi rejouer le coup,et, sinon, <Passer la main !> à la GRISE.\n\n"\
        "La touche <Figer !> permet d'interrompre le mouvement à tout moment, et la touche <Relancer !> de le redémarrer.\n\n\n"\
        "ALGORITHME\n\n"\
        "Lorsque la boule BLANCHE approche, par exemple, de la boule GRISE, l'algorithme compare la distance entre leurs centres à la somme de leurs rayons.\n"\
        "Quand l'écart devient négatif, il y a intersection des deux contours.\n\n"\
        "L'algorithme calcule alors le recul  en position des deux boules sur leurs directions initiales et en proportion de leurs vitesses, pour revenir au strict contact.\n\n"\
        "La sortie du choc, en direction et en vitesse, se fait ensuite selon les lois de la mécanique des chocs inélastiques entre solides.\n"\
        "Elle prend en compte (de façon très simplifiée) l'effet latéral et la hauteur de tir imprimés au moment du tir.\n\n"\
        "Un coefficient (n) de réduction de la vitesse intervient à chaque choc, y/c avec les bandes.\n" 
        "Un ralentissement (k) a lieu également à chaque itération.\n").pack(padx =10, pady =10)        

def processus():
    ""
    msg =Toplevel()
    Message(msg, bg ="dark green", fg ="white", width =450,font ="Arial 8", 
        text="PROCESSUS à suivre\n\n"\
        "1.  Cliquer sur <Préparer le jeu !>\n\n"\
        "2.  Régler vitesse et orientation\n"\
             "en déplaçant le cercle blanc\n"\
             "(réglage fin par clics successifs)\n\n"\
        "3.  Régler effet latéral et hauteur\n"\
             "en déplaçant la bille bleue\n\n"\
        "4.  Appuyer sur la touche <Tirer !>\n\n"\
        "5.  En cas de succès, <Continuer !>\n"\
             "ou <Rejouer !> : pour améliorer\n\n"\
        "6.  Si échec, <Passer la main !>\n"\
             "ou <Rejouer !>: pour réessayer\n\n"\
        "7.  Possibilité de <Figer !> le mouvement\n"\
             "puis de <Relancer !>\n\n\n"\
        "Echelle du jeu:\n"\
             "Elle est peut être modifiée en\n"\
             "intervenant dans le menu <Règle du jeu>.\n"\
             "Valeurs possibles: de 0.5 à 1.0\n"\
             "(valeur actuelle=0.5)\n").pack(padx =10, pady =10)

def aPropos():
    "Fenêtre-message indiquant l'auteur" 
    msg =Toplevel()
    Message(msg, width =200, aspect =100, justify =CENTER,
        text ="Billard français \n\nHCD, Octobre 2005.\n"\
        "Python version 2.4.2\nTk version 8.4").pack(padx =10, pady =10)

def scale(E):
    "Changement d'échelle"
    global L,H,h,r,rr,R,R4,R6,RS
    global x1,y1,x2,y2,x3,y3
    global x4o,y4o,x5o,y5o,x4,y4,x5,y5
    E=float(E)
    L,H,h,r,rr,R,R4,R6,RS=E*L,E*H,E*h,E*r,E*rr,E*R,E*R4,E*R6,E*RS                                                    
    x1,y1,x2,y2,x3,y3=E*x1,E*y1,E*x2,E*y2,E*x3,E*y3                                          
    can.config(height=H+h,width=L)
    can2.config(width=h)
    can3.config(height=h/3,width=h)
    x4o,y4o,x5o,y5o=E*x4o,E*y4o,E*x5o,E*y5o
    x4,y4,x5,y5=E*x4,E*y4,E*x5,E*y5
    can.coords(Pupitre,E*4,H,L,H+h)
    can.coords(texte,E*L/2,E*L/3)
    can.coords(t1,L/8,H+h-E*10)
    can.coords(t2,L/2,H+h-E*10)
    can.coords(t3,7*L/8,H+h-E*10)
    can.coords(texte1,L/2,H+E*7.5)
    can.coords(texte2,L/8,H+E*7.5)
    can.coords(texte3,7*L/8,H+E*7.5)
    can.coords(REG4,L/8-R4,H+h/2-R4,L/8+R4,H+h/2+R4)
    can.coords(curseur4,L/8,H+h/2+R4,L/8,H+h/2-R4)
    can.coords(REG6,L/2-3*h/4,H+h/8,L/2+3*h/4,H+7*h/8)
    can.coords(REG5,7*L/8-R6,H+h/2-R6,7*L/8+R6,H+h/2+R6)
    can.coords(REG5B,7*L/8-R,H+h/2-R,7*L/8+R,H+h/2+R)
    can.coords(curseur5,7*L/8-R,H+h/2,7*L/8-3*h/16+R/2,H+h/2)
    can.coords(pA,L/4-rr,H/2-rr,L/4+rr,H/2+rr)
    can.coords(pB,L/2-rr,H/2-rr,L/2+rr,H/2+rr)
    can.coords(pC,3*L/4-rr,H/2-rr,3*L/4+rr,H/2+rr)
    can.coords(pD,3*L/4-rr,H/3-rr,3*L/4+rr,H/3+rr)
    can.coords(pE,3*L/4-rr,2*H/3-rr,3*L/4+rr,2*H/3+rr)
    can3.coords(texte1S,2*h/3,h/4)
    can3.coords(texte1E,2*h/3,h/4)
    can3.coords(texte3S,2*h/3,h/4)
    can3.coords(texte3E,2*h/3,h/4)
    EE=1.0

def echelle():
    "Choix de l'échelle" 
    éch=Toplevel()
    curE=Scale(éch,length=200,label="Echelle du jeu",orient=HORIZONTAL,from_=0.95,to=1.05,resolution=0.05,command=scale)
    curE.set(1.0)                                               # position initiale du curseur 
    curE.pack()

######## Programme principal ############################################

# Création du widget principal :
root = Tk()
root.title('>>>>>>>    BILLARD    <<<<<<<')

# données initiales:                                    
flag=0 	                                                        # compteur		   

# Billard

L=600                                                           # longueur du billard
H=L/2                                                           # largeur du billard
r,rr=10,1                                                       # rayons des boules et des marques du tapis
k,s=0.996,0.5                                                   # coefficient de freinage du tapis, vitesse d'arrêt du mouvement
n=0.8                                                           # coefficient de réduction de la vitesse lors d'un choc
x1,y1,x2,y2,x3,y3=3*L/4-r,H/2-r,L/2-r,H/2-r,L/4-r,H/2-r         # coordonnées courantes des boules
dx1,dy1,dx2,dy2,dx3,dy3=0,0,0,0,0,0                             # composantes courantes des vecteurs vitesse des boules
c12,c23,c31=0,0,0                                               # compteurs de choc
point1,point3,score1,score3=0,0,0,0                             # compteurs de point et de score
R1,R3,T1,T3,PM1,PM3,CT1,CT3=0,0,0,0,0,0,0,0                     # indicateurs (rejouer,tirer,passer la main,continuer)
RN1,RN3,RT1,RT3=0,0,0,0                                         # indicateurs de rebond sur les bandes et après choc
j,j1,j3,t1,t3,r1,r3,rt,t=0,0,0,0,0,0,0,0,0                      # compteurs de lancements de jeux et de tirs
texte1E,texte1S,texte3E,texte3S=0,0,0,0
S1,S3,E1,E3=0,0,0,0                                             # résultats (S=succès,E=échec)
e,ha,o,v,o4=0,0,pi,8,pi/2                                       # réglages initiaux 
figer=0
tA=0

# Pupitre de réglage du tir
h=H/2                                                           # hauteur du pupitre de réglage
R,R4,R6,RS=4,25,3*h/8,3*h*r/4/H                                 # rayons du système de réglage
x4o,y4o,x5o,y5o=L/8-R,H+h/2-R,7*L/8-3*h/16-3*R/2,H+h/2-R
x4,y4,x5,y5=L/8-R,H+h/2-R,7*L/8-3*h/16-3*R/2,H+h/2-R

# création des widgets "dépendants" :
can=Canvas(root,bg='dark green',height=H+h,width=L,highlightbackground='brown')
can.grid(row=1,column=0,rowspan=2)
can2=Canvas(root,bg='brown',highlightbackground='brown')
can2.grid(row=1,column=1,sticky=N)
can3=Canvas(root,bg='white',height=h/3,width=h)
can3.grid(row=2,column=1,padx=0,pady=0,ipadx=10,ipady=10,sticky=N+S)

# Pupitre de commande
Pupitre=can.create_rectangle(4,H,L,H+h,width=2,fill='brown')
t1=can.create_text(L/8,H+h-10,text='Effet et hauteur de tir',fill="white")
t2=can.create_text(L/2,H+h-10,text='Simulation',fill="white")
t3=can.create_text(7*L/8,H+h-10,text='Vitesse et orientation de tir',fill="white")
texte1=can.create_text(L/2,H+7.5,text='Régler le tir, puis "Tirer !"',fill="white")
texte2=can.create_text(L/8,H+7.5,text='Déplacer la bille bleue',fill="white")
texte3=can.create_text(7*L/8,H+7.5,text='Déplacer le cercle blanc',fill="white")
REG4=can.create_oval(L/8-R4,H+h/2-R4,L/8+R4,H+h/2+R4,width=1,fill='white')
curseur4=can.create_line(L/8,H+h/2+R4,L/8,H+h/2-R4,width=1,fill='white')
REG6=can.create_rectangle(L/2-3*h/4,H+h/8,L/2+3*h/4,H+7*h/8,width=2,fill='dark green')
REG5=can.create_oval(7*L/8-R6,H+h/2-R6,7*L/8+R6,H+h/2+R6,width=1,fill='dark green')
REG5B=can.create_oval(7*L/8-R,H+h/2-R,7*L/8+R,H+h/2+R,width=1,fill='white')
curseur5=can.create_line(7*L/8-R,H+h/2,7*L/8-3*h/16+R/2,H+h/2,width=1,fill='dark green',arrow=LAST)

# création des cinq points gris sur le tapis et des deux flèches
pA=can.create_oval(L/4-rr,H/2-rr,L/4+rr,H/2+rr,width=0,fill='light grey')
pB=can.create_oval(L/2-rr,H/2-rr,L/2+rr,H/2+rr,width=0, fill='light grey')
pC=can.create_oval(3*L/4-rr,H/2-rr,3*L/4+rr,H/2+rr,width=0,fill='light grey')
pD=can.create_oval(3*L/4-rr,H/3-rr,3*L/4+rr,H/3+rr,width=0,fill='light grey')
pE=can.create_oval(3*L/4-rr,2*H/3-rr,3*L/4+rr,2*H/3+rr,width=0,fill='light grey')
flèche1=can.create_line(0,0,0,0,arrow=LAST)
flèche3=can.create_line(0,0,0,0,arrow=LAST)

# Message d'introduction
texte=can.create_text(L/2,L/3,text='Cliquer sur le bouton "Règle du jeu"\n\nou\n\ndirectement sur "Préparer le jeu"',fill="white")

# Menu <Règle du jeu> 
RdJ = Menubutton(can2, text ='Règle du jeu',height=2,width=25,relief=GROOVE,bg="dark green",fg="white")
RdJ.pack(padx=5,pady=5,side=BOTTOM,anchor=SW)
me1 = Menu(RdJ)
me1.add_command(label='Présentation',underline=0,command=presentation)
me1.add_command(label='Processus',underline=0,command=processus)
me1.add_command(label='Echelle',underline=0,command=echelle)
me1.add_command(label='A propos ...',underline=0,command=aPropos)
RdJ.configure(menu=me1)

# Affichage des réglages et des scores:

  # hauteur:
can.hauteur=Label(can2,text='0',fg='white',bg='brown')
can.hauteur.pack(side=BOTTOM)
Label(can2,text="hauteur",fg='white',bg='brown').pack(side=BOTTOM)
  # effet:
can.effet=Label(can2,text='0',fg='white',bg='brown')
can.effet.pack(side=BOTTOM)
Label(can2,text="effet",fg='white',bg='brown').pack(side=BOTTOM)
  # vitesse:
can.vitesse=Label(can2,text='0',fg='white',bg='brown')
can.vitesse.pack(side=BOTTOM)
Label(can2,text="vitesse",fg='white',bg='brown').pack(side=BOTTOM)
  # orientation:
can.orientation=Label(can2,text='0',fg='white',bg='brown')
can.orientation.pack(side=BOTTOM)
Label(can2,text="orientation",fg='white',bg='brown').pack(side=BOTTOM)
  # Score B3:
can.score3=Label(can2,text='0',fg='white',bg='brown')
can.score3.pack(side=BOTTOM)
Label(can2,text="score GRISE",fg='white',bg='brown').pack(side=BOTTOM)
  # Score B1:
can.score1=Label(can2,text='0',fg='white',bg='brown')
can.score1.pack(side=BOTTOM)
Label(can2,text="score BLANCHE",fg='white',bg='brown').pack(side=BOTTOM)

# Boutons de commande

  # 'Continuer ?':
CT=Button(can2,text='Continuer? ',height=2,width=25,relief=GROOVE,bg="white",activebackground="dark green",activeforeground="white",command=continuer)
CT.pack(padx=5,pady=5,side=BOTTOM,anchor=SW)
CT.pack_forget()
  # 'Passer la main ?':
PM=Button(can2,text='Passer la main? ',height=2,width=25,relief=GROOVE,bg="white",activebackground="dark green",activeforeground="white",command=passer)
PM.pack(padx=5,pady=5,side=BOTTOM,anchor=SW)
PM.pack_forget()
  # 'Rejouer le coup ?':
RJ=Button(can2,text='Rejouer le coup ?',height=2,width=25,relief=GROOVE,bg="white",activebackground="dark green",activeforeground="white",command=rejouer)
RJ.pack(padx=5,pady=5,side=BOTTOM,anchor=SW)
RJ.pack_forget()
  # bouton d'arrêt du mouvement:
FI=Button(can2,text='Figer le mouvement',height=2,width=25,relief=GROOVE,bg="white",activebackground="dark green",activeforeground="white",command=stop)
FI.pack(padx=5,pady=5,side=BOTTOM,anchor=SW)
FI.pack_forget()
  # bouton de redémarrage du mouvement:
RL=Button(can2,text='Relancer le mouvement',height=2,width=25,relief=GROOVE,bg="white",activebackground="dark green",activeforeground="white",command=go)
RL.pack(padx=5,pady=5,side=BOTTOM,anchor=SW)
RL.pack_forget()
  # 'Tirer !':
T=Button(can2,text='Tirer !',height=2,width=25,relief=GROOVE,bg="white",activebackground="dark green",activeforeground="white",command=tirer)
T.pack(padx=5,pady=5,side=BOTTOM,anchor=SW)
T.pack_forget()
  # 'Préparer le tir !':
J=Button(can2,text='Préparer le jeu !',height=2,width=25,relief=GROOVE,bg="white",activebackground="dark green",activeforeground="white",command=jouer)
J.pack(padx=5,pady=5,side=BOTTOM,anchor=SW)

root.mainloop()


 Conclusion

Merci à tous ceux qui ont bien voulu prendre connaissance des premières versions.
Une nouvelle visite du script devrait les intéresser, car de nombreuses fonctionnalités
ont été ajoutées.
Commencer par appuyer sur le bouton "Règle du jeu" qui donne une présentation d'ensemble,
ainsi que le processus à suivre pour jouer.

PS : commentaires et cotations seront les bienvenus !

 Fichier Zip

Les Membres Club peuvent télécharger directement un fichier contenu dans le zip sans télécharger le zip en entier !

Télécharger le zip


 Historique

18 août 2005 10:23:18 :
ajout de commentaires
09 septembre 2005 00:13:56 :
Les boules sortent maintenant de façon aléatoire sur le billard ou, en cas de recouvrement, en position "canonique" (alignées). Le code est surtout complété pour permettre de choisir la position des boules sur le billard, puis la direction de tir de la boule blanche. Une flèche orientable apparait puis disparait au moment du tir. L'algorithme du choc entre boules, qui constitue l'originalité du programme, est réintégré dans le nouveau script.
17 octobre 2005 22:15:15 :
Fonctionnalités nouvelles: 1. Prise en compte de l'effet et de la hauteur de tir 2. Création d'un pupitre de tir permettant de commander: - orientation et vitesse - effet et hauteur 3. Création de boutons de commande pour gérer les phases de jeu: - "préparer le tir" - "continuer", "rejouer le coup", "passer la main" 4. Création du menu "Règle du jeu" avec: - la "présentation" du script - la descrition du "processus" à suivre pour jouer - la possibilité de changer l'"échelle" des canevas 5 . Création d'un billard "miniature" pour visualiser et mémoriser la trajectoire de la boule tirée
30 novembre 2005 01:32:52 :
Saisie de mots clés
23 décembre 2005 01:36:55 :
Ajout d'un zip

 Sources du même auteur

Source avec Zip MASTERMIND (PAR JULIE ET HCD)
Source avec Zip Source avec une capture RÉSOLUTION DES ÉQUATIONS DU 4ÈME DEGRÉ
Source avec Zip Source avec une capture LE CENTRE DU CERCLE RETROUVÉ PAR NAPOLÉON !
Source avec Zip Source avec une capture CERCLE ET DROITE D' EULER ANIMÉS DANS UN TRIANGLE
Source avec Zip COLLISIONS EN 3D AVEC VISUAL PYTHON

 Sources de la même categorie

Source avec Zip QUESTIONNAIRE par darkanghel91
Source avec Zip Source avec une capture JEU DU PLUS OU MOINS par Iphonemax
TAQUIN 4*4 par fredericfabry
Source avec Zip Source avec une capture ASTRE2.0 CASSE-BRIQUES par Mints
Source avec Zip JEU DU NOMBRE MYSTERE EN PYTHON par messorama

 Sources en rapport avec celle ci

Source avec Zip Source avec une capture EDITEUR CROQUIS par grephit
Source avec Zip ROTRING SCRIPT DESSIN par grephit
Source avec Zip Source avec une capture HORLOGE-CHRONOMÈTRE-RÉVEIL par yveslc
Source avec Zip COLLISIONS EN 3D AVEC VISUAL PYTHON par HCD
Source avec Zip Source avec une capture COLLISIONS EN CASCADES : PLUS D'UNE CENTAINE DE BOULES S'ENT... par HCD

Commentaires et avis

Commentaire de jpountz le 16/08/2006 15:16:11

@ HCD
Je viens de l'essayer, et c'est vraiment extrèmement bien fait! Il va falloir que je me penche un peu plus sur le code...
Félicitations! Ça mérite un 10!

Commentaire de HCD le 31/08/2006 22:11:52

MERCI !

Commentaire de minick1996 le 24/10/2008 15:33:10

tres bonne sources mes manque un petit peu de design il y a de meilleur base que tk Mais tres bonne sources mais je vois pas le but on peu déplacer le balle

Commentaire de minick1996 le 25/10/2008 02:26:24

Sa mérite quand meme un 10 tres bien fait

Commentaire de minick1996 le 25/10/2008 02:27:22 10/10

désoler javais pas cliquer sur les étoile ;) faik je fait monter ta sources a 10

 Ajouter un commentaire


Discussions en rapport avec ce code source dans le forum

Variation Label grâce à une fonction appellé par Button [ par philux21 ] bonjour, je souhaite faire varier une valeur affichée dans un label. Je m'y prends ainsi : http://pastebin.com/8qnFG01J je ne comprends pas mon erre Espace dans un label Tkinter [ par dahrprog ] Bonjour tout le monde , je voudrais afficher des données de ma base de données sur une interface Tkinter via une Label , ça marche bien , j'ai mis : Petit problème avec "return" [ par Uims ] Bonjour, Je suis entrain de faire un annuaire en python (avec Tk), mais j'ai un petit probl&#232;me avec return dans la fonction "loc", j'aimerai que Une scrollbar sur un Label ? [ par stephane70 ] Bonjour, Je mets en place un petit programme destiné à faire un instantanée graphique des connections en cours sur le pc ainsi que les executables en Problème sur la taille de fenetre en Tkinter [ par stephane70 ] Bonjour, Je mets en place un petit programme destiné à faire un instantanée graphique des connections en cours sur le pc ainsi que les executables en héritage de wxObject et polymorphisme ?? [ par RV2931 ] Bonjour,Je programme en wxPython et j'aurai voulu savoir comment dériver un objet wx pour faire un bouton personalisé par exemple, avec des informatio [Tkinter] Erreur premier programme [ par O_connor ] Bonjour à toutes et à tous,Je poste un ce topic car voilà deux jours que je bloque sur ma petite application que j'essaie de réaliser avec une GUI.Ce Question sur PyQt4 !!!!!! [ par Subversion ] Bonjour à vous tous,Voilà, je dois programmer en Python via Eclipse (avec PyDev) afin d'élaborer une interface graphique. De ce fait, je suis en train Gestion d'une interface graphique [ par lilly74 ] Bonjour, je débute en python et j'essaie de créer une interface graphique qui prend en entrée deux chaînes de caractères et qui les traite selon une m


Nos sponsors


Sondage...

CalendriCode

Février 2012
LMMJVSD
  12345
6789101112
13141516171819
20212223242526
272829    

Consulter la suite du CalendriCode

 
Développement réalisé par Nicolas SOREL (Nix) avec l'aide de : Cyril DURAND et Emmanuel (EBArtSoft), Merci à Vincent pour ses précieux conseils.
CodeS-SourceS.com© Toute reproduction même partielle est interdite sauf accord écrit du Webmaster
CodeS-SourceS.com© est une marque déposée tous droits réservés

Google Coop CodeS-SourceS Google Coop CodeS-SourceS
Temps d'éxécution de la page : 4,306 sec (3)

Nous contacter | Annoncer sur CodeS-SourceS | Mentions légales