-
Notifications
You must be signed in to change notification settings - Fork 8
/
JuegoDeLaVida.py
237 lines (180 loc) · 7.35 KB
/
JuegoDeLaVida.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
# https://github.com/Jonatandb/DotCSV-Juego-de-la-vida
# -*- coding: utf-8 -*-
#
import pygame
import time, os
import numpy as np
# Hago que la ventana aparezca centrada en Windows
os.environ["SDL_VIDEO_CENTERED"] = "1"
pygame.init()
# Establezco el título de la ventana:
pygame.display.set_caption("Juego de la vida - Jonatandb")
# Carga el icono si existe
iconPath = "./icono.ico"
if os.path.exists(iconPath):
icono = pygame.image.load(iconPath)
# Establece el icono de la ventana
pygame.display.set_icon(icono)
# Defino ancho y alto de la ventana
width, height = 700, 700
# Creación de la ventana
screen = pygame.display.set_mode((height, width))
# Color de fondo, casi negro
bg = 25, 25, 25
# Pinto el fondo con el color elegido (bg)
screen.fill(bg)
# Cantidad de celdas en cada eje
nxC, nyC = 60, 60
# Ancho y alto de cada celda
dimCW = width / nxC
dimCH = height / nyC
# Estructura de datos que contiene todos los estados de las diferentes celdas
# Estados de las celdas: Vivas = 1 - Muertas = 0
# Inicializo matriz con ceros
gameState = np.zeros((nxC, nyC))
# Autómata palo:
# 0 1 0
# 0 1 0
# 0 1 0
# gameState[5, 3] = 1
# gameState[5, 4] = 1
# gameState[5, 5] = 1
# Autómata móvil:
# 0 1 0
# 0 0 1
# 1 1 1
# gameState[21, 21] = 1
# gameState[22, 22] = 1
# gameState[22, 23] = 1
# gameState[21, 23] = 1
# gameState[20, 23] = 1
# Versión de mi autómata que siempre aparece centrada: Autómata Jonatandb :)
posInitX = int((nxC / 2) - 3)
posInitY = int((nyC / 2) - 5)
gameState[posInitX, posInitY] = 1
gameState[posInitX + 1, posInitY] = 1
gameState[posInitX + 2, posInitY] = 1
gameState[posInitX + 3, posInitY] = 1
gameState[posInitX + 3, posInitY + 1] = 1
gameState[posInitX + 3, posInitY + 2] = 1
gameState[posInitX, posInitY + 3] = 1
gameState[posInitX + 3, posInitY + 3] = 1
gameState[posInitX, posInitY + 4] = 1
gameState[posInitX + 1, posInitY + 4] = 1
gameState[posInitX + 2, posInitY + 4] = 1
gameState[posInitX + 3, posInitY + 4] = 1
# Control de la ejecución - En True se inicia pausado (Para poder ver la forma inicial de los aútomatas):
pauseExec = True
# Controla la finalización del juego:
endGame = False
# Acumulador de cantidad de iteraciones:
iteration = 0
clock = pygame.time.Clock()
# Bucle de ejecución principal (Main Loop):
while not endGame:
newGameState = np.copy(gameState)
# Vuelvo a colorear la pantalla con el color de fondo
screen.fill(bg)
# Agrego pequeña pausa para que el cpu no trabaje al 100%
time.sleep(0.1)
# Registro de eventos de teclado y mouse
ev = pygame.event.get()
# Contador de población:
population = 0
for event in ev:
# Si cierran la ventana finalizo el juego
if event.type == pygame.QUIT:
endGame = True
break
if event.type == pygame.KEYDOWN:
# Si tocan escape finalizo el juego
if event.key == pygame.K_ESCAPE:
endGame = True
break
# Si tocan la tecla r limpio la grilla, reseteo población e iteración y pongo pausa
if event.key == pygame.K_r:
iteration = 0
gameState = np.zeros((nxC, nyC))
newGameState = np.zeros((nxC, nyC))
pauseExec = True
else:
# Si tocan cualquier tecla no contemplada, pauso o reanudo el juego
pauseExec = not pauseExec
# Detección de click del mouse:
mouseClick = pygame.mouse.get_pressed()
# Obtención de posición del cursor en la pantalla:
# Si se hace click con cualquier botón del mouse, se obtiene un valor en mouseClick mayor a cero
if sum(mouseClick) > 0:
# Click del medio pausa / reanuda el juego
if mouseClick[1]:
pauseExec = not pauseExec
else:
# Obtengo las coordenadas del cursor del mouse en pixeles
posX, posY, = pygame.mouse.get_pos()
# Convierto de coordenadas en pixeles a celda clickeada en la grilla
celX, celY = int(np.floor(posX / dimCW)), int(np.floor(posY / dimCH))
# Click izquierdo y derecho permutan entre vida y muerte
newGameState[celX, celY] = not gameState[celX, celY]
if not pauseExec:
# Incremento el contador de generaciones
iteration += 1
# Recorro cada una de las celdas generadas
for y in range(0, nxC):
for x in range(0, nyC):
if not pauseExec:
# Cálculo del número de vecinos cercanos
n_neigh = (
gameState[(x - 1) % nxC, (y - 1) % nyC]
+ gameState[x % nxC, (y - 1) % nyC]
+ gameState[(x + 1) % nxC, (y - 1) % nyC]
+ gameState[(x - 1) % nxC, y % nyC]
+ gameState[(x + 1) % nxC, y % nyC]
+ gameState[(x - 1) % nxC, (y + 1) % nyC]
+ gameState[x % nxC, (y + 1) % nyC]
+ gameState[(x + 1) % nxC, (y + 1) % nyC]
)
# Una célula muerta con exactamente 3 células vecinas vivas "nace"
# (es decir, al turno siguiente estará viva).
if gameState[x, y] == 0 and n_neigh == 3:
newGameState[x, y] = 1
# Una célula viva con 2 o 3 células vecinas vivas sigue viva,
# en otro caso muere (por "soledad" o "superpoblación")
elif gameState[x, y] == 1 and (n_neigh < 2 or n_neigh > 3):
newGameState[x, y] = 0
# Incremento el contador de población:
if gameState[x, y] == 1:
population += 1
# Creación del polígono de cada celda a dibujar
poly = [
(int(x * dimCW), int(y * dimCH)),
(int((x + 1) * dimCW), int(y * dimCH)),
(int((x + 1) * dimCW), int((y + 1) * dimCH)),
(int(x * dimCW), int((y + 1) * dimCH)),
]
if newGameState[x, y] == 0:
# Dibujado de la celda para cada par de x e y:
# screen -> Pantalla donde dibujar
# (128, 128, 128) -> Color a utilizar para dibujar, en este caso un gris
# poly -> Puntos que definan al poligono que se está dibujando
pygame.draw.polygon(screen, (128, 128, 128), poly, 1)
else:
if pauseExec:
# Con el juego pausado pinto de gris las celdas
pygame.draw.polygon(screen, (128, 128, 128), poly, 0)
else:
# Con el juego ejecutándose pinto de blanco las celdas
pygame.draw.polygon(screen, (255, 255, 255), poly, 0)
# Actualizo el título de la ventana
title = f"Juego de la vida - Jonatandb - Población: {population} - Generación: {iteration}"
if pauseExec:
title += " - [PAUSADO]"
pygame.display.set_caption(title)
print(title)
# Actualizo gameState
gameState = np.copy(newGameState)
# Muestro y actualizo los fotogramas en cada iteración del bucle principal
pygame.display.flip()
# Fuerzo a que se renderice como mucho 60 frames por segundo, para no consumir CPU demás
# https://www.pygame.org/docs/ref/time.html#pygame.time.Clock.tick
clock.tick(60)
print("Juego finalizado - [email protected]")