Bataille Navale
Minimum
- gérer l’état des bateaux par un code dans une matrice 2D (0 = vide, 1=bateau, 2 = coulé, 3 = tir raté)
- avoir plus d’un bateau par flotte pour le joueur et l’ordinateur
- affichage travaillé du plateau de jeu (pas juste un print() de la matrice donc)
- un diagramme d’activité général du jeu, pas plus grand qu’une feuille A4 paysage pour la lisibilité, à vous de choisir le niveau de généralité qui convient pour communiquer l’essentiel
- Gérer la possibilité pour le joueur/ordinateur de rejouer si on a coulé un bateau
- Empêcher que les bateaux soient placés (manuellement ou automatiquement par l'ordinateur) deux fois au même endroit dans la matrice.
Bonus
- Possibilité de jouer contre l’ordinateur ou avec un autre joueur
- Gérer des bateaux de tailles différentes avec des chiffres, un exemple : Bateau de taille 1 codé par 1 case de valeur 1, bateau de taille 2 codé par 2 cases de valeur 2 dans la matrice, etc. à la fois pour le joueur et l’ordinateur, ce qui oblige à passer sur des matrices différentes : une pour gérer les codes des bateaux, une pour afficher les tirs touchés / ratés (avec 1 et 2 par exemple) puis le résultat affiché (ici représenté par Coulé , Touché, / Raté )

-
Gérer ce nouvel état possible touché / coulé pour les bateaux, avec affichage, par exemple avec un compteur indiquant pour chaque bateau le nombre d’impact (voir les dictionnaires en python { 3 : 1, 6 : 4 } => bateau de 3 touché 1 fois; bateau de 6 touché 4 fois )
-
Gérer des bateaux d’orientations différentes pour le joueur et l’ordinateur ( attention les deux derniers points sont de difficulté plus importante, notamment car il faut gérer les collisions et les bords de la matrice pour le placement, utiliser les fonctions pour garder un code le plus lisible possible )
Première version
Version sans fonction :
import random
contenuLigne = []
tabNavale = []
for numLigne in range(3):
contenuLigne = []
for numColonne in range(3):
contenuLigne.append(0)
tabNavale.append(contenuLigne)
#print("tabNaval contient", tabNavale)
xNavire = random.randint(0,2)
yNavire = random.randint(0,2)
print (yNavire ,",", xNavire )
tabNavale[yNavire][xNavire] = 1
essai = 0
trouve = False
while (trouve != True) and (essai < 3):
tirY = int(input("Saisir une ligne entre 0 et 2"))
tirX = int(input("Saisir une colonne entre 0 et 2"))
while tirX >=3 or tirY >= 3:
print("Erreur recommence")
tirY = int(input("Saisir une ligne entre 0 et 2"))
tirX = int(input("Saisir une colonne entre 0 et 2"))
if tabNavale[tirY][tirX] == 1:
print("TROUVE")
trouve = True
else:
print("RATÉ !")
tabNavale[tirY][tirX] = 2
essai = essai + 1
carte = ""
for ligne in range(len(tabNavale)):
for colonne in range(len(tabNavale)):
contenu = tabNavale[ligne][colonne]
# affiche tout
if trouve == True or essai >= 3:
if tabNavale[ligne][colonne] == 1:
carte += " ^ "
elif tabNavale[ligne][colonne] == 2:
carte += " o "
else:
carte += " ~ "
else:
if tabNavale[ligne][colonne] == 2:
carte += " o "
else:
carte += " ~ "
carte += "\n"
print(carte)
On se rend compte qu'une partie du code est redondante, et/ou assez verbeuse et peut être transformé en fonction :
- répétition en cas d'erreur de saisie, par exemple si l'utilisateur saisie une coordonnée qui est en dehors du cadre
- affichage de la carte, dont on peux moduler la légende en fonction de ce que l'on veut afficher
- construction de la matrice, ici il n'y en a qu'une mais ensuite il nous en faudra 2 par joueurs ! En plus on aimerait faire varier la taille de celle-ci !
Cette partie qui consiste à répéter et à tester la saisie utilisateur est amené à revenir régulièrement dans notre code, elle peut devenir une fonction. Celle-ci prend en paramètre la valeur de y et de x, ceux-ci doivent être passé au moment ou on appele cette fonction. Une fois que la saisie est valide on renvoie les coordonnées validé sous forme de liste avec le mot-clef return
Le code pour gérer le même affichage de carte, mais avec des informations différentes est assez difficile à lire du fait du nombre de if important.
Là aussi on peut définir une fonction a qui on passe deux paramètres sous forme de liste, les numéro qui peuvent être affiché, et les numéro qui doivent être masqué.
def transformMap(elementToNotDisplay):
legende = {0:" ~ ", 1:" ^ ", 2: " o ", 3: " x "}
carte = ""
#...
return carte
Enfin la première partie, on l'aime pas trop non plus, dans la suite du jeu il nous faudra forcément plusieurs matrices pour l'ordinateur (bateaux et tirs) et le joueurs (bateaux et tirs).
def buildMatrice(ligne,colonne,valeur):
# ...
return l_list
mShipJoueur = buildMatrice(5,5,0)
mShipOrdi = buildMatrice(5,5,0)
dShipOrdi = buildMatrice(5,5,0)
dShipJoueur = buildMatrice(5,5,0)
Correction
def transformMap(elementToNotDisplay):
legende = {0:" ~ ", 1:" ^ ", 2: " o ", 3: " x "}
carte = ""
for ligne in range(len(tabNavale)):
for colonne in range(len(tabNavale)):
contenu = tabNavale[ligne][colonne]
if contenu in elementToNotDisplay:
carte += legende[0]
else:
carte += legende[contenu]
carte += "\n"
return carte
def checkXY(y,x):
while x >=3 or y >= 3:
print("Erreur recommence")
y = int(input("Saisir une ligne entre 0 et 2"))
x = int(input("Saisir une colonne entre 0 et 2"))
return [y,x]
Code Complet :
import random
contenuLigne = []
def buildMatrice(ligne,colonne,valeur):
tabNavale = []
for numLigne in range(ligne):
contenuLigne = []
for numColonne in range(colonne):
contenuLigne.append(valeur)
tabNavale.append(contenuLigne)
return tabNavale
def checkXY(y,x):
tirX = x
tirY = y
while tirX >=3 or tirY >= 3:
print("Erreur recommence")
tirY = int(input("Saisir une ligne entre 0 et 2"))
tirX = int(input("Saisir une colonne entre 0 et 2"))
return tirY, tirX
def transformMap(tabData, elementToNotDisplay):
legende = {0:" ~ ", 1:" ^ ", 2: " o ", 3: " x "}
carte = ""
for ligne in range(len(tabData)):
for colonne in range(len(tabData)):
contenu = tabData[ligne][colonne]
# affiche tout sauf ce qui est déclaré dans elementToNotDisplay
if legende[contenu] in legende[elementToNotDisplay]:
carte += legende[0]
else:
carte += legende[contenu]
carte += "\n"
return carte
#print("tabNaval contient", tabNavale)
matriceJeu = buildMatrice(3,3,0)
xNavire = random.randint(0,2)
yNavire = random.randint(0,2)
print (yNavire ,",", xNavire )
matriceJeu[yNavire][xNavire] = 1
essai = 0
trouve = False
while (trouve != True) and (essai < 3):
tirY = int(input("Saisir une ligne entre 0 et 2"))
tirX = int(input("Saisir une colonne entre 0 et 2"))
tirY, tirX = checkXY(tirY,tirX)
print("Erreur recommence")
if matriceJeu[tirY][tirX] == 1:
print("TROUVE")
trouve = True
else:
print("RATÉ !")
matriceJeu[tirY][tirX] = 2
essai = essai + 1
carte = transformMap(matriceJeu, 1)
print(carte)
Deuxième version
Maintenant il serait intéressant d'aller plus loin en ajoutant nos deux joueurs, toujours en jouant avec des bateaux d'une seule case pour ne pas trop complexifier d'un coup. Les joueurs doivent pouvoir choisir ou positionner leur bateaux en début de partie, et les positions entrées doivent être correctes.
- Réaliser une fonction qui ajoute un bateau dans la matrice
matriceToAddAShip, la signature devrait être celle-ci.addAShip(matriceToAddAShip, typeOfPlayer). Celle-ci ne renvoie rien et modifie la matrice directement sur place dans la fonction. - Avant d'ajouter un bateau, dans la fonction
addAShipil faut bien penser à tester si la position est valide en faisant appel à une fonctiontestIfXYValid(y,x,matriceToTest)qui renvoie vrai ou faux.