172 lines
4.6 KiB
Python
172 lines
4.6 KiB
Python
#encoding: utf-8
|
|
|
|
import random
|
|
import curses
|
|
import time
|
|
|
|
|
|
def swap( items, i, j ):
|
|
assert( i < len(items) and j < len(items) )
|
|
items[i], items[j] = items[j],items[i]
|
|
return items
|
|
|
|
|
|
def permute( items, index ):
|
|
""" Permute 4 chiffres deux à deux, par exemple avec index==0 :
|
|
0 1 2 3 4 5 6 7
|
|
▲ ▲ ▲ ▲
|
|
│ └─┘ │
|
|
└─────┘
|
|
3 2 1 0 4 5 6 7
|
|
"""
|
|
assert( index+3 < len(items) )
|
|
|
|
# Échange les nombres aux deux bouts.
|
|
items = swap( items, index, index+3 )
|
|
|
|
# Échange les nombres au milieu.
|
|
items = swap( items, index+1, index+2 )
|
|
|
|
return items
|
|
|
|
|
|
def display( scr, items, index, msg = "" ):
|
|
""" Affiche un écran de jeu interactif en mode texte:
|
|
D'abord une ligne pour un éventuel message,
|
|
ensuite la séquence permutée,
|
|
puis le schéma de permutation.
|
|
|
|
Par exemple:
|
|
Séquence mélangée en 2 permutations
|
|
0 1 6 7 3 2 5 4
|
|
▲ ▲ ▲ ▲
|
|
│ └─┘ │
|
|
└─────┘
|
|
"""
|
|
# Efface ce qui aurait été affiché précédemment.
|
|
scr.clear()
|
|
# Ajoute une chaine de caractères,
|
|
# à partir de la première ligne et de la première colonne.
|
|
scr.addstr( 0,0, msg + "\n" )
|
|
# Rempli le restant de la ligne affichée à l'écran par des espaces.
|
|
# (lire "CLeaR TO End Of Line")
|
|
scr.clrtoeol()
|
|
|
|
# On peut omettre les coordonnées, le curseur d'affichage part alors de la
|
|
# dernière position...
|
|
scr.addstr( " ".join([str(i) for i in items]) )
|
|
# ... d'où l'intérêt d'ajouter des fins de ligne (caractère "\n").
|
|
scr.addstr("\n")
|
|
|
|
# On insèrera une colonne d'espaces avant le schéma de permutation,
|
|
# selon l'index considéré.
|
|
pad = " " * index
|
|
|
|
scr.addstr( pad + ("▲ " * 4) + "\n" )
|
|
scr.clrtoeol()
|
|
scr.addstr( pad + "│ └─┘ │\n" )
|
|
scr.clrtoeol()
|
|
scr.addstr( pad + "└─────┘\n" )
|
|
scr.clrtoeol()
|
|
|
|
# Rempli l'écran de ligne vide jusqu'en bas ("CLeaR TO BOttom").
|
|
scr.clrtobot()
|
|
|
|
|
|
def shuffle( items, permutations ):
|
|
""" Applique un nombre donné de permutations aléatoires """
|
|
for n in range(permutations):
|
|
i = random.randint(0,size-4)
|
|
items = permute( items, i )
|
|
|
|
|
|
def loop( scr, items, nb_shuffle ):
|
|
msg = "Séquence mélangée en "+str(nb_shuffle)+" permutations"
|
|
display( scr, items, 0, msg )
|
|
|
|
end_msg = ""
|
|
|
|
ui_delay = 0.05
|
|
# Modèle de la séquence initiale, ordonnée
|
|
items_ok = sorted( items )
|
|
attempts = 1
|
|
i = 0
|
|
while True:
|
|
# Récupère le code de la touche qui viens d'être utilisée.
|
|
keycode = scr.getch()
|
|
cmd = chr(0)
|
|
|
|
# Si le code est un caractère ASCII (une lettre non accentuée)
|
|
if 0 < keycode < 256:
|
|
# Récupère le caractère correspondant à ce code.
|
|
cmd = chr(keycode)
|
|
|
|
if cmd in 'qQ':
|
|
break
|
|
|
|
elif keycode == curses.KEY_LEFT:
|
|
if i > 0:
|
|
i -= 1
|
|
|
|
elif keycode == curses.KEY_RIGHT:
|
|
if i < size-4:
|
|
i += 1
|
|
|
|
elif cmd == " " or keycode == curses.KEY_UP:
|
|
permute( items, i )
|
|
|
|
# Si la séquence permutée correspond à la même séquence, mais triée
|
|
if items == items_ok:
|
|
msg = "Vous avez réussi en "+str(attempts)+" permutations"
|
|
end_msg = msg
|
|
else:
|
|
attempts += 1
|
|
|
|
# Affiche l'écran de jeu
|
|
display( scr, items, i, msg )
|
|
# Met à jour le terminal
|
|
scr.refresh()
|
|
# Attends quelques millisecondes avant de relancer le tout.
|
|
# Si on n'attends pas, le processeur sera utilisé à 100%,
|
|
# ce qui est inutile vu le temps de réaction moyen d'un être humain.
|
|
time.sleep( ui_delay )
|
|
|
|
return end_msg
|
|
|
|
|
|
def play( size, nb_shuffle ):
|
|
|
|
scr = curses.initscr()
|
|
# Ne pas afficher les touches pressées.
|
|
curses.noecho()
|
|
# Active la prise en compte des touches "flèches".
|
|
scr.keypad(1)
|
|
|
|
items = [n for n in range(size)]
|
|
|
|
end_msg = ""
|
|
try:
|
|
shuffle( items, nb_shuffle )
|
|
end_msg = loop( scr, items, nb_shuffle )
|
|
|
|
# Quelles que soit les erreurs ayant été levées, ou pas,
|
|
# on effectue ce bloc de code.
|
|
finally:
|
|
# Dé-initialise la bibliothèque et remet le terminal
|
|
# dans sa configuration précédente, sans quoi le terminal
|
|
# ne s'affichera plus correctement à la sorti du programme.
|
|
curses.endwin()
|
|
|
|
return end_msg
|
|
|
|
|
|
if __name__=="__main__":
|
|
size = 8
|
|
nb_shuffle = 2
|
|
|
|
msg = play( size, nb_shuffle )
|
|
|
|
# Si le message n'est pas vide.
|
|
if msg:
|
|
print(msg)
|
|
|