summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app.py64
-rw-r--r--config.py24
-rw-r--r--data_textes.py22
-rw-r--r--gere_erreurs.py37
-rw-r--r--gere_grille.py101
-rw-r--r--static/outilspage.js153
-rw-r--r--static/style.css38
-rw-r--r--templates/base.html31
-rw-r--r--templates/custom.html35
-rw-r--r--templates/faq.html30
-rw-r--r--templates/index.html42
11 files changed, 577 insertions, 0 deletions
diff --git a/app.py b/app.py
new file mode 100644
index 0000000..8b558ea
--- /dev/null
+++ b/app.py
@@ -0,0 +1,64 @@
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3"""
4Created on Mon Jul 26 17:31:48 2021
5
6@author: sekhmet
7"""
8
9#!/usr/bin/env python3
10# -*- coding: utf-8 -*-
11
12import flask
13from data_textes import liste_textes
14import gere_grille as g
15import gere_erreurs as e
16from config import DEFAUT, CONFIG
17
18
19def initialise_mode_beta():
20 global beta
21 hote = flask.request.host
22 if hote[:4] == "beta":
23 print("** Mode bêta !**")
24 return True
25 else:
26 return False
27
28
29app = flask.Flask(__name__)
30
31
32@app.route('/', methods=["GET", "POST"])
33def index():
34 liste_err = e.initialise_erreurs()
35 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
37 conf = g.decode_grille(idg, liste_err)
38 if conf == {}: # Erreur à la génération
39 bingo = g.genere_grille(DEFAUT, liste_textes)
40 conf = DEFAUT.copy()
41 e.erreur("L'url de la grille n'est pas valide...", liste_err)
42 else:
43 bingo=conf["grille"]
44 else:
45 # On récupère les données post (et ça sera défaut si y'a rien)
46 if flask.request.method == "POST":
47 conf = g.gere_donnees_custom(flask.request.form, liste_err)
48 else:
49 conf= DEFAUT.copy()
50 bingo = g.genere_grille(conf, liste_textes) # aléatoire
51
52 chainecode = g.encode_grille(conf, bingo, liste_err)
53
54 return flask.render_template("index.html", bingo=bingo, chainecode=chainecode, conf=conf, e=liste_err[0]+liste_err[1]+liste_err[2])
55
56
57@app.route('/custom')
58def custom():
59 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])
61
62if __name__ == "__main__":
63 # print("Mode debug maison : "+str(niveau_debug))
64 app.run(host='0.0.0.0',debug=True) \ No newline at end of file
diff --git a/config.py b/config.py
new file mode 100644
index 0000000..deb461a
--- /dev/null
+++ b/config.py
@@ -0,0 +1,24 @@
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3"""
4Configuration générale
5"""
6
7# Configuration par défaut
8DEFAUT = {}
9
10DEFAUT["titre"] = "Le bingo de l'allaitement"
11
12DEFAUT["nblignes"] = 4
13DEFAUT["nbcolonnes"] = 3
14DEFAUT["nbcasesvides"] = 0
15
16
17# Configuration
18
19CONFIG = {}
20CONFIG["lmax_titre"] = 50
21CONFIG["maxlignes"] = 20
22CONFIG["minlignes"] = 1
23CONFIG["maxcolonnes"] = 20
24CONFIG["mincolonnes"] = 1 \ No newline at end of file
diff --git a/data_textes.py b/data_textes.py
new file mode 100644
index 0000000..8082ecf
--- /dev/null
+++ b/data_textes.py
@@ -0,0 +1,22 @@
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3"""
4Created on Mon Jul 26 22:50:08 2021
5
6@author: sekhmet
7"""
8
9liste_textes = [
10 "Tu vas pas l'allaiter jusqu'à [âge quelconque] !",
11 "Tu es sûre que tu as assez de lait ?",
12 "Quand est-ce que tu vas lui donner du lait normal ?",
13 "Il/elle fait ses nuits ?",
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).",
16 "Ton lait n'est pas/plus assez nourrissant.",
17 "Il/elle doit apprendre à se détacher de maman.",
18 "Tu as pris combien de kilos ?",
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",
21
22 ] \ No newline at end of file
diff --git a/gere_erreurs.py b/gere_erreurs.py
new file mode 100644
index 0000000..0a12018
--- /dev/null
+++ b/gere_erreurs.py
@@ -0,0 +1,37 @@
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3"""
4Created on Tue Jul 27 11:16:54 2021
5
6@author: sekhmet
7"""
8
9## Gestion des erreurs en flask
10import sys
11
12niveau_debug = ("debug" in sys.argv)
13
14def initialise_erreurs():
15 """ retourne trois listes vides, erreurs fatales (0), warnings(1), debug(2):"""
16 return ([],[],[])
17
18
19def erreur(message,listeerreurs):
20 """ en cas d'erreur où on ne peut pas continuer
21 message est une chaîne"""
22 print("** Erreur fatale : "+message)
23 listeerreurs[0].append("** Erreur : "+message)
24
25def warning(message,listeerreurs):
26 """ En cas d'avertissement mais on peut quand même continuer """
27 print("** Warning : "+message)
28 message = "Alerte : "+message
29 if message not in listeerreurs[1]:
30 listeerreurs[1].append(message)
31
32def debug(message,listeerreurs):
33 global niveau_debug
34 if niveau_debug:
35 print("##Debug : "+message)
36 listeerreurs[2].append("# Debug : "+message)
37 \ No newline at end of file
diff --git a/gere_grille.py b/gere_grille.py
new file mode 100644
index 0000000..9a472ed
--- /dev/null
+++ b/gere_grille.py
@@ -0,0 +1,101 @@
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3"""
4Created on Mon Jul 26 22:58:28 2021
5
6@author: sekhmet
7"""
8import random
9import zlib, base64, json
10import gere_erreurs as e
11from config import DEFAUT, CONFIG
12
13def 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.
15 config contient tout ce qu'on veut pour la grille"""
16
17 nblignes, nbcol = config["nblignes"], config["nbcolonnes"]
18
19 # Créer la grille
20 grille = [ [""]*nbcol for i in range(nblignes)]
21
22 nbdata = nbcol*nblignes - config["nbcasesvides"] # Nombre d'entrées
23
24 # Créer le sous-tableau
25 if len(textes)>= nbdata: # Si y'a assez de textes
26 soustab = random.sample(textes, nbdata) + ["0"]*config["nbcasesvides"]
27 else:
28 # On met tous les textes + complète avec des "0"
29 soustab = textes + ["0"]*(nbcol*nblignes - len(textes))
30 random.shuffle(soustab)
31 #print(soustab)
32
33 # On met tout ça dans la grille
34 for i in range(nblignes):
35 for j in range(nbcol):
36 grille[i][j] = soustab[i*nbcol+j]
37
38 return grille
39
40def encode_grille(config, grille, liste_err):
41 """ grille est un tableau double qu'on veut sauvegarder.
42 config est la configuration (on va garder le titre avec)
43 Renvoie une chaîne de caractères qui encode cette grille
44 de manière condensée. Renvoie une chaîne cheloue"""
45 # Chaîne de caractère
46 data = {"titre": config["titre"], "grille": grille}
47 chaine = json.dumps(data)
48 code = zlib.compress(chaine.encode())
49 chaineencodee = str(base64.urlsafe_b64encode(code))
50 e.debug(chaineencodee, liste_err)
51 return chaineencodee[2:-1] # Enlever le b' devant et le ' à la fin
52
53def decode_grille(chaineencodee, liste_err):
54 """ l'inverse de la fonction précédente : renvoie le dictionnaire
55 avec les params et la grille reconstituée
56 """
57 e.debug(chaineencodee, liste_err)
58 b2 = base64.urlsafe_b64decode(chaineencodee)
59 try:
60 decodee = zlib.decompress(b2)
61 except:
62 e.erreur("Impossible de décoder la chaîne : "+chaineencodee, liste_err)
63 return {}
64 # Remettre ça en python
65 data = json.loads(decodee)
66 return data
67
68###########################
69
70def gere_donnees_custom(data, liste_err):
71 """ data est le dictionnaire de requête. Gère les données reçues
72 et en fait un dictionnaire propre, en mettant les défauts là où
73 c'est pas bon"""
74
75 conf =DEFAUT.copy()
76
77 ## Le titre
78 t = data.get("titre", "")
79 if len(t) > 0:
80 conf["titre"] = t[0:CONFIG["lmax_titre"]]
81
82 # Les dimensions
83 conf["nblignes"] = minimaxi(data.get("nblignes",""), CONFIG["minlignes"], CONFIG["maxlignes"], DEFAUT["nblignes"], liste_err)
84 conf["nbcolonnes"] = minimaxi(data.get("nbcolonnes",""), CONFIG["mincolonnes"], CONFIG["maxcolonnes"], DEFAUT["nbcolonnes"], liste_err)
85
86 # Les cases vides
87 conf["nbcasesvides"] = minimaxi(data.get("nbcasesvides",""), 0, CONFIG["maxlignes"]*CONFIG["maxcolonnes"], DEFAUT["nbcasesvides"], liste_err)
88
89 return conf
90###
91def minimaxi(donnee, mini, maxi, defaut, liste_err):
92 """ 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
94 valle mini, maxi et si ça foire on met le défaut"""
95 try:
96 x = int(donnee)
97 except:
98 e.warning("La donnée "+donnee+ "est invalide !", liste_err)
99 x = defaut
100 x = max(mini, min(x, maxi))
101 return x \ No newline at end of file
diff --git a/static/outilspage.js b/static/outilspage.js
new file mode 100644
index 0000000..b8db8b3
--- /dev/null
+++ b/static/outilspage.js
@@ -0,0 +1,153 @@
1/* Calcul des scores */
2var points_par_case = 1 ;
3var points_par_ligne = 10 ;
4
5
6
7// Couleurs des cases
8var couleur_base = "rgb(238, 238, 238)" ;
9var couleur_valide = 'rgb(255, 136, 136)' ;
10
11
12// Valide la case et la colore en rouge
13function validecase(elem) {
14 elem.style.backgroundColor = couleur_valide ;
15
16 detectelignes() ;
17}
18
19// efface la grille
20function effacegrille() {
21 var table=document.getElementById("grille") ;
22 var listetd = table.getElementsByTagName("td") ;
23 for (var i=0; i< listetd.length; i++){
24 listetd[i].style.backgroundColor = couleur_base ;
25 }
26 metscore(0) ;
27}
28
29// mettre à jour le score si on veut
30function metscore(score) {
31 document.getElementById("score").innerHTML = score ;
32}
33
34// Compte les lignes, colonnes et diagonales de la grille et met à jour le score
35function detectelignes(elem) {
36 var table=document.getElementById("grille") ;
37 var listelignes = table.getElementsByTagName("tr") ;
38 var nblignes = listelignes.length ;
39 var nbcolonnes = listelignes[0].children.length ;
40 var i, j ;
41
42 // lignes
43 var nb_lignes_completes = 0 ;
44 var remplie ;
45 for(i=0; i<nblignes; i++) {
46 remplie = true ;
47 for(j=0; j<nbcolonnes; j++) {
48 //alert(j) ;
49 //alert(listelignes[i].children[j].style.backgroundColor) ;
50 if(listelignes[i].children[j].style.backgroundColor != couleur_valide) {
51 // c'est pas une ligne, dommage
52 remplie = false ;
53 //alert("la ligne "+i+"n'est pas remplie, vu à la colonne "+j) ;
54 break
55 }
56 }
57 if(remplie) {
58 nb_lignes_completes+=1 ;
59 }
60 }
61
62 // Colonnes
63 var nb_colonnes_completes = 0 ;
64 for(j=0; j<nbcolonnes; j++) {
65 remplie = true ;
66 for (i=0; i<nblignes; i++) {
67 if(listelignes[i].children[j].style.backgroundColor != couleur_valide) {
68 // c'est pas une colonne, dommage
69 remplie = false ;
70 break
71 }
72 }
73 if (remplie) {
74 nb_colonnes_completes+=1 ;
75 }
76 }
77
78 // Diagonales.
79 var nb_diagonales_1 = 0 ;
80 var nb_diagonales_2 = 0 ;
81 if(nblignes <= nbcolonnes) {
82 // Les diagonales se comptent horizontalement : "\\\" et "///"
83 for(i=0; i<nbcolonnes - nblignes +1; i++) {
84 // diagonales "\"
85 remplie=true ;
86 for(j=0; j<nblignes; j++) {
87 if(listelignes[j].children[i+j].style.backgroundColor != couleur_valide) {
88 remplie = false
89 break
90 }
91 }
92 if (remplie) {
93 nb_diagonales_1+=1
94 }
95
96 // diagonales "/"
97 remplie=true ;
98 for(j=0; j<nblignes; j++) {
99 if(listelignes[j].children[nbcolonnes-i-j-1].style.backgroundColor != couleur_valide) {
100 remplie = false
101 break
102 }
103 }
104 if (remplie) {
105 nb_diagonales_2+=1
106 }
107 }
108
109 } else { // les diagonales vont se compter "verticalement"
110 for(i=0; i<nblignes - nbcolonnes +1; i++) {
111 // diagonales "\"
112 remplie=true ;
113 for(j=0; j<nbcolonnes; j++) {
114 if(listelignes[i+j].children[j].style.backgroundColor != couleur_valide) {
115 remplie = false
116 break
117 }
118 }
119 if (remplie) {
120 nb_diagonales_1+=1
121 }
122
123 // diagonales "/"
124 remplie=true ;
125 for(j=0; j<nbcolonnes; j++) {
126 if(listelignes[nblignes -i-j-1].children[j].style.backgroundColor != couleur_valide) {
127 remplie = false
128 break
129 }
130 }
131 if (remplie) {
132 nb_diagonales_2+=1
133 }
134 }
135
136
137 }
138 // Compter les cases utilisées
139 var nbcases = 0 ;
140 for(i=0; i<nblignes; i++) {
141 for(j=0; j<nbcolonnes; j++) {
142 if (listelignes[i].children[j].style.backgroundColor == couleur_valide) {
143 nbcases+=1
144 }
145 }
146
147 }
148
149
150 // Mettre le score à jour
151 score = (nb_lignes_completes + nb_colonnes_completes + nb_diagonales_1 + nb_diagonales_2) *points_par_ligne + nbcases ;
152 metscore(score) ;
153}
diff --git a/static/style.css b/static/style.css
new file mode 100644
index 0000000..fa5f191
--- /dev/null
+++ b/static/style.css
@@ -0,0 +1,38 @@
1/* Styles divers */
2.cliquable {
3 cursor: pointer;
4 text-decoration: underline;
5}
6
7.petit {
8 font-size: 0.8em;
9}
10
11
12/* Grille du bingo */
13#grille {
14 background-color: #F8F8F8 ;
15 padding: 1px ;
16 margin: 30px ;
17 border: 1px solid black ;
18}
19
20#grille td {
21 background-color:#EEEEEE;
22 border: 1px solid black;
23 margin: 0px;
24 padding: 3px ;
25 text-align: center ;
26}
27
28#grille td.vide {
29 background-color:#999999 ;
30}
31
32/* Formulaire page custom */
33.texte {
34 width:20em
35}
36
37.data {
38 width:3em
diff --git a/templates/base.html b/templates/base.html
new file mode 100644
index 0000000..028aaa9
--- /dev/null
+++ b/templates/base.html
@@ -0,0 +1,31 @@
1<!DOCTYPE html>
2
3<html lang="fr">
4 <head>
5 <meta charset="UTF-8" >
6 <title>Le bingo de l'allaitement</title>
7 <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}" type="text/css">
8 <!--<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}">-->
9
10 <script src="static/outilspage.js"></script>
11 <meta name="viewport" content="width=device-width, initial-scale=1.0">
12
13 </head>
14
15 <body>
16
17 {% block contenu %}{% endblock %}
18
19 <hr>
20<div id="basdepage">
21 <nav>
22 <a href="/">Grille aléatoire</a> |
23 <a href="/custom">Créer une grille personnalisée</a> |
24<!-- <a href="/apropos">À propos</a> |-->
25
26 </nav>
27</div>
28
29
30 </body>
31</html>
diff --git a/templates/custom.html b/templates/custom.html
new file mode 100644
index 0000000..cc5521c
--- /dev/null
+++ b/templates/custom.html
@@ -0,0 +1,35 @@
1{% extends "base.html" %}
2{% block contenu %}
3<h1>Créer une grille personnalisée</h1>
4
5{% if e | length >0 %}
6<div id="erreurs">
7 <h2>Log d'erreurs</h2>
8 <ul>
9 {% for err in e %}
10 <li>{{ err }}</li>
11 {% endfor %}
12 </ul>
13</div>
14{% endif %}
15
16<div id="contenu">
17
18<form action="/" method="POST">
19
20<ul>
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>
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>
25
26
27</ul>
28<input type="submit" name="zou" value="Je veux une grille !">
29
30</form>
31
32</div>
33
34
35{% endblock %}
diff --git a/templates/faq.html b/templates/faq.html
new file mode 100644
index 0000000..162f68d
--- /dev/null
+++ b/templates/faq.html
@@ -0,0 +1,30 @@
1{% extends "base.html" %}
2{% block contenu %}
3<h2>Foire Aux Questions (FAQ)</h2>
4
5<div id="sommaire">
6<ul>{% for cat in lcateg %}
7<li><a href="#{{ cat }}">{{ cat }}</a></li>
8{% endfor %}
9</ul>
10</div>
11
12<div id="questionsreponses">
13{% for i in range(lcateg|length) %}
14{% set qr = tableqr[i] %}
15
16<h3 id="{{ lcateg[i] }}">{{ lcateg[i] }}</h3>
17<ul>
18 {% for (q,r) in qr %}
19 <li><p><strong>Q : </strong>{{ q|safe }}</p>
20 <p><strong>R : </strong>{{ r|safe }}</p>
21 </li>
22 {% endfor %}
23</ul>
24
25
26{% endfor %}
27</div>
28
29
30{% endblock %}
diff --git a/templates/index.html b/templates/index.html
new file mode 100644
index 0000000..852fdd7
--- /dev/null
+++ b/templates/index.html
@@ -0,0 +1,42 @@
1{% extends "base.html" %}
2{% block contenu %}
3<h1>{{ conf.titre }}</h1>
4
5{% if e | length >0 %}
6<div id="erreurs">
7 <h2>Log d'erreurs</h2>
8 <ul>
9 {% for err in e %}
10 <li>{{ err }}</li>
11 {% endfor %}
12 </ul>
13</div>
14{% endif %}
15
16<div id="contenu">
17
18<p>Cochez la case dès que vous entendez une réplique idiote !</p>
19<table id="grille">
20{% for ligne in bingo %}
21<tr>{% for elt in ligne %}
22 {% if elt == "0" %}
23 <td class="vide"></td>
24 {% else %}
25 <td onclick='validecase(this)'>{{ elt }}</td>
26 {% endif %}
27 {% endfor %}
28</tr>
29{% endfor %}
30</table>
31
32<p>Score : <span id="score">0</span></p>
33
34<p onclick="effacegrille()" class="cliquable">Effacer la grille</p>
35
36<hr>
37<a href="/?grille={{ chainecode }}">Lien permanent vers cette grille</a>
38
39</div>
40
41
42{% endblock %}