jeu_de_la_vie
Différences
Ci-dessous, les différences entre deux révisions de la page.
Les deux révisions précédentesRévision précédenteProchaine révision | Révision précédenteProchaine révisionLes deux révisions suivantes | ||
jeu_de_la_vie [2019/10/07 09:06] – Camille | jeu_de_la_vie [2019/10/18 15:08] – Mushussu | ||
---|---|---|---|
Ligne 1: | Ligne 1: | ||
- | ====== | + | ====== Documentation du projet "Jeu de la vie" réalisé pour Centre Sciences en 2019 ====== |
===== Introduction: | ===== Introduction: | ||
==== Cadre ==== | ==== Cadre ==== | ||
- | L' | + | L' |
- | ==== Qu' | + | |
- | D' | + | ==== Qu' |
- | //Le jeu de la vie est un automate cellulaire imaginé par John Horton Conway en 1970 et qui est probablement le plus connu de tous les automates cellulaires. | + | D' |
+ | |||
+ | Le jeu de la vie est un automate cellulaire imaginé par John Horton Conway en 1970 et qui est probablement le plus connu de tous les automates cellulaires. | ||
Le jeu de la vie n’est pas un jeu, puisqu' | Le jeu de la vie n’est pas un jeu, puisqu' | ||
Le « jeu » se déroule sur une grille à deux dimensions, théoriquement infinie (mais de longueur et de largeur finies et plus ou moins grandes dans la pratique), dont les cases — qu’on appelle des « cellules », par analogie avec les cellules vivantes — peuvent prendre deux états distincts : « vivante » ou « morte ». | Le « jeu » se déroule sur une grille à deux dimensions, théoriquement infinie (mais de longueur et de largeur finies et plus ou moins grandes dans la pratique), dont les cases — qu’on appelle des « cellules », par analogie avec les cellules vivantes — peuvent prendre deux états distincts : « vivante » ou « morte ». | ||
- | **À chaque étape, l’évolution d’une cellule est entièrement déterminée par l’état de ses huit voisines** de la façon suivante : | + | **À chaque étape, l’évolution d’une cellule est entièrement déterminée par l’état de ses huit voisines** de la façon suivante : |
+ | |||
+ | * Une cellule morte possédant exactement trois voisines vivantes devient vivante (elle naît). | ||
+ | * Une cellule vivante possédant deux ou trois voisines vivantes le reste, sinon elle meurt. | ||
- | * Une cellule morte possédant exactement trois voisines vivantes devient vivante (elle naît).\\ | ||
- | * | ||
- | * Une cellule vivante possédant deux ou trois voisines vivantes le reste, sinon elle meurt.\\ // | ||
- | * | ||
**La configuration de départ détermine entièrement l' | **La configuration de départ détermine entièrement l' | ||
+ | |||
=====Cahier des charges===== | =====Cahier des charges===== | ||
Dans le cadre d'une exposition, il était nécessaire d' | Dans le cadre d'une exposition, il était nécessaire d' | ||
Le tout devait être assez compact et transportable. | Le tout devait être assez compact et transportable. | ||
+ | |||
=====Réalisation===== | =====Réalisation===== | ||
Les choix techniques ont été les suivants:\\ | Les choix techniques ont été les suivants:\\ | ||
Ligne 42: | Ligne 45: | ||
{{: | {{: | ||
+ | |||
=====Matériel===== | =====Matériel===== | ||
Un plateau de jeu dont un carré de 4x4 trous sont évidés de façon à laisser s' | Un plateau de jeu dont un carré de 4x4 trous sont évidés de façon à laisser s' | ||
Ligne 51: | Ligne 55: | ||
Une RaspberryPi pour la gestion des événements et l' | Une RaspberryPi pour la gestion des événements et l' | ||
Un écran Waveshare 1920x1080 pixels | Un écran Waveshare 1920x1080 pixels | ||
+ | |||
=====Logiciel===== | =====Logiciel===== | ||
Un code python pour la prise en compte des billes et l' | Un code python pour la prise en compte des billes et l' | ||
OS Raspbian version Buster (10.4 (?)) | OS Raspbian version Buster (10.4 (?)) | ||
- | Modifications de l' | + | Modifications de l'OS:\\ |
- | -prise en compte du bouton marche/ | + | -prise en compte du bouton marche/ |
- | -lancement du programme Jeu de la vie au démarrage de l'OS | + | -lancement du programme Jeu de la vie au démarrage de l'OS\\ |
- | Sauvegarde du système complet sur une carte SD de secours: procédure | + | Sauvegarde du système complet sur une carte SD de secours: procédure\\ |
- | -copie de la carte SD d' | + | -copie de la carte SD d' |
- | -copie sur une autre carte SD | + | -copie sur une autre carte SD\\ |
- | Liste exhaustive du matériel: | + | Liste exhaustive du matériel:\\ |
- | Photos | + | Photos\\ |
- | Codes | + | Codes\\ |
- | Schéma électrique pour les FSR | + | Le code a été écrit en python et utilise la bibliothèque pygame. Il s'agit de l' |
- | Schéma d' | + | http:// |
- | Schéma de câblage sur la Raspberry | + | |
+ | |||
+ | ======================================================= | ||
+ | |||
+ | <code python> | ||
+ | '' | ||
+ | import pygame, sys\\ | ||
+ | from pygame.locals import *\\ | ||
+ | import random\\ | ||
+ | import RPi.GPIO as GPIO\\ | ||
+ | from time import sleep\\ | ||
+ | '' | ||
+ | '' | ||
+ | GPIOCasesInit = {17:(9,4), 27:(10,4), 22:(11,4), 5:(12,4), 6:(9,5), 13:(10,5), 19:(11,5), 26:(12,5), 18:(9,6), 24:(10,6), 23:(11,6), 25:(12,6), 12:(9,7), 16:(10,7), 20:(11,7), 21: | ||
+ | assert len(GPIOCasesInit)==16\\ | ||
+ | assert len(set(GPIOCasesInit.values()))==16\\ | ||
+ | GPIO.setmode(GPIO.BCM)\\ | ||
+ | '' | ||
+ | '' | ||
+ | for n in GPIOCasesInit: | ||
+ | GPIO.setup(n, | ||
+ | GPIO.setup(14, | ||
+ | GPIO.setup(15, | ||
+ | '' | ||
+ | '' | ||
+ | GPIO.add_event_detect(14, | ||
+ | GPIO.add_event_detect(15, | ||
+ | #Number of frames per second\\ | ||
+ | FPS = 10\\ | ||
+ | |||
+ | ###Sets size of grid\\ | ||
+ | WINDOWWIDTH = 1920\\ | ||
+ | WINDOWHEIGHT = 1080\\ | ||
+ | CELLSIZE = 40\\ | ||
+ | |||
+ | #Check to see if the width and height are multiples of the cell size.\\ | ||
+ | assert WINDOWWIDTH % CELLSIZE == 0, " | ||
+ | assert WINDOWHEIGHT % CELLSIZE == 0, " | ||
+ | |||
+ | #Determine number of cells in horizonatl and vertical plane\\ | ||
+ | CELLWIDTH = WINDOWWIDTH / CELLSIZE # number of cells wide\\ | ||
+ | CELLHEIGHT = WINDOWHEIGHT / CELLSIZE # Number of cells high\\ | ||
+ | |||
+ | # set up the colours\\ | ||
+ | BLACK = (0, 0, 0)\\ | ||
+ | WHITE = (255, | ||
+ | DARKGRAY = (40, 40, 40)\\ | ||
+ | GREEN = (50, | ||
+ | RED = (255, 0, 100)\\ | ||
+ | |||
+ | BoxExample = {1:(3,10), 2:(15,10), 3:(2,11), 4:(4,11), 5:(10,11), 6:(14,11), 7:(16,11), 8:(3,12), 9:(9,12), 10:(10,12), 11:(11,12), 12:(14,12), 13:(16,12), 14:(15,13), 15:(4,16), 16:(9,16), 17:(10,16), 18:(14,16), 19:(16,16), 20:(17,16), 21:(5,17), 22:(8,17), 23:(11,17), 24:(14,17), 25:(15,17), 26:(17,17), 27:(3,18), 28:(4,18), 29:(5,18), 30:(9,18), 31:(11,18), 32:(10,19), 33: | ||
+ | |||
+ | def text_objects(text, | ||
+ | textSurface = font.render(text, | ||
+ | return textSurface, | ||
+ | |||
+ | def afficheInit(text, | ||
+ | largeText = pygame.font.Font(' | ||
+ | TextSurf, TextRect = text_objects(text, | ||
+ | TextRect.center = (x,y)\\ | ||
+ | DISPLAYSURF.blit(TextSurf, | ||
+ | pygame.display.update()\\ | ||
+ | # | ||
+ | |||
+ | #Draws the grid lines\\ | ||
+ | def drawGrid(): | ||
+ | for x in range(0, WINDOWWIDTH, | ||
+ | pygame.draw.line(DISPLAYSURF, | ||
+ | for y in range (0, WINDOWHEIGHT, | ||
+ | pygame.draw.line(DISPLAYSURF, | ||
+ | |||
+ | |||
+ | def drawGridExample(): | ||
+ | for n in BoxExample: | ||
+ | pygame.draw.rect(DISPLAYSURF, | ||
+ | |||
+ | #Colours the cells green for life and white for no life\\ | ||
+ | def colourGrid(item, | ||
+ | x = item[0]\\ | ||
+ | y = item[1]\\ | ||
+ | y = y * CELLSIZE # translates array into grid size\\ | ||
+ | x = x * CELLSIZE # translates array into grid size\\ | ||
+ | if lifeDict[item] == 0:\\ | ||
+ | pygame.draw.rect(DISPLAYSURF, | ||
+ | if lifeDict[item] == 1:\\ | ||
+ | pygame.draw.rect(DISPLAYSURF, | ||
+ | # | ||
+ | return lifeDict[item]\\ | ||
+ | |||
+ | #Creation un dictionnaire de l' | ||
+ | #Toutes les cellules sont " | ||
+ | def blankGrid(): | ||
+ | gridDict = {}\\ | ||
+ | #Creation d un dictionnaire pour toutes les cellules de la grille\\ | ||
+ | for y in range (CELLHEIGHT): | ||
+ | for x in range (CELLWIDTH): | ||
+ | gridDict[x, | ||
+ | return gridDict\\ | ||
+ | |||
+ | def startingGridInit(lifeDict, | ||
+ | for ncapt in GPIOCasesInit: | ||
+ | if(GPIO.input(ncapt)!=0): | ||
+ | lifeDict[GPIOCasesInit[ncapt]] = 1\\ | ||
+ | # | ||
+ | # | ||
+ | return lifeDict\\ | ||
+ | |||
+ | #Determines how many alive neighbours there are around each cell\\ | ||
+ | def getNeighbours(item, | ||
+ | neighbours = 0\\ | ||
+ | for x in range (-1,2):\\ | ||
+ | for y in range (-1,2):\\ | ||
+ | checkCell = (item[0]+x, | ||
+ | if checkCell[0] < CELLWIDTH | ||
+ | if checkCell [1] < CELLHEIGHT and checkCell[1]> | ||
+ | if lifeDict[checkCell] == 1:\\ | ||
+ | if x == 0 and y == 0: # negate the central cell\\ | ||
+ | neighbours += 0\\ | ||
+ | else:\\ | ||
+ | neighbours += 1\\ | ||
+ | return neighbours\\ | ||
+ | |||
+ | #determines the next generation by running a ' | ||
+ | def tick(lifeDict): | ||
+ | newTick = {}\\ | ||
+ | for item in lifeDict: | ||
+ | #get number of neighbours for that item\\ | ||
+ | numberNeighbours = getNeighbours(item, | ||
+ | if lifeDict[item] == 1: # For those cells already alive\\ | ||
+ | if numberNeighbours < 2: # kill under-population\\ | ||
+ | newTick[item] = 0\\ | ||
+ | elif numberNeighbours > 3: #kill over-population\\ | ||
+ | newTick[item] = 0\\ | ||
+ | else:\\ | ||
+ | newTick[item] = 1 # keep status quo (life)\\ | ||
+ | elif lifeDict[item] == 0:\\ | ||
+ | if numberNeighbours == 3: # cell reproduces\\ | ||
+ | newTick[item] = 1\\ | ||
+ | else:\\ | ||
+ | newTick[item] = 0 # keep status quo (death)\\ | ||
+ | return newTick\\ | ||
+ | |||
+ | #main function\\ | ||
+ | def main():\\ | ||
+ | |||
+ | ps14=0\\ | ||
+ | ps15=0\\ | ||
+ | cs14=0\\ | ||
+ | cs15=0\\ | ||
+ | # GPIOCasesInit = {17:(9,4), 27:(10,4), 22:(11,4), 5:(12,4), 6:(9,5), 13:(10,5), 19:(11,5), 26:(12,5), 12:(9,6), 23:(11,6), 25:(12,6), 21:(9,7), 16:(10,7), 20: | ||
+ | etat=0\\ | ||
+ | FLAG_PUSH = 0\\ | ||
+ | pygame.init()\\ | ||
+ | global DISPLAYSURF\\ | ||
+ | FPSCLOCK = pygame.time.Clock()\\ | ||
+ | DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH, | ||
+ | pygame.display.set_caption(' | ||
+ | DISPLAYSURF.fill(WHITE)\\ | ||
+ | # GPIOCasesInit=valCaptInit()\\ | ||
+ | lifeDict = blankGrid() #Creation un dictionnaire de cellules, initialisation a zero\\ | ||
+ | #lifeDict = startingGridInit(lifeDict, | ||
+ | #Colours the live cells, blanks the dead\\ | ||
+ | for item in lifeDict: | ||
+ | colourGrid(item, | ||
+ | drawGrid()\\ | ||
+ | pygame.display.update()\\ | ||
+ | while True: #main game loop\\ | ||
+ | for event in pygame.event.get(): | ||
+ | if event.type == QUIT:\\ | ||
+ | pygame.quit()\\ | ||
+ | sys.exit()\\ | ||
+ | if event.type == pygame.KEYUP: | ||
+ | DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH, | ||
+ | cs14=GPIO.input(14)\\ | ||
+ | cs15=GPIO.input(15)\\ | ||
+ | if ps14!=cs14: | ||
+ | print(' | ||
+ | print(' | ||
+ | if(etat==0): | ||
+ | afficheInit(' | ||
+ | afficheInit(' | ||
+ | afficheInit(' | ||
+ | drawGridExample()\\ | ||
+ | pygame.display.update()\\ | ||
+ | #passage a etat suivant\\ | ||
+ | # if GPIO.event_detected(14): | ||
+ | if(ps14==1 and cs14==0): | ||
+ | doit_demarrer=False\\ | ||
+ | nb_viv=0\\ | ||
+ | for elem in GPIOCasesInit: | ||
+ | if(GPIO.input(elem)): | ||
+ | doit_demarrer = True\\ | ||
+ | nb_viv+=1\\ | ||
+ | print(GPIOCasesInit[elem])\\ | ||
+ | print(' | ||
+ | if doit_demarrer: | ||
+ | etat=1\\ | ||
+ | lifeDict = startingGridInit(lifeDict, | ||
+ | |||
+ | else:\\ | ||
+ | etat=0\\ | ||
+ | elif(etat==1): | ||
+ | if(ps15==1 and cs15==0): | ||
+ | # if GPIO.event_detected(15): | ||
+ | etat=0 | ||
+ | lifeDict=blankGrid() | ||
+ | if(ps14==1 and cs14==0): | ||
+ | # if GPIO.event_detected(14): | ||
+ | #runs a tick | ||
+ | nb_viv=0 | ||
+ | lifeDict = tick(lifeDict) | ||
+ | print(' | ||
+ | for item in lifeDict: | ||
+ | if(lifeDict[item]): | ||
+ | nb_viv=nb_viv+1 | ||
+ | print(nb_viv) | ||
+ | if(nb_viv==0): | ||
+ | print(' | ||
+ | etat=0 | ||
+ | #Colours the live cells, blanks the dead | ||
+ | for item in lifeDict: | ||
+ | colourGrid(item, | ||
+ | drawGrid() | ||
+ | pygame.display.update() | ||
+ | # | ||
+ | # | ||
+ | ps14=cs14 | ||
+ | ps15=cs15 | ||
+ | sleep(0.1) | ||
+ | # | ||
+ | |||
+ | if __name__==' | ||
+ | main() | ||
+ | |||
+ | |||
+ | '' | ||
+ | </ | ||
+ | ======================================================= | ||
+ | |||
+ | |||
+ | |||
+ | Schéma électrique pour les FSR\\ | ||
+ | Schéma d' | ||
+ | Schéma de câblage sur la Raspberry\\ | ||
=====Retour d' | =====Retour d' | ||
Ligne 83: | Ligne 331: | ||
Le mieux pour simuler la pression du doigt c’est une « goutte d’eau », pieds autocollants antidérapant en forme de demi-hémisphère sur les cylindres | Le mieux pour simuler la pression du doigt c’est une « goutte d’eau », pieds autocollants antidérapant en forme de demi-hémisphère sur les cylindres | ||
- | |||
- | |||
- | > | ||
> Le 19.07.2019 11:01, Guy Antoine a écrit : | > Le 19.07.2019 11:01, Guy Antoine a écrit : | ||
>> Bonjour Camille | >> Bonjour Camille | ||
Ligne 93: | Ligne 338: | ||
>> en plexi mais c'est très " | >> en plexi mais c'est très " | ||
>> Donc on vérifieras au règlage s'il faut les lester. | >> Donc on vérifieras au règlage s'il faut les lester. | ||
- | |||
- | |||
Modifications en vue de la version 2: | Modifications en vue de la version 2: | ||
Il s' | Il s' | ||
jeu_de_la_vie.txt · Dernière modification : 2020/10/29 14:03 de serge