Une grille "démineur"☘
Vous connaissez sans doute le jeu "démineur" (sinon cherchez sur le web).
L'objectif est ici de créer la grille de jeu.
Un affichage☘
Pour afficher nos grilles de démineur, on va ici créer un fichier html.
On propose le code suivant enregistré dans le fichier affichage_html.py.
texte du fichier affichage_html.py
def grille_html(tab):
"""
tab -- matrice
renvoie le code html d'une page html affichant le contenu
de tab dans un élément html table.
"""
html = """<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8">
<title> Grille </title>
<style>
html{font-size: 20px;}
body{width: 80%; margin: 20px auto;}
td{padding: 5px; text-align: center;}
</style>
</head>
<body>
<table>
<tr>
"""
nb_lignes = len(tab)
nb_colonnes = len(tab[0])
# on place les numéros de colonne:
html += """<td style="border: none;"></td>\n"""
for col in range(nb_colonnes):
html += f"""<td style="color: green; border: none; font-size: 0.5rem;"> {col} </td>\n"""
html += "</tr>\n" # fermeture de la ligne du tableau portant les numéros de colonne
# on remplit les lignes:
for lig in range(nb_lignes):
html += "<tr>"
# on inscrit le numéro de ligne:
html += f"""<td style="color: green; border: none; font-size: 0.5rem;">{lig}</td>\n"""
# on crée les cellules de l'élément html table en y inscrivant les valeurs contenues dans tab:
for col in range(nb_colonnes):
html += f"""<td style="background-color: white; border: 1px solid black; "> {tab[lig][col]} </td>\n"""
html += "</tr>\n"
html += "</table>\n"
html += "</body>\n</html>"
return html
def creation_fichier_html(nom_fichier, tab):
"""
nom -- chaîne de caractères, nom d'un fichier à créer
tab -- matrice à afficher
La fonction ne renvoie rien, elle crée un fichier html.
"""
# on crée un fichier html qui sera nommé nom_fichier:
with open(nom_fichier + '.html', 'w') as f:
# on écrit la chaine créée par la fonction précédente dans ce fichier:
print(grille_html(tab), file=f)
Vous devez lire ce code et en comprendre l'essentiel pour vous en servir.
Dans un autre fichier python, créez une matrice de votre choix et affichez la avec le script du fichier précédent.
Solution
Dans un fichier utilisation.py
placé dans le même répertoire que le fichier affichage_html.py
, on importe
tout d'abord ce fichier affichage_html.py
puis on crée une matrice quelconque et on appelle
la fonction creation_fichier_html
:
from affichage_html import *
matrice = [ [ i+j for j in range(7)] for i in range(5) ]
creation_fichier_html("fichier_essai", matrice)
Il reste à vérifier qu'un fichier fichier_essai.html est bien présent dans le dossier du script puis à l'ouvrir avec un navigateur.
Variante
On peut écrire une variante du fichier affichage_html.py
en utilisant
la bibliothèque jinja2 :
voir le fichier affiche_matrice.py.
Texte du fichier .py
from jinja2 import Template
# création du modèle de page html:
template = Template("""
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8">
<title> Grille </title>
<style>
html{font-size: 20px;}
body{width: 80%; margin: 20px auto;}
td{padding: 5px; text-align: center;}
</style>
</head>
<body>
<table>
<tr>
<td style="border: none;"></td>
{% for col in range(nb_colonnes) %}
<td style="color: green; border: none; font-size: 0.5rem;"> {{col}} </td>
{% endfor %}
</tr>
{% for lig in range(nb_lignes) %}
<tr>
<td style="color: green; border: none; font-size: 0.5rem;">{{lig}}</td>
{% for col in range(nb_colonnes) %}
<td style="background-color: white; border: 1px solid black; ">
{{tab[lig][col]}}
</td>
{% endfor %}
</tr>
{% endfor %}
</table>
</body>
</html>
""")
def creation_fichier_html(nom_fichier, tab):
"""
nom -- chaîne de caractères, nom d'un fichier à créer
tab -- matrice à afficher
La fonction ne renvoie rien, elle crée un fichier html.
"""
with open(nom_fichier + '.html', 'w') as f:
texte = template.render(nb_colonnes=len(tab[0]), nb_lignes=len(tab), tab=tab)
print(texte, file=f)
On pourra faire appel à la fonction créant un fichier html affichant le tableau de la même façon que dans l'exemple précédent.
from affiche_matrice import *
matrice = [ [ i+j for j in range(7)] for i in range(5) ]
creation_fichier_html("fichier_essai", matrice)
Autre templating
La bibliothèque mako est une autre bibliothèque de templating.
from mako.template import Template
# création du modèle de page html:
template = Template("""
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8">
<title> Grille </title>
<style>
html{font-size: 20px;}
body{width: 80%; margin: 20px auto;}
td{padding: 5px; text-align: center;}
</style>
</head>
<body>
<table>
<tr>
<td style="border: none;"></td>
% for col in range(nb_colonnes) :
<td style="color: green; border: none; font-size: 0.5rem;"> ${col} </td>
% endfor
</tr>
% for lig in range(nb_lignes) :
<tr>
<td style="color: green; border: none; font-size: 0.5rem;"> ${lig}</td>
% for col in range(nb_colonnes) :
<td style="background-color: white; border: 1px solid black; ">
${tab[lig][col]}
</td>
% endfor
</tr>
% endfor
</table>
</body>
</html>
""")
def creation_fichier_html(nom_fichier, tab):
"""
nom -- chaîne de caractères, nom d'un fichier à créer
tab -- matrice à afficher
La fonction ne renvoie rien, elle crée un fichier html.
"""
with open(nom_fichier + '.html', 'w') as f:
texte = template.render(nb_colonnes=len(tab[0]), nb_lignes=len(tab), tab=tab)
print(texte, file=f)
Exemple d'utilisation:
matrice = [ [ 10*i+j for j in range(7)] for i in range(5) ]
creation_fichier_html("grille_mako", matrice)
Création du champ de mines.☘
Le champ de mines sera ici représenté par une matrice carrée, liste de listes en langage Python.
Compléter le texte de la fonction suivante:
def cree_champ_de_mines(n, p):
"""
crée une matrice carrée de taille n
avec des mines disséminées au hasard.
Chaque cellule reçoit une mine avec une proba p.
"""
Exemple.
En appelant la fonction d'affichage de l'exercice précédent avec cree_champ_de_mines(10, 0.3)
:
>>> creation_fichier_html("essai", cree_champ_de_mines(10, 0.3))
on a obtenu :
Random
On fera appel au module random pour décider, pour chaque cellule, si elle reçoit ou non une bombe.
Solution
Un code possible.
from affichage import *
from random import random
def cree_champ_de_mines(n, p):
"""
crée une matrice carrée de taille n
avec des mines disséminées au hasard.
Chaque cellule reçoit une mine avec une proba p.
"""
champ = [[0 for col in range(n)] for lig in range(n)]
for lig in range(n):
for col in range(n):
if 0 <= random() < p: champ[lig][col] = "💣"
return champ
# essai:
creation_fichier_html("essai", cree_champ_de_mines(10, 0.3))
Création des indications☘
Chaque cellule qui ne contient pas une bombe doit contenir le nombre de bombes présentes dans les cellules voisines.
Une cellule est considérée voisine d'une autre si elle présente un côté ou un sommet commun. Ainsi, une cellule hors des bords a 8 voisines.
Liste des voisins☘
Compléter la fonction ci-dessous permettant de calculer la liste des voisins d'une cellule (contenant ou non des bombes).
def voisinage(colonne, ligne, n):
"""
colonne: entier entre 0 et n-1
ligne: entier entre 0 et n-1
n: entier représentant le nombre de lignes
(et de colonnes) d'une matrice champ de mines.
renvoie la liste des voisins sous la forme
de couples (numéro de colonne, numéro de ligne)
de la cellule de coordonnées (colonne, ligne).
(Attention aux cellules de bordure...)
"""
Exemples.
>>> voisinage(0,0,5)
[(1, 0), (0, 1), (1, 1)]
>>> voisinage(1,1,5)
[(0, 0), (1, 0), (2, 0), (0, 1), (2, 1), (0, 2), (1, 2), (2, 2)]
Solution
Un code possible:
def voisinage(colonne, ligne, n):
"""
colonne: entier entre 0 et n-1
ligne: entier entre 0 et n-1
n: entier représentant le nombre de lignes
(et de colonnes) d'une matrice champ de mines.
renvoie la liste des voisins sous la forme
de couples (numéro de colonne, numéro de ligne)
de la cellule de coordonnées (colonne, ligne).
(Attention aux cellules de bordure...)
"""
x = colonne
y = ligne
voisins = [ (x-1,y-1), (x,y-1), (x+1,y-1),
(x-1,y), (x+1,y),
(x-1,y+1), (x,y+1), (x+1,y+1) ]
return [ v for v in voisins if 0<= v[0] < n and 0 <= v[1] < n]
Nombre de bombes voisines☘
Compléter:
def compte_bombes_voisines(colonne, ligne, champ):
"""
champ est une matrice carrée représentant un champ de mines.
colonne, ligne: coordonnées d'une cellule du champ.
renvoie le nombre de bombes présentes dans les cellules voisines
de la cellule (colonne, ligne).
"""
Solution
def compte_bombes_voisines(colonne, ligne, champ):
"""
champ est une matrice carrée représentant un champ de mines.
colonne, ligne: coordonnées d'une cellule du champ.
renvoie le nombre de bombes présentes dans les cellules voisines
de la cellule (colonne, ligne).
"""
compteur_bombes = 0
for v in voisinage(colonne, ligne, len(champ)):
if champ[v[1]][v[0]] == "💣" :
compteur_bombes += 1
return compteur_bombes
Mise à jour des indications de la grille☘
Il s'agit maintenant de parcourir toute la grille et de placer, dans chaque cellule qui ne contient pas une bombe, le nombre de bombes présentes dans les cellules voisines.
def place_indications(champ):
"""
champ est une matrice carrée représentant un champ de mines.
la fonction met à jour cette matrice en plaçant
dans chaque cellule qui ne contient pas une bombe,
le nombre de bombes présentes dans les cellules voisines.
"""
Solution
def place_indications(champ):
"""
champ est une matrice carrée représentant un champ de mines.
la fonction met à jour cette matrice en plaçant
dans chaque cellule qui ne contient pas une bombe,
le nombre de bombes présentes dans les cellules voisines.
"""
for lig in range(n):
for col in range(n):
if champ[lig][col] != "💣" :
champ[lig][col] = compte_bombes_voisines(col, lig, champ)
Code complet☘
Récapitulatif du code des fonctions
from affichage import *
from random import random
def cree_champ_de_mines(n, p):
"""
crée une matrice carrée de taille n
avec des mines disséminées au hasard.
Chaque cellule reçoit une mine avec une proba p.
"""
champ = [[0 for col in range(n)] for lig in range(n)]
for lig in range(n):
for col in range(n):
if 0 <= random() < p: champ[lig][col] = "💣"
return champ
def voisinage(colonne, ligne, n):
"""
colonne: entier entre 0 et n-1
ligne: entier entre 0 et n-1
n: entier représentant le nombre de lignes
(et de colonnes) d'une matrice champ de mines.
renvoie la liste des voisins sous la forme
de couples (numéro de colonne, numéro de ligne)
de la cellule de coordonnées (colonne, ligne).
(Attention aux cellules de bordure...)
"""
x = colonne
y = ligne
voisins = [ (x-1,y-1), (x,y-1), (x+1,y-1),
(x-1,y), (x+1,y),
(x-1,y+1), (x,y+1), (x+1,y+1) ]
return [ v for v in voisins if 0<= v[0] < n and 0 <= v[1] < n]
def compte_bombes_voisines(colonne, ligne, champ):
"""
champ est une matrice carrée représentant un champ de mines.
colonne, ligne: coordonnées d'une cellule du champ.
renvoie le nombre de bombes présentes dans les cellules voisines
de la cellule (colonne, ligne).
"""
compteur_bombes = 0
for v in voisinage(colonne, ligne, len(champ)):
if champ[v[1]][v[0]] == "💣" :
compteur_bombes += 1
return compteur_bombes
def place_indications(champ):
"""
champ est une matrice carrée représentant un champ de mines.
la fonction met à jour cette matrice en plaçant
dans chaque cellule qui ne contient pas une bombe,
le nombre de bombres présentes dans les cellules voisines.
"""
for lig in range(n):
for col in range(n):
if champ[lig][col] != "💣" :
champ[lig][col] = compte_bombes_voisines(col, lig, champ)
# un test avec création fichier html:
n = 10
p = 0.3
champ = cree_champ_de_mines(n, p)
place_indications(champ)
creation_fichier_html("essai", cree_champ_de_mines(10, 0.3))