Description
Il y a quelque semaine on a entamé la création d’un clone de « Snake », en modalité texte.
Nous sommes partis d’un vidéo sur YouTube, où le but étais de construire un « Snake » en python dans 5 minutes.
On a utilisé la librairie curses de Python, puis nous avons ajouté la gestion des couleurs.
Nous avons compliqué les choses en partageant l’écran en deux fenêtres, une pour les communications « pendant » le jeu, et l’autre pour la fenêtre de jeu lui-même.
Nous avons appris à gérer les boucles de jeux, l’affichage des points (sur une fenêtre dédiée à la communication), et aussi la fin du jeu.
Enfin, nous avons appris à gérer la notion de « high score », dans la façon la plus simple : En écrivant et lisant un fichier de texte. L’input ici est fait a “l’ancienne”, on gère lettre par lettre, et le nom du joueur est au maximum de 3 lettres.
Le diagramme d’états
Voilà à grandes lignes le diagramme des états du jeu :
Le code
Et voilà le code (une des versions, nous avons implémenté des moutures légèrement différents) :
import random import curses import art from time import sleep from random import randint # On regarde si il y a un record try: record = open("snake.record") recordMan = record.readline() recordScore = int(record.readline()) record.close() except : recordMan = "ABC" recordScore = 3 s = curses.initscr() curses.curs_set(0) # Ordre est important! curses.start_color() curses.noecho() sh, sw = s.getmaxyx() w_comm = curses.newwin(sh, 20, 0, 0) win = curses.newwin(sh, sw-20, 0, 20) win.keypad(1) win.timeout(100) def afficheText(win, y, x, text, color, sleepTime=0): textList=art.text2art(text).splitlines() i = 0 for line in textList: win.addstr(y+i, x, line, color) i+=1 win.refresh() sleep(sleepTime) # Ordre est important! curses.use_default_colors() curses.init_pair(1, curses.COLOR_GREEN, curses.COLOR_GREEN) curses.init_pair(2, curses.COLOR_RED, curses.COLOR_BLACK) curses.init_pair(3, curses.COLOR_CYAN, curses.COLOR_CYAN) curses.init_pair(4, curses.COLOR_YELLOW, curses.COLOR_BLACK) curses.init_pair(5, curses.COLOR_BLACK, curses.COLOR_BLACK) colors = {'green': curses.color_pair(1), 'red': curses.color_pair(2), 'blue': curses.color_pair(3), 'yellow': curses.color_pair(4), 'black': curses.color_pair(5)} color_list = colors.values # il est possible d'utiliser box() aussi afficheText(win, int(sh/3), int(sw/4)-10, "SnAkE", colors['yellow'], 2) afficheText(win, int(sh/3), int(sw/4)-10, "SnAkE", colors['black'], 0) while True: win.clear() win.border() w_comm.box() w_comm.refresh() snk_x = int(sw/4) snk_y = int(sh/2) snake = [ [snk_y, snk_x], [snk_y, snk_x-1], [snk_y, snk_x-2] ] food = [int(sh/2), int(sw/2)] win.addch(food[0], food[1], curses.ACS_DIAMOND, colors['red']) key = curses.KEY_RIGHT pause = False touches = [ord('p'), ord('q'), curses.KEY_DOWN, curses.KEY_UP, curses.KEY_LEFT, curses.KEY_RIGHT] manges = 0 afficheText(w_comm, 5, 5, str(manges), colors['red']) w_comm.refresh() while True: next_key = win.getch() if next_key not in touches: next_key=-1 if next_key == ord('p'): pause = not pause if pause : old_key = key else : next_key = old_key if next_key == ord('q'): curses.endwin() quit() if not pause: key = key if next_key == -1 else next_key if snake[0][0] in [0, sh] or snake[0][1] in [0, sw-1] or snake[0] in snake[1:]: afficheText(win, int(sh/3), int(sw/5), "PERDU", colors['red'], 2) break new_head = [snake[0][0], snake[0][1]] if key == curses.KEY_DOWN: new_head[0] += 1 if key == curses.KEY_UP: new_head[0] -= 1 if key == curses.KEY_LEFT: new_head[1] -= 1 if key == curses.KEY_RIGHT: new_head[1] += 1 snake.insert(0, new_head) if snake[0] == food: food = None while food is None: nf = [ random.randint(2, sh-3), random.randint(21, sw-3) ] food = nf if nf not in snake else None try: win.addch(food[0], food[1], curses.ACS_DIAMOND, colors['red']) except: food = None afficheText(w_comm, 5, 5, str(manges), colors['black']) manges+=1 afficheText(w_comm, 5, 5, str(manges), colors['red']) #w_comm.addstr(5, 5, str(manges)) w_comm.refresh() else: tail = snake.pop() win.addch(tail[0], tail[1], ' ') try: win.addch(snake[0][0], snake[0][1], curses.ACS_CKBOARD,colors['green']) for i in range (1,len(snake)-1): win.addch(snake[i][0], snake[i][1], curses.ACS_CKBOARD,colors['blue']) except: afficheText(win, int(sh/3), int(sw/5), "PERDU", colors['red'], 2) curses.endwin() break # Si le dernier score est plus du record? Il faut mettre à jour le record if manges > recordScore : # Nettoyer la fenetre win.clear() win.border() # Premier charactere... # On permet les lettres, les chiffres et les fleches pour bouger... # Position = 0 prenom = "_" afficheText(win, 5, 5, prenom, colors['red']) touchesCTRL = [curses.KEY_DOWN, curses.KEY_UP, curses.KEY_LEFT, curses.KEY_RIGHT] alphabet="_ABCDEFGJKLMNOPQRSTUVWXYZ0123456789" index = 0 position = 0 while position < 3: next_key = win.getch() if next_key in touchesCTRL: if next_key == curses.KEY_UP: index+=1 if index >=len(alphabet): index = 0 prenom = prenom[:-1] + alphabet[index] if next_key == curses.KEY_DOWN: index-=1 if index < 0 : index = len(alphabet)-1 prenom = prenom[:-1] + alphabet[index] if next_key == curses.KEY_RIGHT: position+=1 if position < 3: prenom = prenom + alphabet[index] if next_key == curses.KEY_LEFT: if position > 0: position-=1 prenom = prenom[:-1] win.clear() win.border() afficheText(win, 5, 5, prenom, colors['red']) if manges > recordScore : win.clear() win.border() afficheText(win, 5, 5, "MERCI!", colors['red'],1) record = open("/home/antonio/Dev/Python/snake.record", 'w') record.write(prenom +"\n") record.write(str(manges)) record.close() recordScore = manges # Demander si rejouer # Nettoyer la fenetre win.clear() win.border() afficheText(win, 5, 5, "Encore? O/N", colors['red']) # Gerer les touches while True : next_key = win.getch() if next_key == ord('o') or next_key == ord('O'): break if next_key == ord('q') or next_key == ord('n'): curses.endwin() quit()