# Snake IA pour NumWorks (MicroPython 1.17)
fromkandinskyimportfill_rect,draw_stringimportion,time,random# ------------------ Réglages ------------------
CELL=10# taille d'une case en pixels
GRID_W=32# 32*10 = 320 px (largeur écran)
GRID_H=22# 22*10 = 220 px (hauteur écran)
OX=0# offset X
OY=0# offset Y
DELAY=0.05# vitesse (secondes)
MAX_STEPS=20000# sécurité anti-boucle infinie
# Couleurs (RGB)
COL_BG=(15,15,20)COL_GRID=(25,25,35)COL_SNAKE=(60,220,120)COL_HEAD=(40,180,90)COL_FOOD=(240,80,80)COL_TEXT=(230,230,230)# Directions: (dx,dy)
DIRS=[(1,0),(-1,0),(0,1),(0,-1)]# ------------------ Outils dessin ------------------
defcell_rect(x,y):returnOX+x*CELL,OY+y*CELL,CELL,CELLdefdraw_cell(x,y,col):rx,ry,rw,rh=cell_rect(x,y)fill_rect(rx,ry,rw,rh,col)defclear_screen():fill_rect(0,0,320,240,COL_BG)defdraw_grid_lines():# optionnel, léger : quadrillage discret
# (désactivable si tu veux plus de vitesse)
forxinrange(GRID_W):fill_rect(OX+x*CELL,OY,1,GRID_H*CELL,COL_GRID)foryinrange(GRID_H):fill_rect(OX,OY+y*CELL,GRID_W*CELL,1,COL_GRID)# ------------------ Logique ------------------
definside(x,y):return0<=x<GRID_Wand0<=y<GRID_Hdefspawn_food(snake_set):# essaie aléatoire, puis fallback linéaire si besoin
for_inrange(200):fx=random.randrange(GRID_W)fy=random.randrange(GRID_H)if (fx,fy)notinsnake_set:return (fx,fy)foryinrange(GRID_H):forxinrange(GRID_W):if (x,y)notinsnake_set:return (x,y)returnNone# plus de place (victoire)
defbfs_next_move(head,food,snake,snake_set):"""
BFS sur la grille pour trouver le 1er pas vers la nourriture.
On évite les cases occupées par le corps, SAUF la queue (car elle bouge).
"""hx,hy=headfx,fy=food# la queue va se libérer si on ne mange pas
tail=snake[-1]# visited et parent: on stocke dans des listes 2D "compactes"
# parent_dir[y][x] = direction index (0..3) utilisée pour arriver ici, depuis parent
visited=[[0]*GRID_Wfor_inrange(GRID_H)]parent=[[-1]*GRID_Wfor_inrange(GRID_H)]qx=[hx]qy=[hy]qi=0visited[hy][hx]=1# autoriser la case de la queue (tail) car elle peut bouger
# (bonne approximation pour éviter de se bloquer)
whileqi<len(qx):x=qx[qi]y=qy[qi]qi+=1ifx==fxandy==fy:breakfordiinrange(4):dx,dy=DIRS[di]nx=x+dxny=y+dyifnotinside(nx,ny):continueifvisited[ny][nx]:continue# collision: éviter le corps, sauf tail
if (nx,ny)insnake_setand(nx,ny)!=tail:continuevisited[ny][nx]=1parent[ny][nx]=diqx.append(nx)qy.append(ny)ifnotvisited[fy][fx]:returnNone# pas de chemin
# remonter depuis food jusqu'à head pour trouver le 1er pas
cx,cy=fx,fywhileTrue:di=parent[cy][cx]ifdi<0:returnNonedx,dy=DIRS[di]px=cx-dxpy=cy-dyifpx==hxandpy==hy:returndicx,cy=px,pydefcount_reachable_free(start,snake_set,tail):"""
Mesure de "sécurité": combien de cases accessibles depuis start,
en évitant le corps (sauf tail).
"""sx,sy=startifnotinside(sx,sy):return0if (sx,sy)insnake_setand(sx,sy)!=tail:return0visited=[[0]*GRID_Wfor_inrange(GRID_H)]qx=[sx]qy=[sy]qi=0visited[sy][sx]=1cnt=1whileqi<len(qx):x=qx[qi]y=qy[qi]qi+=1fordiinrange(4):dx,dy=DIRS[di]nx=x+dxny=y+dyifnotinside(nx,ny):continueifvisited[ny][nx]:continueif (nx,ny)insnake_setand(nx,ny)!=tail:continuevisited[ny][nx]=1qx.append(nx)qy.append(ny)cnt+=1returncntdefchoose_safe_move(head,food,snake,snake_set):"""
Fallback si BFS impossible: choisir un coup qui évite de mourir
et garde le plus d'espace accessible (anti-suicide).
"""hx,hy=headtail=snake[-1]best_di=Nonebest_score=-1fordiinrange(4):dx,dy=DIRS[di]nx=hx+dxny=hy+dyifnotinside(nx,ny):continueif (nx,ny)insnake_setand(nx,ny)!=tail:continue# score = espace accessible + petit bonus si rapproche de la nourriture
space=count_reachable_free((nx,ny),snake_set,tail)dist=abs(nx-food[0])+abs(ny-food[1])score=space*10-distifscore>best_score:best_score=scorebest_di=direturnbest_di# ------------------ Jeu ------------------
defgame():random.seed()clear_screen()# draw_grid_lines() # décommente si tu veux le quadrillage
# Snake initial (au centre)
sx=GRID_W//2sy=GRID_H//2snake=[(sx,sy),(sx-1,sy),(sx-2,sy)]snake_set=set(snake)food=spawn_food(snake_set)iffoodisNone:draw_string("Victoire!",100,110,COL_TEXT,COL_BG)return# dessin initial
for (x,y)insnake:draw_cell(x,y,COL_SNAKE)draw_cell(snake[0][0],snake[0][1],COL_HEAD)draw_cell(food[0],food[1],COL_FOOD)score=0steps=0whilesteps<MAX_STEPS:steps+=1# Quitter (touche BACK)
ifion.keydown(ion.KEY_BACK):breakhead=snake[0]# 1) tenter BFS vers la nourriture
di=bfs_next_move(head,food,snake,snake_set)# 2) sinon jouer un coup "sûr"
ifdiisNone:di=choose_safe_move(head,food,snake,snake_set)# 3) si aucun coup possible -> mort
ifdiisNone:breakdx,dy=DIRS[di]nx=head[0]+dxny=head[1]+dy# collision (mur / corps)
tail=snake[-1]if (notinside(nx,ny))or((nx,ny)insnake_setand(nx,ny)!=tail):break# avancer
new_head=(nx,ny)ate=(nx==food[0]andny==food[1])# redessiner ancienne tête en corps
draw_cell(head[0],head[1],COL_SNAKE)# ajouter tête
snake.insert(0,new_head)snake_set.add(new_head)# manger ?
ifate:score+=1# nouvelle nourriture
food=spawn_food(snake_set)iffoodisNone:# plus de place
draw_cell(new_head[0],new_head[1],COL_HEAD)draw_string("Victoire! Score: "+str(score),40,225,COL_TEXT,COL_BG)returndraw_cell(food[0],food[1],COL_FOOD)else:# enlever queue
tx,ty=snake.pop()snake_set.remove((tx,ty))draw_cell(tx,ty,COL_BG)# dessiner tête
draw_cell(new_head[0],new_head[1],COL_HEAD)# petit HUD
fill_rect(0,225,320,15,COL_BG)draw_string("Score: "+str(score)+" (BACK pour quitter)",2,225,COL_TEXT,COL_BG)time.sleep(DELAY)# fin
fill_rect(0,225,320,15,COL_BG)draw_string("Perdu. Score: "+str(score)+" (BACK)",2,225,COL_TEXT,COL_BG)game()
During your visit to our site, NumWorks needs to install "cookies" or use other technologies to collect data about you in order to:
Ensure the proper functioning of the site (essential cookies); and
Track your browsing to send you personalized communications if you have created a professional account on the site and can be contacted (audience measurement cookies).
With the exception of Cookies essential to the operation of the site, NumWorks leaves you the choice: you can accept Cookies for audience measurement by clicking on the "Accept and continue" button, or refuse these Cookies by clicking on the "Continue without accepting" button or by continuing your browsing. You can update your choice at any time by clicking on the link "Manage my cookies" at the bottom of the page. For more information, please consult our cookies policy.