serpentgame.py 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. #!/usr/bin/python
  2. import time
  3. import random
  4. from pad import *
  5. from serpentdata import *
  6. from apcmini import APCMini
  7. """
  8. Un element du serpent
  9. contient la position (x et y) et la direction
  10. """
  11. class SerpentCase:
  12. def __init__(self, x, y, dir):
  13. self.x=x
  14. self.y=y
  15. self.dir=dir
  16. # retourne la position dans un tuple
  17. def pos(self):
  18. return (self.x, self.y)
  19. #retourne la prochaine position (au pas suivant) sans modifier l'objet
  20. def peekNext(self):
  21. if self.dir==SerpentAPCMini.UP:
  22. return (self.x,(self.y+1)%8)
  23. elif self.dir==SerpentAPCMini.DOWN:
  24. return (self.x,(self.y-1)%8)
  25. elif self.dir==SerpentAPCMini.LEFT:
  26. return ((self.x-1)%8, self.y)
  27. elif self.dir==SerpentAPCMini.RIGHT:
  28. return ((self.x+1)%8, self.y)
  29. def obstacleFromMatrix(mat):
  30. out=[]
  31. for j in range(len(mat)):
  32. for i in range(len(mat[j])):
  33. if mat[j][i]:
  34. out.append((i,len(mat)-j-1))
  35. return out
  36. """
  37. Classe qui gère le jeu du serpent sur l'AKAI APC Mini
  38. """
  39. class SerpentAPCMini(Pad):
  40. def __init__(self, adapter):
  41. Pad.__init__(self, adapter)
  42. SerpentAPCMini.UP=64
  43. SerpentAPCMini.DOWN=65
  44. SerpentAPCMini.LEFT=66
  45. SerpentAPCMini.RIGHT=67
  46. SerpentAPCMini.EXIT=98
  47. SerpentAPCMini.EMPTY=0
  48. SerpentAPCMini.SERPENT=1
  49. SerpentAPCMini.FRUIT=2
  50. SerpentAPCMini.OBSTACLE=2
  51. SerpentAPCMini.SERPENT_COLOR=1
  52. SerpentAPCMini.FRUIT_COLOR=5
  53. SerpentAPCMini.OBSTACLE_COLOR=3
  54. self.lastTime=time.time()
  55. self.dir=SerpentAPCMini.LEFT
  56. self.changed=False
  57. self.timeToWait=1
  58. self.scoreleds=[89,88,87,86,85,84,83,82,71,70]
  59. self.levels=SERPENT_LEVELS
  60. self.levelIndex=0
  61. #self.scoreleds=[70,71,82,83,84,85,86,87,88,89]
  62. """
  63. Gere les input, notamment l'allumage des leds des boutons directionnels
  64. """
  65. def onNoteOn(self, channel, idx, val):
  66. if idx==SerpentAPCMini.UP and self.serpent[0].dir!=SerpentAPCMini.DOWN:
  67. self.changed=True
  68. self.serpent[0].dir=idx;
  69. self[idx].on()
  70. elif idx==SerpentAPCMini.DOWN and self.serpent[0].dir!=SerpentAPCMini.UP:
  71. self.changed=True
  72. self.serpent[0].dir=idx;
  73. self[idx].on()
  74. elif idx==SerpentAPCMini.LEFT and self.serpent[0].dir!=SerpentAPCMini.RIGHT:
  75. self.changed=True
  76. self.serpent[0].dir=idx;
  77. self[idx].on()
  78. elif idx==SerpentAPCMini.RIGHT and self.serpent[0].dir!=SerpentAPCMini.LEFT:
  79. self.changed=True
  80. self.serpent[0].dir=idx;
  81. self[idx].on()
  82. elif idx==SerpentAPCMini.EXIT:
  83. self.stop=True
  84. """
  85. Gere les input, notamment l'extinction des leds des boutons directionnels
  86. """
  87. def onNoteOff(self, channel, idx, val):
  88. if idx==SerpentAPCMini.UP and self.serpent[0].dir!=SerpentAPCMini.DOWN:
  89. self[idx].off()
  90. elif idx==SerpentAPCMini.DOWN and self.serpent[0].dir!=SerpentAPCMini.UP:
  91. self[idx].off()
  92. elif idx==SerpentAPCMini.LEFT and self.serpent[0].dir!=SerpentAPCMini.RIGHT:
  93. self[idx].off()
  94. elif idx==SerpentAPCMini.RIGHT and self.serpent[0].dir!=SerpentAPCMini.LEFT:
  95. self[idx].off()
  96. """
  97. Retourne l'état d'une case d'un jeu (Serpent, fruit, obstacle ou vide)
  98. """
  99. def stateAt(self, x, y=None):
  100. if y==None and (isinstance(x,tuple) or isinstance(x,tuple)):
  101. y=x[1]
  102. x=x[0]
  103. for s in self.serpent:
  104. if s.x==x and s.y==y:
  105. return SerpentAPCMini.SERPENT
  106. for s in self.fruits:
  107. if s[0]==x and s[1]==y:
  108. return SerpentAPCMini.FRUIT
  109. for s in self.obstacle:
  110. if s[0]==x and s[1]==y:
  111. return SerpentAPCMini.FRUIT
  112. return SerpentAPCMini.EMPTY
  113. """
  114. Renvoie une position disponible pour un nouveau fruit
  115. """
  116. def nextFruit(self):
  117. for i in range(64):
  118. x=random.randint(0,7)
  119. y=random.randint(0,7)
  120. if self.stateAt(x,y)==SerpentAPCMini.EMPTY:
  121. return (x,y)
  122. """
  123. Fonction d'affichage de la grille
  124. """
  125. def refresh(self):
  126. x=[]
  127. for i in range(8):
  128. x.append([0,0,0,0,0,0,0,0])
  129. for s in self.fruits:
  130. x[s[1]][s[0]]=SerpentAPCMini.FRUIT_COLOR
  131. for s in self.serpent:
  132. x[s.y][s.x]=SerpentAPCMini.SERPENT_COLOR
  133. for s in self.obstacle:
  134. x[s[1]][s[0]]=SerpentAPCMini.OBSTACLE_COLOR
  135. for j in range(8):
  136. for i in range(8):
  137. self[i,j].send(x[j][i])
  138. """
  139. Vérifie si une collision a lieu
  140. Retour:
  141. True -> Collision
  142. False -> Pas de collision
  143. """
  144. def collision(self):
  145. s=self.serpent[0].pos()
  146. for i in range(1, len(self.serpent)):
  147. ss=self.serpent[i].pos()
  148. if ss[0]==s[0] and ss[1]==s[1]:
  149. return True
  150. for o in self.obstacle:
  151. if o[0]==s[0] and o[1]==s[1]:
  152. return True
  153. return False
  154. """
  155. Affiche les score sur les leds ronde de droite
  156. """
  157. def printScore(self): #binary
  158. for i in range(len(self.scoreleds)):
  159. if (self.score & (1<<i))>0:
  160. self[self.scoreleds[i]].on()
  161. else:
  162. self[self.scoreleds[i]].off()
  163. """
  164. Fait un pas dans le jeu (un mouvement automatique du serpent)
  165. """
  166. def step(self):
  167. s=(self.serpent[0].x, self.serpent[0].y)
  168. #modification de la vitesse en fonction du score
  169. self.timeToWait=self.levels[self.levelIndex]['speeds'][self.score]
  170. #vérifie si le serpent mange un fruit
  171. for x in self.fruits:
  172. if s[0]==x[0] and s[1]==x[1]:
  173. l=self.serpent[0]
  174. self.serpent.append(SerpentCase(l.x, l.y, l.dir))
  175. for fi in range(len(self.fruits)):
  176. f=self.fruits[fi]
  177. if f[0]==l.x and f[1]==l.y:
  178. self.fruits[fi]=self.nextFruit()
  179. self.timeToWait*=0.9
  180. self.score+=1
  181. #bouge le serpent d'un pas
  182. for xx in reversed(range(len(self.serpent))):
  183. x=self.serpent[xx]
  184. if xx==0:
  185. if x.dir==SerpentAPCMini.UP:
  186. x.y=(x.y+1)%8
  187. elif x.dir==SerpentAPCMini.DOWN:
  188. x.y=(x.y-1)%8
  189. elif x.dir==SerpentAPCMini.LEFT:
  190. x.x=(x.x-1)%8
  191. elif x.dir==SerpentAPCMini.RIGHT:
  192. x.x=(x.x+1)%8
  193. else:
  194. y=self.serpent[xx-1]
  195. x.x=y.x
  196. x.y=y.y
  197. x.dir=y.dir
  198. """
  199. Affiche l'écran de Game Over:
  200. TODO: Permettre de passer l'écran en appuyant sur une touche
  201. """
  202. def gameOver(self):
  203. self.stop=False
  204. self.changed=False
  205. # etape 1 affichage score et game over
  206. txt = Text(" Score:"+str(self.score)+" Game Over! ", (8,4), (0,2))
  207. txt.setColor(LedButton.RED)
  208. self.fill(LedButton.RED_BLINK)
  209. time.sleep(2)
  210. self.clear()
  211. for x in range(txt.stepCount()):
  212. self.showText(txt)
  213. if self.pollInput()!=None: break
  214. time.sleep(0.2)
  215. # etape 2 affichage score et try again, avec les input pour
  216. # quitter ou recommencer
  217. txt = Text(" Score:"+str(self.score)+" Try Again? ", (8,4), (0,4))
  218. txt.setColor(LedButton.YELLOW)
  219. yes=Text.letterVector('Y', LedButton.GREEN_BLINK)
  220. no=Text.letterVector('N', LedButton.RED_BLINK)
  221. self.mapSubRect(yes, (0,0), (4,4))
  222. self.mapSubRect(no, (5,0), (9,4))
  223. i=0
  224. while self.stop==False:
  225. if i%4==0:
  226. self.showText(txt)
  227. self.printScore()
  228. i=i+1
  229. yesIdx=[0,1,2,3,8,9,10,11,16,17,18,19,24,25,26,27]
  230. for v in yesIdx:
  231. if self.getInputState(v):
  232. return True
  233. noIdx=[4,5,6,7,12,13,14,15,20,21,22,23,28,29,30,31,98]
  234. for v in noIdx:
  235. if self.getInputState(v):
  236. return False
  237. time.sleep(0.05)
  238. """
  239. Initialise une nouvelle partie
  240. Retour:
  241. True: si tous les niveaux sont finis (pas de partie à charger)
  242. False: si un niveau a été trouvé
  243. """
  244. def __newGame(self):
  245. self.score=0
  246. self.stop=False
  247. self.loose=False
  248. self.serpent=[]
  249. self.fruits=[]
  250. if self.levelIndex >= len(self.levels):
  251. return True
  252. self.obstacle=obstacleFromMatrix(self.levels[self.levelIndex]['obstacles'])
  253. self.serpent.append(SerpentCase(4,3,SerpentAPCMini.RIGHT))
  254. self.serpent.append(SerpentCase(3,3,SerpentAPCMini.RIGHT))
  255. self.serpent.append(SerpentCase(2,3,SerpentAPCMini.RIGHT))
  256. self.fruits.append(self.nextFruit())
  257. self.timeToWait=self.levels[self.levelIndex]['speeds'][self.score]
  258. return False
  259. """
  260. Démarre le jeu, cette fonction boucle durant tout le jeu sur elle même
  261. TODO: Pouvoir recommencer ou arreter quand on gagne le jeu
  262. """
  263. def start(self):
  264. continuer=True
  265. nextLevel=False
  266. while continuer:
  267. #if self.levelIndex<len(self.levels): ## gagné
  268. # pass
  269. #else:
  270. nextLevel=False
  271. self.__newGame()
  272. self.lastTime=time.time()
  273. self.clear()
  274. txt = Text(" Level "+str(self.levelIndex+1)+" ", (8,4), (0,2))
  275. for x in range(txt.stepCount()-2):
  276. self.showText(txt)
  277. if self.pollInput()!=None: break
  278. time.sleep(0.1)
  279. self.fill(LedButton.GREEN_BLINK)
  280. time.sleep(2)
  281. while self.loose==False and self.stop==False:
  282. while self.timeToWait+self.lastTime>time.time() and self.changed==False:
  283. time.sleep(0.001)
  284. self.step()
  285. self.refresh()
  286. self.printScore()
  287. if self.collision():
  288. break
  289. self.changed=False
  290. if self.score>=len(self.levels[self.levelIndex]['speeds']):
  291. self.levelIndex+=1
  292. nextLevel=True
  293. break
  294. self.lastTime=time.time()
  295. if not nextLevel:
  296. continuer=self.gameOver()
  297. self.clear()
  298. return False