Internet, c'est compliqué, c'est tout nouveau
Christine Albanel
Juniper Green est un jeu d'opposition (Il oppose deux joueurs) mathématique.
Ce jeu a été créé par Richard Porteous, enseignant à l’école de Juniper Green (Et voilà d'où vient ce nom !)
Il s'est surtout fait connaitre par la revue Pour la Science (en 1997).
Le jeu de Juniper Green doit être joué avec un liste des nombres de 1 à 20 puis de 1 à 50 pour que les enfants s'approprient correctement le jeu.
Ensuite le tableau peut contenir autant de nombre que l'on souhaite, la limite étant fixée par les moyens de calcul. Le matériel est constitué d'un tableau de nombre et d'une feuille commune. Chacun à son tour choisit un multiple ou un diviseur du dernier nombre coché, l'écrit pour compléter la liste en cours et raye la case correspondante dans le tableau.
Une version en solitaire consiste a essayer de créer la suite la plus longue. Ce jeu est un travail difficile mais très efficace sur les multiples et diviseurs.
Sources : sur apmep.fr
En utilisant ce jeu en classe (et pas seulement en cycle3 : En troisième il permet d'évoquer les nombres premiers d'une façon originale !) Je me suis trouvé plus d'une fois étonné de l'engouement généré !
C'est pourquoi j'ai le plaisir d'offrir à la communauté cette petite application: Juniper-U ! (prononcez Juniper-You, après tout c'est moi qui choisis !)
# -*- coding: utf-8 -*-
# Juniper-U est développé par Wouf (2018)
import random, webbrowser
from tkinter import *
from tkinter import messagebox
#les variables globales
IA=False #c'estl IA qui commence (bascule si new game)
partieencours=False
partie=[]
scoreIA,scorejoueur =0,0
class Juniper:
def __init__(self, partie,IA_turn):
self.partie = partie
self.IA_turn=IA_turn #est-ce à l'IA de jouer ?
self.variantes = [x for x in range(1,21) if x not in partie and (partie[-1]%x==0 or x%partie[-1]==0)]
self.fini = (len(self.variantes)==0)
def __repr__(self):
debug=str(self.partie)
debug+="\n"
debug+=" " +str(self.variantes)
debug+="\n"
if self.fini:
debug+="partie terminée"
else:
debug+="partie en cours"
debug+="\n"
if self.IA_turn:
debug+="C'est à l'ordinateur de joué"
else:
debug+="C'est au joueur de joué"
debug+="\n -------------------------------------------------------------"
return debug
def aide():
message= """Le jeu de Juniper green
Je choisis un nombre entre 1 et 20
À tour de rôle, chaque joueur doit choisir un nombre parmi les multiples ou les diviseurs du nombre choisi précédemment par son adversaire
Un nombre ne peut être joué qu'une seule fois.
Le premier nombre choisi doit être pair !
La partie se joue en (au moins) deux manches, je commence la première, vous commencez la deuxième !
Développé par Wouf sur Python 3.6.4 ce petit soft est gratuit, et ne peut être vendu!
Mais rien ne vous empèche de faire un petit don paypal à wouf@libertysurf.fr !
Les sources et des notions de stratégie sont disponibles sur:
http://site2wouf.fr/juniper
Vous pouvez aussi y poser des questions !
wOuf
"""
messagebox.showinfo("Aide" , message)
def lien():
webbrowser.open('http://site2wouf.fr/juniper')
def affichscore():
return "IA :" +str( scoreIA)+" JOUEUR :" +str(scorejoueur)
def affichpartie():
if IA:
libele="IA - JOUEUR :"
else:
libele="JOUEUR - IA :"
libele+="\n"
for x in partie:
libele+=str(x)+"-"
return libele
def newgame():
global partieencours,scoreIA,IA,partie
if partieencours:
if messagebox.askyesno ("Abandon ?" ,"Vous abandonnez la partie en cours ?" ):
partieencours=False
partie=[]
for i in button:
i.configure(state="normal" )
scoreIA+=1
IA=not IA
label1.configure(text=affichpartie())
label3.configure(text=affichscore())
exit
else:
partie=[]
IA=not IA
for i in button:
i.configure(state="normal" )
label3.configure(text=affichscore())
label1.configure(text=affichpartie())
partieencours=True
if IA:
jouer(partie)
def fonction(x):
global partie
if len(partie)==0:
if x%2==0:
partie.append(x)
button[x-1].configure(state="disabled" )
label1.configure(text=affichpartie())
jouer(partie)
else:
if partie[-1]%x==0 or x%partie[-1]==0:
partie.append(x)
button[x-1].configure(state="disabled" )
label1.configure(text=affichpartie())
jouer(partie)
def make_children(p):
""" Cette fonction reçoit un objet de la classe Juniper
renvoie ses enfants (les sous-variantes)
en tant qu'objets de la classe Juniper"""
children=[]
for v in p.variantes:
children.append(Juniper(p.partie+[v],not p.IA_turn))
return children
def evalue_noeud(p):
""" Cette fonction reçoit un objet de la classe Juniper et
renvoie un booleen :
True si l'IA gagne en jouant les bons coups coups
False si le joueur gagne en jouant les bons coups"""
if p.fini:
if p.IA_turn:
return False
else:
return True
else:
if p.IA_turn:
t=False
for enfants in make_children(p):
t=t or evalue_noeud(enfants)
else:
t=True
for enfants in make_children(p):
t=t and evalue_noeud(enfants)
return t
def choix_variante(p):
global scorejoueur,partieencours,partie
""" Cette fonction reçoit un objet de la classe Juniper et
renvoie l'entier qui doit être choisi pour que le joueur
puisse se tromper dans une variante gagnante pour lui
avec la frequence la plus grande.
"""
variantes=p.variantes
if len(variantes)==0:
return 0
if len(variantes)==1:
return variantes[0]
if 1 in variantes:
variantes.remove(1)
return random.choice(variantes)
def perdu():
global scorejoueur,partieencours
#perdu
for i in button:
i.configure(state="disabled" )
scorejoueur+=1
label3.configure(text=affichscore())
messagebox.showinfo("GAME OVER" , "Bravo !" )
partieencours=False
def testgain():
global partie, scoreIA,partieencours
if len([x for x in range(1,21) if x not in partie and (partie[-1]%x==0 or x%partie[-1]==0)])==0:
scoreIA+=1
for i in button:
i.configure(state="disabled" )
label3.configure(text=affichscore())
partieencours=False
messagebox.showinfo("GAME OVER" , "J'ai gagné !" )
partie=[]
def jouer(p=[]):
""" p est une liste de coups
c'est à dire la partie.
Appeler sans parametre elle fait
commencer l'IA.
Cette fonction renvoie le coup
joué par l'IA."""
if len(p)==0:
#IA commence
choix=random.choice([2,4,6,8,10,12,16,18,20])
button[choix-1].configure(state="disabled" )
partie.append(choix)
label1.configure(text=affichpartie())
testgain()
return
p2=Juniper([int(x) for x in p],True)
possibles=[i for i in p2.variantes if evalue_noeud(Juniper(p2.partie+[i],False))]
if len(possibles)!=0:
ia=random.choice(possibles)
partie.append(ia)
label1.configure(text=affichpartie())
button[ia-1].configure(state="disabled" )
testgain()
return
ia=choix_variante(Juniper(p,True))
if ia!=0:
partie.append(ia)
label1.configure(text=affichpartie())
button[ia-1].configure(state="disabled" )
testgain()
else:
perdu()
return
fenetre = Tk()
fenetre.title("JuniPeR-U" )
menubar = Menu(fenetre)
menubar.add_command(label="New Game" , command=newgame)
menubar.add_command(label="Help" , command=aide)
menubar.add_command(label="En ligne" , command=lien)
fenetre.config(menu=menubar)
frame1 = Frame(fenetre)
label1 =Label(frame1, text=affichpartie())
label1.pack()
frame1.pack()
frame2 = Frame(fenetre)
button=[]
for i in range(1,21):
button.append(Button(frame2,state="disabled" ,borderwidth=2,width=6,height=3,text=i,command=lambda i=i:fonction(i)))
#positionnement
no=1
for i in button:
i.grid(column=(no-1)%5,row=(no-1)//5)
no+=1
frame2.pack()
frame3=Frame(fenetre) #les scores
label3=Label(frame3, text=affichscore())
label3.pack()
frame3.pack()
fenetre.mainloop()
Mon travail vous intéresse et vous désirez participer aux frais du site ?
Vous pouvez faire un don ici
L'application a été testé sur divers système sans soucis dans l'environnement Python3
Le setup pour Windows est régulièrement mis à jour avec les DLL qui manquent sur certains systèmes (N'hésitez pas à commenter plus bas si vous avez un souci)
Merci à REB (Red is Beautiful) alias Cedric Brasseur pour sa contribution sur les systèmes obsolètes et les DLL préhistoriques
Passage ce jour en version 1.2.0 (le 08/06/2018): Plus de hasard dans le choix des variantes de l'IA pour éviter le jeu par coeur lorsque le joueur a trouvé une variante gagnante!
La problématique était la suivante :
L'équipe pédagogiques du collège dans lequel j'exerce désirait, dans le cadre de la semaine des Mathématiques, créer une activité en ligne à destination de toutes les classes de sixième. Chaque élève joue pour sa classe. Il doit donc avoir un pseudo et nous devons, grâce à lui, savoir dans quelle classe il est inscrit.
Or la nécessité d'être en conformité avec le RGPD nous oblige à une certaine prudence.
Notre idée est la suivante :
Nous créons pas classe une liste de 50 pseudos dans lequel un code numérique identifie la classe d'origine. Chaque élève choisit un pseudo et le raye de la liste.
Ce pseudo est son identifiant pour accéder aux activités (via Canopé) . Aucune donnée personnelle n'est sauvegardée...
J'utilise un fichier texte avec quelques noms d'animaux :
[text] CHIEN CHAT TAUREAU VACHE AGNEAU CHEVRE CERF LAPIN COCHON CHEVAL LION TIGRE PANTHERE JAGUAR GUEPARD OURS LOUP RENARD HYENE ELEPHANT RHINOCEROS HIPPOPOTAME ZEBRE GIRAFE ANTILOPE KOALA KANGOUROU CASTOR SINGE PANDA LOUTRE TORTUE SERPENT LEZARD IGUANE CROCODILE ALLIGATOR DRAGON PYTHON MOUSTIQUE MOUTON CHEVREUIL OURSON SOURIS RAT POULE CANARD OIE COQ PAON PERROQUET PINGOUIN FLAMANT FOUINE HERISSON COLOMBE PIGEON [/text]Avec le code python qui suit on génère un fichier texte qui répond au cahier des charges:
Et on obtient le fichier texte " result.txt ":
[text]6A CHEVRE17 GUEPARD17 OURS29 FOUINE21 POULE13 OURSON17 COLOMBE21 VACHE13 CHEVREUIL21 COQ25 FLAMANT17 COCHON13 HYENE21 CASTOR29 PERROQUET13 KANGOUROU21 GIRAFE29 ANTILOPE33 TORTUE21 TIGRE21 CHIEN17 IGUANE29 TAUREAU17 CHEVAL25 ALLIGATOR25 RENARD25 LION17 PINGOUIN21 PIGEON21 RHINOCEROS21 CHAT13 SERPENT33 MOUTON21 HERISSON21 KOALA29 MOUSTIQUE13 DRAGON25 ZEBRE17 PAON21 SOURIS25 AGNEAU33 PANTHERE33 CROCODILE33 RAT25 PANDA29 SINGE17 LEZARD29 LOUP25 OIE13 CANARD33 ---------------------------------------- 6B PANDA38 RENARD38 CHEVREUIL26 CHAT22 CHIEN22 CHEVRE14 OURSON34 HYENE18 CERF38 PYTHON14 LOUTRE22 VACHE34 HIPPOPOTAME22 CASTOR18 MOUSTIQUE14 LOUP26 FOUINE26 OURS26 LEZARD34 COCHON38 OIE38 SOURIS22 CROCODILE26 SERPENT14 TIGRE26 DRAGON22 IGUANE34 AGNEAU18 PINGOUIN26 SINGE26 ANTILOPE22 ZEBRE14 KANGOUROU14 ALLIGATOR18 HERISSON34 LAPIN22 PERROQUET18 PAON14 COLOMBE26 POULE26 MOUTON38 COQ14 JAGUAR34 ELEPHANT18 LION18 RHINOCEROS14 TAUREAU34 GUEPARD26 FLAMANT26 PANTHERE38 ---------------------------------------- 6C COCHON27 CROCODILE31 ZEBRE11 LOUTRE31 FOUINE19 KANGOUROU23 LEZARD19 GUEPARD11 LAPIN31 PYTHON19 TIGRE19 OIE31 GIRAFE15 COQ31 CHEVAL27 CASTOR19 ELEPHANT15 OURSON15 RENARD19 DRAGON11 TORTUE27 ALLIGATOR11 HYENE31 CHAT31 KOALA15 RHINOCEROS31 LION19 FLAMANT19 PAON23 LOUP15 HIPPOPOTAME11 CERF11 CHEVREUIL11 VACHE19 CHIEN23 SINGE23 AGNEAU27 CHEVRE11 OURS31 IGUANE27 PANTHERE23 SERPENT23 TAUREAU23 POULE31 CANARD23 COLOMBE11 PIGEON23 RAT23 PINGOUIN19 PANDA27 ---------------------------------------- 6D CHEVRE28 PAON32 ZEBRE12 CASTOR16 MOUSTIQUE32 LOUTRE12 CHEVAL36 RENARD24 OURSON36 CHEVREUIL32 ANTILOPE36 TORTUE36 SINGE16 TIGRE12 TAUREAU16 COCHON28 LEZARD24 AGNEAU12 PIGEON28 JAGUAR12 HYENE36 HERISSON36 FLAMANT32 CHAT24 RAT16 PERROQUET28 VACHE16 GIRAFE24 ELEPHANT12 PINGOUIN36 SERPENT24 MOUTON16 POULE28 OURS24 PYTHON24 HIPPOPOTAME28 COLOMBE32 LION12 ALLIGATOR24 GUEPARD12 RHINOCEROS24 COQ16 OIE24 SOURIS12 LOUP16 CERF32 CROCODILE32 PANDA24 KOALA12 FOUINE24 ---------------------------------------- [/text]J'ai choisi les nombres de deux chiffres pour qu'on puisse rapidement retrouver la classe en question : Le reste dans la division euclidienne de ce nombre par 4 donne le rang de la classe :
13 = 4 × 3 + 1 : première classe
Le code Python n'est pas commenté, il est très simple !
lien vers l'article sur wouf blogVous connaissez Python?
Python est un langage de programmation.
Le nom Python ne viendrait pas du nom d'un reptile mais du Monty Python Flying Circus, un groupe de comiques complètement déjantés qui ont sévis sur la BBC dans les années 60-70.
Sur le site de Wouf, vous trouverez:
Python is fantastic!