diff --git a/README b/README index 519d59f..ea0b026 100644 --- a/README +++ b/README @@ -7,7 +7,7 @@ Jeux de base * Devine le numéro - CODÉ * Pense à un numéro - CODÉ * Simulateur de Mounty Hall - CODÉ -* Ordonner par permutations +* Ordonner par permutations - CODÉ * Jeu du pendu - CODÉ * IA du pendu - CODÉ * Donjon dont vous êtes le héro diff --git a/src/permutator.py b/src/permutator.py index 7223948..4afa8c3 100644 --- a/src/permutator.py +++ b/src/permutator.py @@ -71,3 +71,4 @@ if __name__=="__main__": break else: attempts += 1 + diff --git a/src/permutator_interactif.py b/src/permutator_interactif.py new file mode 100644 index 0000000..d7b18f6 --- /dev/null +++ b/src/permutator_interactif.py @@ -0,0 +1,172 @@ +#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) +