snake.py

Created by cent20

Created on May 05, 2020

8.36 KB

Découvrez la création de ce snake ici : https://nsi.xyz/snake
Utilisable directement sur le workshop mais meilleur sur la calculatrice ! Par Arthur Jacquin, mars 2020


from kandinsky import *

from ion import keydown

from time import monotonic

from random import choice



def wait(buttons = range(53)): # Attends qu'une des touches précisées soit pressée

    while True:

        for i in buttons:

            if keydown(i):

                while keydown(i): True # Fonction anti-rebond

                return i 



def omega(): # Vérificateur d'OS

    try: get_keys()

    except: return False

    else: return True



# Positionnement

mh = 20 # Marge du haut

mg = 20 # Marge à gauche

ae = 15 # Aération

esp = 5 # Espacement

b = [150,300] # Bornes pour les options



# Couleurs

ome = (192,53,53) # Couleur d'Omega

eps = (255,183,52) # Couleur d'Epsilon

act = eps # Couleur de l'objet actif

n = (0,0,0) # Titre, options

g = (70,70,70) # Paramètres, curseur



def menu(titre, action, *para):

    # Fonctions graphiques

    def draw_action(col): # Actualise l'apparence de l'action

        draw_string(action, int(160-5*len(action)), mh+20+ae, col)

    def draw_option(i, col): # Actualise l'apparence de l'option du paramètre i

        draw_string(" "*int((b[1]-b[0])/10), b[0], mh+2*(20+ae)+i*(20+esp))

        txt = str(para[i][aff[i]])

        if txt.find("$") != -1: # Affichage de plusieurs lignes

            txt, txt2 = txt[:txt.find("$")], txt[txt.find("$")+1:] # Séparation de l'option

            draw_string(" "*32, 0, mh+2*(20+ae)+(i+1)*(20+esp)) # Effacement de la ligne suivante

            draw_string(str(txt2), 160-5*len(txt2), mh+2*(20+ae)+(i+1)*(20+esp), col)

        draw_string(txt, int(b[0]+(b[1]-b[0]-10*len(str(txt)))/2), mh+2*(20+ae)+i*(20+esp), col)

        draw_string(("<"*(col==act)+" ")[0], b[0]-10, mh+2*(20+ae)+i*(20+esp), g) # Curseur gauche

        draw_string((">"*(col==act)+" ")[0], b[1], mh+2*(20+ae)+i*(20+esp), g) # Curseur droit

    

    # Initialisation du menu

    fill_rect(0,0,320,222,(255,255,255))

    if omega(): act = ome # Adaptation de la couleur à l'OS

    else: act = eps

    aff = [1 for i in para]

    curs = 0 # Initialisation sur l'action

    draw_string(titre, int(160-5*len(titre)), mh, n) # Titre

    draw_action(act) # Action

    for i in range(len(para)): # Paramètres

        draw_string(para[i][0], mg, mh+2*(20+ae)+i*(20+esp), n)

        draw_option(i, g)

    

    # Naviguation dans le menu

    while True:

        if curs == 0: # Action

            draw_action(act)

            r = wait([1,2,4])

            if r == 4: # Retourne les valeurs validées

                return [para[i][aff[i]] for i in range(len(para))]

            else:

                draw_action(n)

        else: # Paramètre

            draw_option(curs-1, act)

            r = wait([0,1,2,3])

            if r in [1,2]: draw_option(curs-1, g)

    

        # Actualisation des options actuelles et du curseur

        if r == 0: aff[curs-1] = (aff[curs-1]-2)%(len(para[curs-1])-1)+1

        elif r == 1: curs = (curs-1)%(len(para)+1)

        elif r == 2: curs = (curs+1)%(len(para)+1)

        elif r == 3: aff[curs-1] = (aff[curs-1])%(len(para[curs-1])-1)+1


# Couleurs

back = (255,255,255) # Arrière-plan

imp = (0,0,0) # Bordure, titres, menus

sub = (70,70,70) # Score, auteur

body = (0, 204, 0) # Corps du serpent

bord = (0, 104, 0) # Bordures du serpent

red = (248, 0, 0) # Langue, yeux, pomme

red_dark = (200, 0, 0) # Pomme


def play(para):

    # Power-ups

    def pom():

        up = [choice(range(32)), choice(range(20))]

        while get_pixel(10*up[0], 22 + 10*up[1]) == bord: up = [choice(range(32)), choice(range(20))]

        Xp, Yp = 10*up[0], 22 + 10*up[1]

        fill_rect(Xp,Yp+4,10,4,red_dark)

        fill_rect(Xp+2,Yp+2,6,8,red_dark)

        fill_rect(Xp+1,Yp+3,8,6,red)

        set_pixel(Xp+1,Yp+3,red_dark)

        set_pixel(Xp+1,Yp+8,red_dark)

        set_pixel(Xp+8,Yp+3,red_dark)

        set_pixel(Xp+8,Yp+8,red_dark)

        fill_rect(Xp+2,Yp,3,1,bord)

        fill_rect(Xp+1,Yp+1,5,1,bord)

        fill_rect(Xp+2,Yp+1,2,1,body)

        fill_rect(Xp+3,Yp+2,3,1,body)


    # Initialisation

    di, sn = 3, [30, 52, 80, 52] # Direction et corps (queue et tête) du serpent

    score = to_add = 0 # Score et croissance

    time = monotonic() # Temps

    if para[1]=="Facile": speed, add = 0.25, 5

    elif para[1]=="Moyen": speed, add = 0.2, 10

    elif para[1]=="Difficile": speed, add = 0.16, 15

    elif para[1]==" Extrême": speed, add = 0.12, 20    

    

    # Dessin de l'interface

    fill_rect(0,0,320,222,back) # Nettoyage

    fill_rect(0,21,320,1,imp) # Bordure supérieure

    draw_string("SNAKE",135,2,imp) # Titre

    draw_string("0",304,2,sub) # Score

    fill_rect(30,52,60,10,bord) # Serpent initial

    fill_rect(31,53,58,8,body)

    if para[0] == "Classique": pom()


    # Boucle principale

    while True:

        # Gestion du temps et de la direction

        direction = di 

        while monotonic() < time + speed:

            for k in range(4):

                if keydown(k) and direction+k != 3: di = k

            if keydown(6): start() # Retour au menu

        time = monotonic()

        # Rafraîchissement de la queue

        if int(to_add): to_add -= 1

        else:

            if get_pixel(sn[0],sn[1]+1) == body: sens = 0

            elif get_pixel(sn[0]+9,sn[1]+1) == body: sens = 3

            elif get_pixel(sn[0]+1,sn[1]) == body: sens = 1

            elif get_pixel(sn[0]+1,sn[1]+9) == body: sens = 2

            fill_rect(sn[0],sn[1],10,10,back)

            sn[0], sn[1] = (sn[0] + 10*(sens==3) - 10*(sens==0))%320, (sn[1] + 10*(sens==2) - 10*(sens==1)-22)%200+22

            if sens == 0: fill_rect(sn[0]+9,sn[1],1,10,bord)

            elif sens == 3: fill_rect(sn[0],sn[1],1,10,bord)

            elif sens == 1: fill_rect(sn[0],sn[1]+9,10,1,bord)

            elif sens == 2: fill_rect(sn[0],sn[1],10,1,bord)

        

        # Rafraîchissement de la tête - Partie 1

        fill_rect(sn[2]+1,sn[3]+1,8,8,body)

        if di == 0: fill_rect(sn[2],sn[3]+1,1,8,body)

        elif di == 1: fill_rect(sn[2]+1,sn[3],8,1,body)

        elif di == 3: fill_rect(sn[2]+9,sn[3]+1,1,8,body)

        elif di == 2: fill_rect(sn[2]+1,sn[3]+9,8,1,body)

        sn[2], sn[3] = sn[2] + 10*(di==3) - 10*(di==0), sn[3] + 10*(di==2) - 10*(di==1)

        if para[2]=="  Téléportation": sn[2], sn[3] = sn[2]%320, (sn[3]-22)%200 + 22

        

        # Traitement et power-ups

        if get_pixel(sn[2], sn[3]) == bord or not(sn[2] in range(320)) or not(sn[3] in range(22, 222)): break # Rencontre bordure mortelle ou corps

        if get_pixel(sn[2] + 4,sn[3] + 4) == red: # Pomme

            score += 15

            to_add += add

            pom()

        

        # Rafraîchissement de la tête - Partie 2

        fill_rect(sn[2],sn[3],10,10,bord)

        fill_rect(sn[2]+1,sn[3]+1,8,8,body)

        if di == 0:

            fill_rect(sn[2]+4,sn[3]+2,1,6,bord)

            fill_rect(sn[2]+3,sn[3]+3,1,4,red)

            fill_rect(sn[2]+3,sn[3]+4,2,2,body)

            fill_rect(sn[2]+9,sn[3]+1,1,8,body)

        elif di == 1:

            fill_rect(sn[2]+2,sn[3]+4,6,1,bord)

            fill_rect(sn[2]+3,sn[3]+3,4,1,red)

            fill_rect(sn[2]+4,sn[3]+3,2,2,body)

            fill_rect(sn[2]+1,sn[3]+9,8,1,body)

        elif di == 3:

            fill_rect(sn[2]+5,sn[3]+2,1,6,bord)

            fill_rect(sn[2]+6,sn[3]+3,1,4,red)

            fill_rect(sn[2]+5,sn[3]+4,2,2,body)

            fill_rect(sn[2],sn[3]+1,1,8,body)

        elif di == 2:

            fill_rect(sn[2]+2,sn[3]+5,6,1,bord)

            fill_rect(sn[2]+3,sn[3]+6,4,1,red)

            fill_rect(sn[2]+4,sn[3]+5,2,2,body)

            fill_rect(sn[2]+1,sn[3],8,1,body)

            

        # Traitement final

        score += speed

        draw_string("  "+str(int(score)),int(314-10*len("  "+str(int(score)))),2,sub) # Rafraichissement du score

        if para[0] == "Dingue":

            if speed > 0.04: speed *= 0.99

            to_add += 0.2



            

    # Procédure de perte

    draw_string("YOU LOST !",110,2,(255,0,0))

    while not(keydown(4)): pass

    play(para)

def start(): # Lance le jeu

    try: para = menu("SNAKE", "Lancer la partie", ["Mode","Classique","Dingue"], ["Difficulté","Moyen","Difficile"," Extrême","Facile"], ["Bordures","Mortelles","  Téléportation"], ["Commandes"," Nav: Flèches","Menu: HOME","Rejouer: OK"], ["Crédits","Arthur J.","Vincent R."])

    except: para = ["Classique","Moyen","Mortelles"]

    play(para)


start()