summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenise sur Lya <sekhmet@lya>2021-07-28 10:31:46 +0200
committerDenise sur Lya <sekhmet@lya>2021-07-28 10:31:46 +0200
commit77986b320dfc33625ea2df7f4049cb6c7f8c222e (patch)
tree9ae157349f22c52d99b3657523283e241f84b3f0
parentea3e2d07911b2f4d3ff044c4a7bfd4e8c77be937 (diff)
downloadbingo-77986b320dfc33625ea2df7f4049cb6c7f8c222e.tar.gz
bingo-77986b320dfc33625ea2df7f4049cb6c7f8c222e.tar.zst
bingo-77986b320dfc33625ea2df7f4049cb6c7f8c222e.zip
Améliorations diverses. Lancement officiel de la bêta !
-rw-r--r--app.py13
-rw-r--r--config.py4
-rw-r--r--data/bingo_data.txt20
-rw-r--r--data_textes.py91
-rw-r--r--gere_grille.py67
-rw-r--r--static/outilspage.js61
-rw-r--r--static/style.css8
-rw-r--r--templates/custom.html16
-rw-r--r--templates/index.html18
9 files changed, 251 insertions, 47 deletions
diff --git a/app.py b/app.py
index 8b558ea..6ef4667 100644
--- a/app.py
+++ b/app.py
@@ -10,7 +10,8 @@ Created on Mon Jul 26 17:31:48 2021
10# -*- coding: utf-8 -*- 10# -*- coding: utf-8 -*-
11 11
12import flask 12import flask
13from data_textes import liste_textes 13
14from data_textes import tabletextes, tablecomplete, extraire_textes_par_cat
14import gere_grille as g 15import gere_grille as g
15import gere_erreurs as e 16import gere_erreurs as e
16from config import DEFAUT, CONFIG 17from config import DEFAUT, CONFIG
@@ -32,11 +33,12 @@ app = flask.Flask(__name__)
32@app.route('/', methods=["GET", "POST"]) 33@app.route('/', methods=["GET", "POST"])
33def index(): 34def index():
34 liste_err = e.initialise_erreurs() 35 liste_err = e.initialise_erreurs()
36 #print(tabletextes)
35 idg = flask.request.args.get("grille", "") # Id de grille passée en param (ou pas) 37 idg = flask.request.args.get("grille", "") # Id de grille passée en param (ou pas)
36 if idg != "": # Si on a mis un url de grille 38 if idg != "": # Si on a mis un url de grille
37 conf = g.decode_grille(idg, liste_err) 39 conf = g.decode_grille(idg, liste_err)
38 if conf == {}: # Erreur à la génération 40 if conf == {}: # Erreur à la génération
39 bingo = g.genere_grille(DEFAUT, liste_textes) 41 bingo = g.genere_grille(DEFAUT, tabletextes)
40 conf = DEFAUT.copy() 42 conf = DEFAUT.copy()
41 e.erreur("L'url de la grille n'est pas valide...", liste_err) 43 e.erreur("L'url de la grille n'est pas valide...", liste_err)
42 else: 44 else:
@@ -47,7 +49,7 @@ def index():
47 conf = g.gere_donnees_custom(flask.request.form, liste_err) 49 conf = g.gere_donnees_custom(flask.request.form, liste_err)
48 else: 50 else:
49 conf= DEFAUT.copy() 51 conf= DEFAUT.copy()
50 bingo = g.genere_grille(conf, liste_textes) # aléatoire 52 bingo = g.genere_grille(conf, tabletextes) # aléatoire
51 53
52 chainecode = g.encode_grille(conf, bingo, liste_err) 54 chainecode = g.encode_grille(conf, bingo, liste_err)
53 55
@@ -57,7 +59,10 @@ def index():
57@app.route('/custom') 59@app.route('/custom')
58def custom(): 60def custom():
59 liste_err = e.initialise_erreurs() 61 liste_err = e.initialise_erreurs()
60 return flask.render_template("custom.html", DEFAUT=DEFAUT,CONFIG=CONFIG, e=liste_err[0]+liste_err[1]+liste_err[2]) 62 categ, tableqr = extraire_textes_par_cat(tablecomplete)
63 nombre_categ = [len(elt) for elt in tableqr]
64 print(nombre_categ)
65 return flask.render_template("custom.html", DEFAUT=DEFAUT,CONFIG=CONFIG, nbdata=len(tabletextes), categ=categ, nbparcat = nombre_categ, e=liste_err[0]+liste_err[1]+liste_err[2])
61 66
62if __name__ == "__main__": 67if __name__ == "__main__":
63 # print("Mode debug maison : "+str(niveau_debug)) 68 # print("Mode debug maison : "+str(niveau_debug))
diff --git a/config.py b/config.py
index deb461a..eafe94d 100644
--- a/config.py
+++ b/config.py
@@ -12,7 +12,7 @@ DEFAUT["titre"] = "Le bingo de l'allaitement"
12DEFAUT["nblignes"] = 4 12DEFAUT["nblignes"] = 4
13DEFAUT["nbcolonnes"] = 3 13DEFAUT["nbcolonnes"] = 3
14DEFAUT["nbcasesvides"] = 0 14DEFAUT["nbcasesvides"] = 0
15 15DEFAUT["reponses_presentes"] = True # veut-on proposer les réponses
16 16
17# Configuration 17# Configuration
18 18
@@ -21,4 +21,4 @@ CONFIG["lmax_titre"] = 50
21CONFIG["maxlignes"] = 20 21CONFIG["maxlignes"] = 20
22CONFIG["minlignes"] = 1 22CONFIG["minlignes"] = 1
23CONFIG["maxcolonnes"] = 20 23CONFIG["maxcolonnes"] = 20
24CONFIG["mincolonnes"] = 1 \ No newline at end of file 24CONFIG["mincolonnes"] = 1
diff --git a/data/bingo_data.txt b/data/bingo_data.txt
new file mode 100644
index 0000000..0d25331
--- /dev/null
+++ b/data/bingo_data.txt
@@ -0,0 +1,20 @@
1"Allaitement","Tu vas l'allaiter jusqu'à [X] ?","Jusqu'à ce qu'il ait son permis !"
2"Allaitement","Tu es sûre que tu as encore/assez de lait ?"
3"Allaitement","Quand est-ce que tu vas lui donner du lait normal ?","J'hésite encore entre le lait de baleine et le lait d'ourse, tu en penses quoi ?"
4"Allaitement","Ton lait n'est pas assez nourrissant.","Probablement plus que ton sperme !"
5"Allaitement","Donne-lui un biberon, tu vois bien que bébé a faim."
6"Allaitement","Donne-lui un biberon, ça le/la calera pour la nuit."
7"Allaitement","Tu arrêteras quand bébé aura des dents"
8"Allaitement","Tu ne devrais pas l'endormir au sein"
9"Allaitement","Encore au sein ?"
10
11"Sommeil","Bébé fait (enfin) ses nuits ?","Et toi, tu fais tes nuits ?","Bébé fait SES nuits bien à lui/elle.","Oui.","Non."
12"Sommeil","Bébé dort (encore) avec vous ?"
13"Sommeil","Laisse bébé pleurer il/elle finira bien par dormir."
14"Sommeil","Il faut lui donner un rythme."
15
16"Pleurs","Laisse bébé pleurer, ça lui fera les poumons."
17
18"Éducation","Il/elle doit apprendre à se détacher de maman."
19
20"Divers","Tu as pris combien de kilos ?"
diff --git a/data_textes.py b/data_textes.py
index 8082ecf..85baa54 100644
--- a/data_textes.py
+++ b/data_textes.py
@@ -6,17 +6,80 @@ Created on Mon Jul 26 22:50:08 2021
6@author: sekhmet 6@author: sekhmet
7""" 7"""
8 8
9liste_textes = [ 9#liste_textes = [
10 "Tu vas pas l'allaiter jusqu'à [âge quelconque] !", 10# "Tu vas pas l'allaiter jusqu'à [âge quelconque] !",
11 "Tu es sûre que tu as assez de lait ?", 11# "Tu es sûre que tu as assez de lait ?",
12 "Quand est-ce que tu vas lui donner du lait normal ?", 12# "Quand est-ce que tu vas lui donner du lait normal ?",
13 "Il/elle fait ses nuits ?", 13# "Il/elle fait ses nuits ?",
14 "Il/elle dort encore avec vous ?", 14# "Il/elle dort encore avec vous ?",
15 "Laisse le/la pleurer il/elle finira bien par dormir (et/ou ça lui fera les poumons).", 15# "Laisse le/la pleurer il/elle finira bien par dormir (et/ou ça lui fera les poumons).",
16 "Ton lait n'est pas/plus assez nourrissant.", 16# "Ton lait n'est pas/plus assez nourrissant.",
17 "Il/elle doit apprendre à se détacher de maman.", 17# "Il/elle doit apprendre à se détacher de maman.",
18 "Tu as pris combien de kilos ?", 18# "Tu as pris combien de kilos ?",
19 "Donne lui un biberon, il/elle fera ses nuits.", 19# "Donne lui un biberon, il/elle fera ses nuits.",
20 "Tu arrêteras quand il/elle aura des dents, puisqu'il/elle va te mordre", 20# "Tu arrêteras quand il/elle aura des dents, puisqu'il/elle va te mordre",
21 21#
22 ] \ No newline at end of file 22# ]
23
24import csv
25
26chemin_data = "data/"
27fichier_bingo = chemin_data+"bingo_data.txt"
28# Au format : catégorie, phrase, réponses.
29
30#fichier_FAQ = chemin_data+"FAQ_data.txt"
31#fichier_changelog = chemin_data+"changelog_data.txt"
32
33
34
35def lire_fichier_csv_simple(fichier, minlong=2):
36 """ lire un fichier csv et le renvoyer en tableau de tableaux
37 minlong est la longueur minimale d'une ligne pour que ça soit accepté
38 (plus court on ne met même pas)"""
39 table=[]
40 with open(fichier, "r") as fichier_csv:
41 reader_notes = csv.reader(fichier_csv,delimiter=",",dialect="unix")
42 for ligne in reader_notes:
43 if len(ligne) >= minlong: # La ligne doit avoir plus de deux éléments
44 table.append(ligne)
45 return table
46
47def extraire_categories(table):
48 """ extrait les catégories (1ere colonne du tableau de tableau)
49 renvoie sous forme de liste"""
50 liste_cat = []
51 for ligne in table:
52 if not (ligne[0] in liste_cat):
53 liste_cat.append(ligne[0])
54 return liste_cat
55
56def extraire_textes_par_cat(table):
57 """ construit deux tables : une de catégories (liste simple)
58 une autre qui est un tableau dont chaque élément est un tuple
59 (phrase, reponses) où reponses est une liste (éventuellement vide)
60
61 categ[i] va correspondre à tableqr[i] en terme de catégorie"""
62 categ = extraire_categories(table)
63 tableqr = [ [] for i in range(len(categ)) ]
64
65 for ligne in table:
66 try:
67 cat = ligne[0]
68 q = ligne[1]
69 lister = ligne[2:] # Le reste
70 ind = categ.index(cat)
71 tableqr[ind].append((q,lister))
72 except:
73 print("Impossible de lire la ligne : "+str(ligne))
74
75 return (categ,tableqr)
76
77def extraire_qr(table):
78 """ on enlève juste la catégorie en début de ligne"""
79 table2 = [ ligne[1:] for ligne in table]
80 return table2
81
82tablecomplete = lire_fichier_csv_simple(fichier_bingo)
83tabletextes = extraire_qr(tablecomplete)
84
85#liste_cat, liste_textes = extraire_textes_par_cat(lire_fichier_csv_simple(fichier_bingo)) \ No newline at end of file
diff --git a/gere_grille.py b/gere_grille.py
index 9a472ed..6898f52 100644
--- a/gere_grille.py
+++ b/gere_grille.py
@@ -5,31 +5,49 @@ Created on Mon Jul 26 22:58:28 2021
5 5
6@author: sekhmet 6@author: sekhmet
7""" 7"""
8import random 8import random, zlib, base64, json
9import zlib, base64, json
10import gere_erreurs as e 9import gere_erreurs as e
11from config import DEFAUT, CONFIG 10from config import DEFAUT, CONFIG
12 11
13def genere_grille(config, textes): 12def genere_grille(config, textes):
14 """ génère une grille avec des éléments aléatoires du tableau textes. Si y'a pas assez, on complète aléatoirement avec des 0. 13 """ génère une grille avec des éléments aléatoires du tableau textes.
15 config contient tout ce qu'on veut pour la grille""" 14 textes est un tableau de tableau : la phrase, puis les réponses
15 Dans la grille on mettra une liste avec la question et les réponses
16 Si y'a pas assez, on met la liste vide []
17
18 config contient tout ce qu'on veut pour la grille,
19 ici on utilisera les dimensions et les phrases_additionnelles
20 on enlève aussi les réponses si config['reponses_presentes'] n'est pas là"""
16 21
17 nblignes, nbcol = config["nblignes"], config["nbcolonnes"] 22 nblignes, nbcol = config["nblignes"], config["nbcolonnes"]
18 23
19 # Créer la grille
20 grille = [ [""]*nbcol for i in range(nblignes)]
21 24
22 nbdata = nbcol*nblignes - config["nbcasesvides"] # Nombre d'entrées 25 soustab = config.get("phrases_add",[]).copy() # On met les phrases custom en premier
26 soustab = soustab + [ [] ]*config["nbcasesvides"] # On ajoute les blocs vides voulus
27
28 #print(soustab)
23 29
24 # Créer le sous-tableau 30 nbdata = nbcol*nblignes - config["nbcasesvides"]-len(config.get("phrases_add", [])) # Nombre d'entrées à prendre
25 if len(textes)>= nbdata: # Si y'a assez de textes 31 if nbdata>0: # Sinon y'a pas besoin du tableau
26 soustab = random.sample(textes, nbdata) + ["0"]*config["nbcasesvides"] 32 if nbdata <= len(textes):
27 else: 33 soustab = soustab+random.sample(textes, nbdata)
28 # On met tous les textes + complète avec des "0" 34 else: # on n'a pas assez de textes, on met des 0
29 soustab = textes + ["0"]*(nbcol*nblignes - len(textes)) 35 soustab = soustab + textes + ['0']*(nbdata - len(textes))
30 random.shuffle(soustab) 36
31 #print(soustab) 37 #print(soustab)
38 # On mélange !
39 random.shuffle(soustab)
32 40
41 # Si on ne veut pas des réponses, on ne garde que le premier élément
42 if not(config.get("reponses_presentes", True)):
43 #print("Je veux pas les réponses !")
44 soustab = [ [elt[0] ] for elt in soustab ]
45 #print(soustab)
46
47
48 # Créer la grille
49 grille = [ [ [] ]*nbcol for i in range(nblignes)]
50
33 # On met tout ça dans la grille 51 # On met tout ça dans la grille
34 for i in range(nblignes): 52 for i in range(nblignes):
35 for j in range(nbcol): 53 for j in range(nbcol):
@@ -86,8 +104,21 @@ def gere_donnees_custom(data, liste_err):
86 # Les cases vides 104 # Les cases vides
87 conf["nbcasesvides"] = minimaxi(data.get("nbcasesvides",""), 0, CONFIG["maxlignes"]*CONFIG["maxcolonnes"], DEFAUT["nbcasesvides"], liste_err) 105 conf["nbcasesvides"] = minimaxi(data.get("nbcasesvides",""), 0, CONFIG["maxlignes"]*CONFIG["maxcolonnes"], DEFAUT["nbcasesvides"], liste_err)
88 106
107 # Les phrases additionnelles
108 conf["phrases_add"] = []
109 i=0
110 while "phrase_add_"+str(i) in data:
111 p = data.get("phrase_add_"+str(i), "")
112 if len(p)>1:
113 conf["phrases_add"].append([p])
114 i=i+1
115
116 # Veut-on les réponses ?
117 conf["reponses_presentes"] = gere_checkbox(data.get("reponses_presentes",""))
118
89 return conf 119 return conf
90### 120
121### Fonctions pour gérer les données saisies
91def minimaxi(donnee, mini, maxi, defaut, liste_err): 122def minimaxi(donnee, mini, maxi, defaut, liste_err):
92 """ donnee est une chaine qui est censée être un nombre entier. 123 """ donnee est une chaine qui est censée être un nombre entier.
93 On vérifie que la donnée est valide, qu'elle est bien dans l'inter 124 On vérifie que la donnée est valide, qu'elle est bien dans l'inter
@@ -98,4 +129,8 @@ def minimaxi(donnee, mini, maxi, defaut, liste_err):
98 e.warning("La donnée "+donnee+ "est invalide !", liste_err) 129 e.warning("La donnée "+donnee+ "est invalide !", liste_err)
99 x = defaut 130 x = defaut
100 x = max(mini, min(x, maxi)) 131 x = max(mini, min(x, maxi))
101 return x \ No newline at end of file 132 return x
133
134def gere_checkbox(donnee):
135 """ renvoie True si la donnee est à "on" et False sinon"""
136 return donnee == "on" \ No newline at end of file
diff --git a/static/outilspage.js b/static/outilspage.js
index b8db8b3..1ddb713 100644
--- a/static/outilspage.js
+++ b/static/outilspage.js
@@ -11,17 +11,25 @@ var couleur_valide = 'rgb(255, 136, 136)' ;
11 11
12// Valide la case et la colore en rouge 12// Valide la case et la colore en rouge
13function validecase(elem) { 13function validecase(elem) {
14 elem.style.backgroundColor = couleur_valide ; 14 if (elem.style.backgroundColor == couleur_valide) {
15 15 alterne_phrase_reponse(elem)
16 detectelignes() ; 16 } else {
17 elem.style.backgroundColor = couleur_valide ;
18 detectelignes() ;
19 }
20
17} 21}
18 22
19// efface la grille 23// efface la grille
20function effacegrille() { 24function effacegrille() {
21 var table=document.getElementById("grille") ; 25 var table=document.getElementById("grille") ;
22 var listetd = table.getElementsByTagName("td") ; 26 var listetd = table.getElementsByTagName("td") ;
27 var ltemp ;
23 for (var i=0; i< listetd.length; i++){ 28 for (var i=0; i< listetd.length; i++){
24 listetd[i].style.backgroundColor = couleur_base ; 29 if (!(listetd[i].classList.contains("vide"))) {
30 listetd[i].style.backgroundColor = couleur_base ;
31 affiche_phrase(listetd[i]) ;
32 }
25 } 33 }
26 metscore(0) ; 34 metscore(0) ;
27} 35}
@@ -151,3 +159,48 @@ function detectelignes(elem) {
151 score = (nb_lignes_completes + nb_colonnes_completes + nb_diagonales_1 + nb_diagonales_2) *points_par_ligne + nbcases ; 159 score = (nb_lignes_completes + nb_colonnes_completes + nb_diagonales_1 + nb_diagonales_2) *points_par_ligne + nbcases ;
152 metscore(score) ; 160 metscore(score) ;
153} 161}
162
163
164/* Outils divers */
165function ajouter_phrase_perso() {
166 var ul = document.getElementById("liste_phrases_add") ;
167 var nb = ul.children.length ;
168 var elt = document.createElement("li") ;
169 elt.innerHTML = '<input type="text" class="texte" name="phrase_add_'+nb+'">' ;
170 ul.appendChild(elt) ;
171
172}
173
174function alterne_phrase_reponse(elem) {
175 var liste = elem.children ;
176 // qui est actif ?
177 for(var i=0; i< liste.length; i++) {
178 if(liste[i].style.display != "none") {
179 liste[i].style.display = "none" ; // on efface celui-là
180 liste[(i+1) % liste.length].style.display = "block" ; // on met le suivant
181 break // on s'arrête là
182 }
183
184 }
185 /*
186 if(elem.getElementsByClassName("phrase")[0].style.display == "none"){
187 affiche_phrase(elem)
188 } else {
189 affiche_reponse(elem)
190 }*/
191}
192
193function affiche_reponse(elem) {
194 var ltemp = elem.getElementsByClassName("phrase") ;
195 if (ltemp.length >0) ltemp[0].style.display = "none" ;
196 ltemp = elem.getElementsByClassName("reponse")
197 if (ltemp.length >0) ltemp[0].style.display = "block" ;
198}
199
200function affiche_phrase(elem) {
201 var ltemp = elem.getElementsByClassName("phrase")
202 if (ltemp.length >0 ) ltemp[0].style.display = "block" ;
203 ltemp = elem.getElementsByClassName("reponse")
204 for (var i=0; i<ltemp.length; i++) ltemp[i].style.display = "none" ;
205}
206
diff --git a/static/style.css b/static/style.css
index fa5f191..36d5569 100644
--- a/static/style.css
+++ b/static/style.css
@@ -15,6 +15,7 @@
15 padding: 1px ; 15 padding: 1px ;
16 margin: 30px ; 16 margin: 30px ;
17 border: 1px solid black ; 17 border: 1px solid black ;
18 table-layout: fixed;
18} 19}
19 20
20#grille td { 21#grille td {
@@ -29,6 +30,12 @@
29 background-color:#999999 ; 30 background-color:#999999 ;
30} 31}
31 32
33.reponse {
34 display: none ;
35 font-style: italic ;
36}
37
38
32/* Formulaire page custom */ 39/* Formulaire page custom */
33.texte { 40.texte {
34 width:20em 41 width:20em
@@ -36,3 +43,4 @@
36 43
37.data { 44.data {
38 width:3em 45 width:3em
46
diff --git a/templates/custom.html b/templates/custom.html
index cc5521c..b3aed77 100644
--- a/templates/custom.html
+++ b/templates/custom.html
@@ -21,9 +21,21 @@
21 <li>Titre de la page : <input class="texte" type="text" name="titre" value="{{ DEFAUT.titre }}"></li> 21 <li>Titre de la page : <input class="texte" type="text" name="titre" value="{{ DEFAUT.titre }}"></li>
22 <li>Nombre de lignes : <input class="data" type="number" min="{{ CONFIG.minlignes }}" max="{{ CONFIG.maxlignes}}" name="nblignes" value="{{ DEFAUT.nblignes }}"></li> 22 <li>Nombre de lignes : <input class="data" type="number" min="{{ CONFIG.minlignes }}" max="{{ CONFIG.maxlignes}}" name="nblignes" value="{{ DEFAUT.nblignes }}"></li>
23 <li>Nombre de colonnes : <input class="data" type="number" min="{{ CONFIG.mincolonnes }}" max="{{ CONFIG.maxcolonnes }}" name="nbcolonnes" value="{{ DEFAUT.nbcolonnes }}"></li> 23 <li>Nombre de colonnes : <input class="data" type="number" min="{{ CONFIG.mincolonnes }}" max="{{ CONFIG.maxcolonnes }}" name="nbcolonnes" value="{{ DEFAUT.nbcolonnes }}"></li>
24 <li>Nombre de cases vides : <input class="data" type="number" min="0" name="nbcasesvides" value="{{ DEFAUT.nbcasesvides }}"> <span class="petit">Remarque : s'il n'y a pas assez de données, la grille sera automatiquement complétée par des cass vides.</span></li> 24 <li>Nombre de cases vides : <input class="data" type="number" min="0" name="nbcasesvides" value="{{ DEFAUT.nbcasesvides }}"> <span class="petit">Remarque : s'il n'y a pas assez de données, la grille sera automatiquement complétée par des cases vides. Il y a actuellement {{ nbdata }} entrées disponibles.</span></li>
25 25
26 <li>Proposer les réponses : <input type="checkbox" name="reponses_presentes" {% if DEFAUT.reponses_presentes %} checked{% endif %}></li>
26 27
28 <li>Ajouter une (ou des) phrase(s) personnalisée <span class="cliquable" onclick="ajouter_phrase_perso()">(plus !)</span> :
29 <ul id="liste_phrases_add"><li><input type="text" class="texte" name="phrase_add_0"></li>
30 </ul>
31 </li>
32
33 <li>Choisir les catégories de remarques :
34 <ul>
35 {% for cat in categ %}
36 <li>{{ cat }} <input type="checkbox" name="categorie_{{cat}}" checked> ({{ nbparcat[loop.index -1] }} phrase(s))</li>
37 {% endfor %}
38 </ul></li>
27</ul> 39</ul>
28<input type="submit" name="zou" value="Je veux une grille !"> 40<input type="submit" name="zou" value="Je veux une grille !">
29 41
diff --git a/templates/index.html b/templates/index.html
index 852fdd7..af8ac6c 100644
--- a/templates/index.html
+++ b/templates/index.html
@@ -16,14 +16,22 @@
16<div id="contenu"> 16<div id="contenu">
17 17
18<p>Cochez la case dès que vous entendez une réplique idiote !</p> 18<p>Cochez la case dès que vous entendez une réplique idiote !</p>
19{% if conf.reponses_presentes %}
20<p>Un deuxième clic permet d'afficher (ou de masquer) une réponse épique !</p>{%endif %}
19<table id="grille"> 21<table id="grille">
20{% for ligne in bingo %} 22{% for ligne in bingo %}
21<tr>{% for elt in ligne %} 23<tr>{% for elt in ligne %}
22 {% if elt == "0" %} 24 {% if elt | length == 0 %} <td class="vide"></td>
23 <td class="vide"></td> 25 {% else %}<td onmousedown='validecase(this)'>
24 {% else %} 26 {% for p in elt %}
25 <td onclick='validecase(this)'>{{ elt }}</td> 27 {% if loop.index == 1 %}
26 {% endif %} 28 <span class="phrase" >{{ p }}</span>
29 {% else %}
30 <span class="reponse">{{ p }}</span>
31 {% endif %}
32 {% endfor %}
33 </td>
34 {% endif %}
27 {% endfor %} 35 {% endfor %}
28</tr> 36</tr>
29{% endfor %} 37{% endfor %}