Initialiser deux listes en variables globales enseigne et valeur contenant respectivement les familles et les valeurs des cartes. Les enseignes et les valeurs seront des objets de type str
from random import randint as rd
Les variables globales sont des constantes
enseigne = ["pique","trefle","coeur","carreau"]
valeur = ["2","3","4","5","6","7","8","9","10","V","D","R","As"]
ENSEIGNES = len(enseigne)
VALEURS = len(valeur)
N = ENSEIGNES * VALEURS # Le nombre total de cartes
Création d'un paquet de cartes. Écrire une fonction fabriquePaquet() qui ne prend pas d’argument et retourne un paquet complet de 52 cartes sous la forme d’une liste de tuples. Chaque tuple représente une carte (valeur, famille) .
def fabriquePaquet():
'''
Renvoie un paquet de carte rangé dans l'ordre des valeurs par enseigne
sous la forme d'une liste. Chaque carte est représentée par un tuple
'''
paquet=[]
for i in range(ENSEIGNES):
for j in range(VALEURS):
paquet.append((valeur[j], enseigne[i]))
return paquet
Mélanger le paquet de cartes. Écrire une fonction fisherYatesMelange(paquet) qui accepte en argument un paquet de cartes et retourne un paquet mélangé complet sous la forme d’une liste de tuples. Pour mélanger le paquet on utilisera l’algorithme de Fisher-Yates encore appelé Knuth shuffle.
def fisherYatesMelange(paquet):
'''
Prend en argument un paquet de carte de type list et renvoie
un paquet mélangé avec l'algo de Fisher Yates encore appelé
Knuth Shuffle
'''
for i in range(1, len(paquet)):
r = rd(0, i)
paquet[i], paquet[r] = paquet[r], paquet[i] #échange par affectation parallèle, possible car les éléments de
return paquet #la liste sont des objets non mutables
Distribuer les cartes. Écrire une fonction distribuer(N, J, paquet) qui accepte en arguments le nombre de cartes à donner \((N)\) à chaque joueur \((J)\) avec \((N, J)\in \mathbb{N^2}\) d’un paquet préalablement mélangé. La fonction doit retourner la main de chaque joueur sous la forme d’un tableau à deux dimensions ainsi que le paquet avec les cartes restantes. La distribution pourra se faire en donnant les cartes une par une ou bien en donnant la totalité des cartes à chaque joueur.
def distribuer(N, J, paquet):
'''
Prend en argument le nombre entier N de cartes à distribuer, le nombre
entier J de joueurs et un paquet de cartes de type list.
Renvoie une liste 2 dimensions contenant les mains de chaque joueur
'''
mains = [[0]*N for l in range(J)]
for l in range(J):
for c in range(N):
if len(paquet)>0:
mains[l][c] = paquet.pop()
else:
return mains, None #retourne les mains des joueurs si plus de carte dans le paquet
return mains, paquet
Déterminer la carte possédant la plus grande valeur. Écrire une fonction meilleurCarte(liste) qui accepte en argument une liste de cartes ( chaque carte étant un tuple (valeur, famille) ) et renvoie sous la forme d’un tuple celle qui possède la plus grande valeur sans distinction de famille.
def meilleurCarte(liste):
'''
Prend en argument une liste de cartes (tuple) et retourne la meilleur carte
'''
meilleur_carte = liste[0]
for carte in liste: #attention carte est un tuple
point_carte = valeur.index(carte[0]) #on cherche l'index de la valeur de la carte dans la liste valeur
if point_carte > valeur.index(meilleur_carte[0]): #plus l'index est élevé meilleur est la carte
meilleur_carte = carte #on conserve la meilleur carte
return meilleur_carte
Lancer le début de la partie. Écrire une fonction InitialisePartie(N, J) accepte en arguments le nombre de cartes à donner (N) à chaque joueur (J), prépare un paquet de cartes, le mélange et distribue les cartes.
def initialisePartie(N, J):
paquet = fabriquePaquet()
paquet = fisherYatesMelange(paquet)
return distribuer(N, J, paquet)
Jouer Bataille Une fois le jeu initialisé, utiliser une fonction jouerBataille() (dont vous choisirez les éventuels arguments) permettant de comparer les cartes tirées par chaque joueur à chaque tour.
def jouerBataille(N, J):
mains, paquet = initialisePartie(N,J)
for carte in range(N):
tour = []
for joueur in range(J):
print joueur, mains[joueur][carte]
tour.append(mains[joueur][carte])
print
print "tour", carte
print "meilleur carte", meilleurCarte(tour)
print
jouerBataille(3, 4)
Voila pour un début très simple. Si maintenant on veut ajouter quelques fonctionnalités à notre bataille, il va falloir diviser pour régner c'est à dire mettre en oeuvre une solution qui répond au problème posé tout en gardant un code modulable et facile à lire.
Chacun est libre d'implémenter les règles avec lesquelles il joue à la bataille.
A chaque tour il faut :
def jouerTour(mains, bataille=0):
'''
Cette fonction prend en paramètre
* un tableau (liste de liste) des mains des joueurs
* une liste optionnelle contenant les indices des joueurs participant à une éventuelle bataille
elle renvoie :
* une liste des cartes posées sur la table
'''
if bataille == 0: #pas de bataille, le cas classique
joueurs = mains
else:
joueurs = [] #En cas de bataille
for j in range(len(mains)): #on parcourt les indices de la liste des mains
if j in bataille: #si l'indice appartient à la liste des joueurs de la bataille
joueurs.append(mains[j]) #on ajoute la main de ce joueur à la liste des mains de la bataille
else: #sinon on ajoute une main vide pour avoir le même de nombre
joueurs.append([]) #de mains que de joueurs (plus facile de déterminer l'indice du gagnant)
#dans tous les cas
table = [] #liste des cartes posées sur la table
for joueur in joueurs: #pour chaque joueur de la liste
if len(joueur) != 0: #si il lui reste des cartes
table.append(joueur[0]) #on pose une carte sur la table
joueur.pop(0) #et on la retire de la main du jour
else:
table.append("-1") #si un joueur n'a plus de carte
return table
Attention le paramètre mains de cette fonction est un objet mutable (passage par référence) je n'ai donc pas besoin de le retourner car il sera automatiquement modifier en dehors de la fonction. Il en sera toujours de même par la suite
def filtreTable(table):
'''
Permet de filtrer une liste de cartes de la table de jeu en supprimant les -1
Renvoie une liste de cartes valides
'''
liste_carte = []
for c in table:
if c != "-1":
liste_carte.append(c)
return liste_carte
def gagnantTour(table):
'''
Cette fonction prend en argument la liste des cartes posées sur la table et renvoie un entier indiquant
l'indice de position du gagnant dans la liste des joueurs.
'''
cartes = filtreTable(table) #on commence par filtrer les cartes valides
if len(cartes) > 0: #si il reste des cartes
carte = meilleurCarte(cartes) #on cherche la meilleur
gagnant = table.index(carte) #et on récupère l'index du joueur à qui appartient cette carte avant le filtre
else:
return rd(0, len(table)-1) #au cas ou il n'y a pas de carte valide (une bataille impossible à finir)
return gagnant
def isBataille(table):
'''
Cette fonction prend en paramètre une liste contenant les cartes posées sur la table pour un tour donné
Elle renvoie la liste des joueurs concernés, il y a bataille si cette liste contient plus d'un joueur.
'''
liste_carte = []
cartes = filtreTable(table)
maxi = meilleurCarte(cartes) #on cherche la meilleur carte posée sur la table
joueurs_bataille = [] #liste des joueurs pour la bataille
for j in range(len(table)): #pour chaque carte sur la table
if table[j][0] != "-1" and table[j][0]==maxi[0]: #on vérifie si elle est d'égale valeur à la meilleure carte
joueurs_bataille.append(j) #Si oui on ajoute l'indice du joueur à la liste des batailleurs!
return joueurs_bataille
def bataille(mains, joueurs):
'''
Cette fonction prend en paramètres:
une liste d'entiers indiquant les joueurs concernés par la bataille,
une liste de l'ensemble des mains des joueurs
Elle renvoie la liste des cartes à ramasser.
'''
table=[]
table.append(jouerTour(mains, joueurs))
table.append(jouerTour(mains, joueurs))
return table
def ramasserCartes(table, joueur, mains):
'''
Cette fonction prend en paramètres :
* une liste des cartes posées sur la table
* un entier indiquant le joueur gagnant
* le tableau de l'ensemble des mains des joueurs
Elle renvoie le tableau des mains mis à jour.
'''
table = fisherYatesMelange(table) #on mélange les cartes ramassées sur la table
for carte in table:
if carte != "-1":
mains[joueur].append(carte) #on met à jour le tableau des mains
def isWin(mains):
joueurs = len(mains) #on compte le nombre de joueurs
perdants = 0
gagnant = 0
for j in range(joueurs): #pour chaque joueur
if mains[j] == []: #si il n'a plus de carte
perdants +=1 #il appartient à la liste des perdants
else:
gagnant = j #sinon c'est un gagnant potentiel
if joueurs - perdants == 1: #si il n' a plus qu'un seul joueur avec des cartes
return gagnant #c'est le gagnant
else:
return -1
def jouerBataille(N, J):
def affiche(): #une fonction interne pour afficher les résultats
for elt in mains: #on peut suivre le jeu à chaque tour
print elt #en affichant les cartes de tous les joueurs
print
mains, paquet = initialisePartie(N,J)
coup = 0
affiche()
while (isWin(mains) == -1): #tant qu'il n'y a pas de gagnant
table = jouerTour(mains) #les joueurs posent une carte sur la table
joueurs_bataille = isBataille(table) #on récupère une liste de joueurs pour la bataille
if len(joueurs_bataille) > 1: #si la liste contient au moins deux joueurs
cartes_bataille = bataille(mains, joueurs_bataille) #on récupère la liste des cartes de la bataille
print "bataille", cartes_bataille
gagnant = gagnantTour(cartes_bataille[-1]) #on cherche le gagnant de la bataille
print "gagnant", gagnant
for c in cartes_bataille: #on ajoute les cartes de la batailles à celles
table += c #de la table
else: #si pas de bataille
gagnant = gagnantTour(table) #on cherche un gagnant
ramasserCartes(table, gagnant, mains) #le gagnant ramasse les cartes
coup += 1
affiche()
return isWin(mains), coup
Un exemple avec affichage des différents tours de jeu.
Question : Que peut-on afficher d'autre (de fort intéressant) avec la cette suite d'instructions ?
cartes = 3
joueurs = 3
stats = [0 for i in range(joueurs)]
for i in range(1):
j, coup = jouerBataille(cartes, joueurs)
stats[j] += 1
print(stats)