#!/usr/bin/python import time import random from pad import * from serpentdata import * from apcmini import APCMini """ Un element du serpent contient la position (x et y) et la direction """ class SerpentCase: def __init__(self, x, y, dir): self.x=x self.y=y self.dir=dir # retourne la position dans un tuple def pos(self): return (self.x, self.y) #retourne la prochaine position (au pas suivant) sans modifier l'objet def peekNext(self): if self.dir==SerpentAPCMini.UP: return (self.x,(self.y+1)%8) elif self.dir==SerpentAPCMini.DOWN: return (self.x,(self.y-1)%8) elif self.dir==SerpentAPCMini.LEFT: return ((self.x-1)%8, self.y) elif self.dir==SerpentAPCMini.RIGHT: return ((self.x+1)%8, self.y) def obstacleFromMatrix(mat): out=[] for j in range(len(mat)): for i in range(len(mat[j])): if mat[j][i]: out.append((i,len(mat)-j-1)) return out """ Classe qui gère le jeu du serpent sur l'AKAI APC Mini """ class SerpentAPCMini(Pad): def __init__(self, adapter): Pad.__init__(self, adapter) SerpentAPCMini.UP=64 SerpentAPCMini.DOWN=65 SerpentAPCMini.LEFT=66 SerpentAPCMini.RIGHT=67 SerpentAPCMini.EXIT=98 SerpentAPCMini.EMPTY=0 SerpentAPCMini.SERPENT=1 SerpentAPCMini.FRUIT=2 SerpentAPCMini.OBSTACLE=2 SerpentAPCMini.SERPENT_COLOR=1 SerpentAPCMini.FRUIT_COLOR=5 SerpentAPCMini.OBSTACLE_COLOR=3 self.lastTime=time.time() self.dir=SerpentAPCMini.LEFT self.changed=False self.timeToWait=1 self.scoreleds=[89,88,87,86,85,84,83,82,71,70] self.levels=SERPENT_LEVELS self.levelIndex=0 #self.scoreleds=[70,71,82,83,84,85,86,87,88,89] """ Gere les input, notamment l'allumage des leds des boutons directionnels """ def onNoteOn(self, channel, idx, val): if idx==SerpentAPCMini.UP and self.serpent[0].dir!=SerpentAPCMini.DOWN: self.changed=True self.serpent[0].dir=idx; self[idx].on() elif idx==SerpentAPCMini.DOWN and self.serpent[0].dir!=SerpentAPCMini.UP: self.changed=True self.serpent[0].dir=idx; self[idx].on() elif idx==SerpentAPCMini.LEFT and self.serpent[0].dir!=SerpentAPCMini.RIGHT: self.changed=True self.serpent[0].dir=idx; self[idx].on() elif idx==SerpentAPCMini.RIGHT and self.serpent[0].dir!=SerpentAPCMini.LEFT: self.changed=True self.serpent[0].dir=idx; self[idx].on() elif idx==SerpentAPCMini.EXIT: self.stop=True """ Gere les input, notamment l'extinction des leds des boutons directionnels """ def onNoteOff(self, channel, idx, val): if idx==SerpentAPCMini.UP and self.serpent[0].dir!=SerpentAPCMini.DOWN: self[idx].off() elif idx==SerpentAPCMini.DOWN and self.serpent[0].dir!=SerpentAPCMini.UP: self[idx].off() elif idx==SerpentAPCMini.LEFT and self.serpent[0].dir!=SerpentAPCMini.RIGHT: self[idx].off() elif idx==SerpentAPCMini.RIGHT and self.serpent[0].dir!=SerpentAPCMini.LEFT: self[idx].off() """ Retourne l'état d'une case d'un jeu (Serpent, fruit, obstacle ou vide) """ def stateAt(self, x, y=None): if y==None and (isinstance(x,tuple) or isinstance(x,tuple)): y=x[1] x=x[0] for s in self.serpent: if s.x==x and s.y==y: return SerpentAPCMini.SERPENT for s in self.fruits: if s[0]==x and s[1]==y: return SerpentAPCMini.FRUIT for s in self.obstacle: if s[0]==x and s[1]==y: return SerpentAPCMini.FRUIT return SerpentAPCMini.EMPTY """ Renvoie une position disponible pour un nouveau fruit """ def nextFruit(self): for i in range(64): x=random.randint(0,7) y=random.randint(0,7) if self.stateAt(x,y)==SerpentAPCMini.EMPTY: return (x,y) """ Fonction d'affichage de la grille """ def refresh(self): x=[] for i in range(8): x.append([0,0,0,0,0,0,0,0]) for s in self.fruits: x[s[1]][s[0]]=SerpentAPCMini.FRUIT_COLOR for s in self.serpent: x[s.y][s.x]=SerpentAPCMini.SERPENT_COLOR for s in self.obstacle: x[s[1]][s[0]]=SerpentAPCMini.OBSTACLE_COLOR for j in range(8): for i in range(8): self[i,j].send(x[j][i]) """ Vérifie si une collision a lieu Retour: True -> Collision False -> Pas de collision """ def collision(self): s=self.serpent[0].pos() for i in range(1, len(self.serpent)): ss=self.serpent[i].pos() if ss[0]==s[0] and ss[1]==s[1]: return True for o in self.obstacle: if o[0]==s[0] and o[1]==s[1]: return True return False """ Affiche les score sur les leds ronde de droite """ def printScore(self): #binary for i in range(len(self.scoreleds)): if (self.score & (1<0: self[self.scoreleds[i]].on() else: self[self.scoreleds[i]].off() """ Fait un pas dans le jeu (un mouvement automatique du serpent) """ def step(self): s=(self.serpent[0].x, self.serpent[0].y) #modification de la vitesse en fonction du score self.timeToWait=self.levels[self.levelIndex]['speeds'][self.score] #vérifie si le serpent mange un fruit for x in self.fruits: if s[0]==x[0] and s[1]==x[1]: l=self.serpent[0] self.serpent.append(SerpentCase(l.x, l.y, l.dir)) for fi in range(len(self.fruits)): f=self.fruits[fi] if f[0]==l.x and f[1]==l.y: self.fruits[fi]=self.nextFruit() self.timeToWait*=0.9 self.score+=1 #bouge le serpent d'un pas for xx in reversed(range(len(self.serpent))): x=self.serpent[xx] if xx==0: if x.dir==SerpentAPCMini.UP: x.y=(x.y+1)%8 elif x.dir==SerpentAPCMini.DOWN: x.y=(x.y-1)%8 elif x.dir==SerpentAPCMini.LEFT: x.x=(x.x-1)%8 elif x.dir==SerpentAPCMini.RIGHT: x.x=(x.x+1)%8 else: y=self.serpent[xx-1] x.x=y.x x.y=y.y x.dir=y.dir """ Affiche l'écran de Game Over: TODO: Permettre de passer l'écran en appuyant sur une touche """ def gameOver(self): self.stop=False self.changed=False # etape 1 affichage score et game over txt = Text(" Score:"+str(self.score)+" Game Over! ", (8,4), (0,2)) txt.setColor(LedButton.RED) self.fill(LedButton.RED_BLINK) time.sleep(2) self.clear() for x in range(txt.stepCount()): self.showText(txt) if self.pollInput()!=None: break time.sleep(0.2) # etape 2 affichage score et try again, avec les input pour # quitter ou recommencer txt = Text(" Score:"+str(self.score)+" Try Again? ", (8,4), (0,4)) txt.setColor(LedButton.YELLOW) yes=Text.letterVector('Y', LedButton.GREEN_BLINK) no=Text.letterVector('N', LedButton.RED_BLINK) self.mapSubRect(yes, (0,0), (4,4)) self.mapSubRect(no, (5,0), (9,4)) i=0 while self.stop==False: if i%4==0: self.showText(txt) self.printScore() i=i+1 yesIdx=[0,1,2,3,8,9,10,11,16,17,18,19,24,25,26,27] for v in yesIdx: if self.getInputState(v): return True noIdx=[4,5,6,7,12,13,14,15,20,21,22,23,28,29,30,31,98] for v in noIdx: if self.getInputState(v): return False time.sleep(0.05) """ Initialise une nouvelle partie Retour: True: si tous les niveaux sont finis (pas de partie à charger) False: si un niveau a été trouvé """ def __newGame(self): self.score=0 self.stop=False self.loose=False self.serpent=[] self.fruits=[] if self.levelIndex >= len(self.levels): return True self.obstacle=obstacleFromMatrix(self.levels[self.levelIndex]['obstacles']) self.serpent.append(SerpentCase(4,3,SerpentAPCMini.RIGHT)) self.serpent.append(SerpentCase(3,3,SerpentAPCMini.RIGHT)) self.serpent.append(SerpentCase(2,3,SerpentAPCMini.RIGHT)) self.fruits.append(self.nextFruit()) self.timeToWait=self.levels[self.levelIndex]['speeds'][self.score] return False """ Démarre le jeu, cette fonction boucle durant tout le jeu sur elle même TODO: Pouvoir recommencer ou arreter quand on gagne le jeu """ def start(self): continuer=True nextLevel=False while continuer: #if self.levelIndextime.time() and self.changed==False: time.sleep(0.001) self.step() self.refresh() self.printScore() if self.collision(): break self.changed=False if self.score>=len(self.levels[self.levelIndex]['speeds']): self.levelIndex+=1 nextLevel=True break self.lastTime=time.time() if not nextLevel: continuer=self.gameOver() self.clear() return False