Skip to content

Instantly share code, notes, and snippets.

@astrojuanlu
Created November 6, 2012 16:40
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save astrojuanlu/4025886 to your computer and use it in GitHub Desktop.
Save astrojuanlu/4025886 to your computer and use it in GitHub Desktop.
Juego de la vida de Conway en Python
# coding: utf-8
"""Juego de la vida de Conway.
Autor: Juan Luis Cano <juanlu001@gmail.com>
El tablero es un array de NumPy, donde 0 significa célula muerta y 1 célula
viva. Se muestra una animación con matplotlib.
"""
from time import sleep
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm
from matplotlib import animation
def vecindario(b):
"""Array de células vivas en el vecindario."""
vecindario = (
np.roll(np.roll(b, 1, 1), 1, 0) + # Abajo-derecha
np.roll(b, 1, 0) + # Abajo
np.roll(np.roll(b, -1, 1), 1, 0) + # Abajo-izquierda
np.roll(b, -1, 1) + # Izquierda
np.roll(np.roll(b, -1, 1), -1, 0) + # Arriba-izquierda
np.roll(b, -1, 0) + # Arriba
np.roll(np.roll(b, 1, 1), -1, 0) + # Arriba-derecha
np.roll(b, 1, 1) # Derecha
)
return vecindario
def paso(b):
"""Paso en el juego de la vida de Conway."""
v = vecindario(b)
buffer_b = b.copy() # Hacemos una copia de la matriz
for i in range(buffer_b.shape[0]):
for j in range(buffer_b.shape[1]):
if v[i, j] == 3 or (v[i, j] == 2 and buffer_b[i, j]):
buffer_b[i, j] = 1
else:
buffer_b[i, j] = 0
return buffer_b
# Parámetros del problema
GENERACIONES = 50
N = 8
M = 8
# Construimos el tablero
tablero = np.zeros((N, M), dtype=int)
# Añadimos una nave
tablero[1, 1:4] = 1
tablero[2, 1] = 1
tablero[3, 2] = 1
# Creamos la figura
fig = plt.figure(figsize=(4, 4))
ax = fig.add_subplot(111)
ax.axis('off')
b = tablero
imagen = ax.imshow(b, interpolation="none", cmap=cm.gray_r)
def animate(i):
global b
b = paso(b)
imagen.set_data(b)
anim = animation.FuncAnimation(fig, animate, frames=GENERACIONES, blit=True)
anim.save('juego_vida.mp4', fps=10)
@Byhako
Copy link

Byhako commented Nov 3, 2017

RuntimeError: The animation function must return a sequence of Artist objects.

@pnmartinez
Copy link

pnmartinez commented Mar 1, 2019

RuntimeError: The animation function must return a sequence of Artist objects.

Fixed it!

And went on working on it. I reformated the whole thing according to my taste, and added a play/pause button as well as a randomizer.

Also: some of the documentation is in spanish, as I it is my main language too.

Enhorabuena por la compacidad del script Juan Luis!

# coding: utf-8

"""Juego de la vida de Conway.

Autor: - Juan Luis Cano <juanlu001@gmail.com>
       - Pausa y randomizado de C.I: Pablo Navarro Martínez <pablonavaber@hotmail.com>

El tablero es un array de NumPy, donde 0 significa célula muerta y 1 célula
viva. Se muestra una animación con matplotlib.

"""

from time import sleep

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm
from matplotlib import animation

import random
from matplotlib.widgets import Button

def vecindario(b):
    """Array de células vivas en el vecindario."""
    vecindario = (
        np.roll(np.roll(b, 1, 1), 1, 0) +  # Abajo-derecha
        np.roll(b, 1, 0) +  # Abajo
        np.roll(np.roll(b, -1, 1), 1, 0) +  # Abajo-izquierda
        np.roll(b, -1, 1) +  # Izquierda
        np.roll(np.roll(b, -1, 1), -1, 0) +  # Arriba-izquierda
        np.roll(b, -1, 0) +  # Arriba
        np.roll(np.roll(b, 1, 1), -1, 0) +  # Arriba-derecha
        np.roll(b, 1, 1)  # Derecha
    )
    return vecindario


def paso(b):
    """Paso en el juego de la vida de Conway."""
    v = vecindario(b)
    buffer_b = b.copy()  # Hacemos una copia de la matriz
    for i in range(buffer_b.shape[0]):
        for j in range(buffer_b.shape[1]):
            if v[i, j] == 3 or (v[i, j] == 2 and buffer_b[i, j]):
                buffer_b[i, j] = 1
            else:
                buffer_b[i, j] = 0
    return buffer_b


# Parámetros del problema
GENERACIONES = 100
N = 16 # Dimensiones del tablero (N, M)
M = N

pause = True # Pausa

def onClick(event):
    global pause
    pause ^= True

# Construimos el tablero
tablero = np.zeros((N, M), dtype = int)

# CONDICIONES INICIALES (CASILLAS ENCENDIDAS)
#   Añadimos una nave 
tablero[1, 1:4] = 1
tablero[2, 1] = 1
tablero[3, 2] = 1

def randomize(event):
    for i in range(0, N-1):
        for j in range(0, N-1):
            tablero[i, j] = random.randint(0, 1)
    global b
    b = tablero
    imagen.set_data(b)
    print(tablero)

# Creamos la figura, formateo diverso
fig = plt.figure(figsize=(4, 4))
ax = fig.add_subplot(111)
# ax.axis('off')
b = tablero 
imagen = ax.imshow(b, interpolation="none", aspect = "equal", cmap=cm.gray_r)

# Major ticks
# ax.set_xticks(np.arange(0, N, 1));
ax.set_yticks(np.arange(0, N, 1));

# Labels for major ticks
# ax.set_xticklabels(np.arange(1, N+1, 1));
ax.set_yticklabels(np.arange(1, N+1, 1));

# Minor ticks
# ax.set_xticks(np.arange(-.5, N, 1), minor=True);
# ax.set_yticks(np.arange(-.5, N, 1), minor=True);

plt.tick_params(    
    axis='x',          # changes apply to the x-axis
    which='both',      # both major and minor ticks are affected
    bottom=False,      # ticks along the bottom edge are off
    top=False,         # ticks along the top edge are off
    labelbottom=False) # labels along the bottom edge are off

def animate(i):
    global b

    if not pause: # Pause check
        print(i) # El parámetro de avance: la pausa no le afecta
        b = paso(b) # Iteramos la animación
        
        imagen.set_data(b)
    
    return imagen,

# Botones play/pausa, randomizar
# fig.canvas.mpl_connect('button_press_event', onClick) # Si queremos conectar el click puse a la figura entera
pause_ax = fig.add_axes((0.3, 0.025, 0.23, 0.04), anchor = 'SE')
pause_button = Button(pause_ax, 'Play/pause', hovercolor='0.975')
pause_button.on_clicked(onClick)

random_ax = fig.add_axes((0.6, 0.025, 0.3, 0.04), anchor = 'SW')
random_button = Button(random_ax, 'Randomize I. C.', hovercolor='0.975')
random_button.on_clicked(randomize)

# Animacion 
anim = animation.FuncAnimation(fig, animate, frames=GENERACIONES, blit=True, interval = 200, repeat = True)
plt.show()

@astrojuanlu
Copy link
Author

Acabo de ver tu comentario, gracias @pnmartinez !

@Shanathory
Copy link

@astrojuanlu Gracias por el aporte!

@Shanathory
Copy link

RuntimeError: la función de animación debe devolver una secuencia de objetos Artist.

**¡Arreglado! **

Y siguió trabajando en ello. Reformateé todo según mi gusto y agregué un **botón de reproducción / pausa **, así como un **aleatorizador **.

Además: parte de la documentación está en español, ya que yo también es mi idioma principal.

Enhorabuena por la compacidad del script Juan Luis!

# coding: utf-8

"""Juego de la vida de Conway.

Autor: - Juan Luis Cano <juanlu001@gmail.com>
       - Pausa y randomizado de C.I: Pablo Navarro Martínez <pablonavaber@hotmail.com>

El tablero es un array de NumPy, donde 0 significa célula muerta y 1 célula
viva. Se muestra una animación con matplotlib.

"""

from time import sleep

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm
from matplotlib import animation

import random
from matplotlib.widgets import Button

def vecindario(b):
    """Array de células vivas en el vecindario."""
    vecindario = (
        np.roll(np.roll(b, 1, 1), 1, 0) +  # Abajo-derecha
        np.roll(b, 1, 0) +  # Abajo
        np.roll(np.roll(b, -1, 1), 1, 0) +  # Abajo-izquierda
        np.roll(b, -1, 1) +  # Izquierda
        np.roll(np.roll(b, -1, 1), -1, 0) +  # Arriba-izquierda
        np.roll(b, -1, 0) +  # Arriba
        np.roll(np.roll(b, 1, 1), -1, 0) +  # Arriba-derecha
        np.roll(b, 1, 1)  # Derecha
    )
    return vecindario


def paso(b):
    """Paso en el juego de la vida de Conway."""
    v = vecindario(b)
    buffer_b = b.copy()  # Hacemos una copia de la matriz
    for i in range(buffer_b.shape[0]):
        for j in range(buffer_b.shape[1]):
            if v[i, j] == 3 or (v[i, j] == 2 and buffer_b[i, j]):
                buffer_b[i, j] = 1
            else:
                buffer_b[i, j] = 0
    return buffer_b


# Parámetros del problema
GENERACIONES = 100
N = 16 # Dimensiones del tablero (N, M)
M = N

pause = True # Pausa

def onClick(event):
    global pause
    pause ^= True

# Construimos el tablero
tablero = np.zeros((N, M), dtype = int)

# CONDICIONES INICIALES (CASILLAS ENCENDIDAS)
#   Añadimos una nave 
tablero[1, 1:4] = 1
tablero[2, 1] = 1
tablero[3, 2] = 1

def randomize(event):
    for i in range(0, N-1):
        for j in range(0, N-1):
            tablero[i, j] = random.randint(0, 1)
    global b
    b = tablero
    imagen.set_data(b)
    print(tablero)

# Creamos la figura, formateo diverso
fig = plt.figure(figsize=(4, 4))
ax = fig.add_subplot(111)
# ax.axis('off')
b = tablero 
imagen = ax.imshow(b, interpolation="none", aspect = "equal", cmap=cm.gray_r)

# Major ticks
# ax.set_xticks(np.arange(0, N, 1));
ax.set_yticks(np.arange(0, N, 1));

# Labels for major ticks
# ax.set_xticklabels(np.arange(1, N+1, 1));
ax.set_yticklabels(np.arange(1, N+1, 1));

# Minor ticks
# ax.set_xticks(np.arange(-.5, N, 1), minor=True);
# ax.set_yticks(np.arange(-.5, N, 1), minor=True);

plt.tick_params(    
    axis='x',          # changes apply to the x-axis
    which='both',      # both major and minor ticks are affected
    bottom=False,      # ticks along the bottom edge are off
    top=False,         # ticks along the top edge are off
    labelbottom=False) # labels along the bottom edge are off

def animate(i):
    global b

    if not pause: # Pause check
        print(i) # El parámetro de avance: la pausa no le afecta
        b = paso(b) # Iteramos la animación
        
        imagen.set_data(b)
    
    return imagen,

# Botones play/pausa, randomizar
# fig.canvas.mpl_connect('button_press_event', onClick) # Si queremos conectar el click puse a la figura entera
pause_ax = fig.add_axes((0.3, 0.025, 0.23, 0.04), anchor = 'SE')
pause_button = Button(pause_ax, 'Play/pause', hovercolor='0.975')
pause_button.on_clicked(onClick)

random_ax = fig.add_axes((0.6, 0.025, 0.3, 0.04), anchor = 'SW')
random_button = Button(random_ax, 'Randomize I. C.', hovercolor='0.975')
random_button.on_clicked(randomize)

# Animacion 
anim = animation.FuncAnimation(fig, animate, frames=GENERACIONES, blit=True, interval = 200, repeat = True)
plt.show()

@pnmartinez gracias por la correción

@astrojuanlu
Copy link
Author

Uf, 9 años hace de este script nada menos :) ¡me alegro de que siga siendo útil!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment