Programación de autómatas celulares en Python (I): El juego de la vida de Conway
19
julio
2021

En este artículo trato la implementación de un segundo autómata celular muy celebre en la comunidad llamado “El mundo alámbrico” ( Wireworld ). Explico la fundamentación del AC y su implementación en Python a partir del código del proyecto del juego de la vida de Conway.

Visita el artículo anterior de la serie si aún no los has leído: Programando autómatas celulares en Python: El juego de la vida de Conway

Fundamento

El mundo alámbrico ( wireworld ) es un autómata celular creado en 1.987 por el ingeniero informático canadiense Brian Silverman. Este autómata permite simular el funcionamiento de circuitos digitales mostrando el desplazamiento de los electrones a través de pistas conductoras.

Programando autómatas celulares Python wireworld 1

Multiplicador binario de 8 bits creado en 2002 por Nick Gardner

Al igual que El juego de la vida de Conway, este AC emplea en una serie de reglas simples que se aplican sobre las celdas que integran el espacio de simulación. Sus características descriptivas son las siguientes:

  • Espacio -> Un mosaico 2D de celdas cada una de las cuales puede tener uno de los siguientes estados:
  • Conjunto de estados -> Cada celda puede tener uno de los siguientes estados:
    • AISLANTE -> La celda es vacía (celda negra)
    • CONDUCTOR -> La celda representa un parte de un hilo conductor (celda azul)
    • ELECTRON -> La celda representa un electrón (celda amarilla)
    • COLA ELECTRON -> La celda representa el punto por el que un electrón acaba de pasar (celda roja)

Programando autómatas celulares Python wireworld 2

Puerta lógica AND

  • Regla de vecindad -> Emplea el patrón de vecindad de Moore de radio 1 según el cual se consideran vecinas las 8 celdas contiguas a cada una:

Programando autómatas celulares Python wireworld 3

Celdas vecinas según vecindad de Moore r =1

  • Reglas de transición -> Las reglas de transición son las siguientes y se aplican por cada celda para obtener su próximo estado según su estado actual y el de sus celdas vecinas:
Estado anterior Estado posterior
Aislante Aislante
Conductor Si uno o dos vecinos son electrones:

·         Electrón

Sino

·         Conductor

Electrón Cola Electrón
Cola Electrón Conductor

Patrones de inicio

Este AC permite crear diseños capaces de simular el funcionamiento circuitos digitales básicos tales como puertas lógicas AND, OR, XOR…, etc. Estas pueden componerse a su vez para diseñar circuitos digitales más complejos, tales como sumadores, memorias, flip-flops…, etc.

Los siguientes son los diseños de las puertas lógicas básicas AND, OR y XOR.

Puerta lógica XOR (disyunción excluyente)

Programando autómatas celulares Python wireworld 4

Puerta lógica OR (disyunción no excluyente)

Programando autómatas celulares Python wireworld 5

Puerta lógica AND (conjunción)

Programando autómatas celulares Python wireworld 6

Implementación empleando Python

Existen implementaciones del mundo alámbrico disponibles online:

https://xalava.github.io/WireWorld/

Programando autómatas celulares Python wireworld 7

A continuación vamos a abordar la implementación de este autómata celular con Python y la librería PyGame. Para ello vamos a basarnos en el proyecto de implementación del Juego de la Vida de Conway visto en el anterior artículo.

Si estás interesado en aprender a desarrollar videojuegos, visita nuestros cursos de videojuegos

Implementación del Autómata Celular

Lo primero es definir la clase que represente el propio autómata celular e implemente su funcionamiento. La llamaremos Wireworld y la crearemos en el fichero “wireworld.py”:

La clase debe constar de los siguientes atributos:

Programando autómatas celulares Python wireworld 8

Las constantes WIDTH, HEIGHT determinan el nº de celdas de ancho y alto del espacio del autómata. Las constantes HEAD, TAIL, CONNECTOR y NONE determinan los valores asociados a los estados de cada celda. Finalmente, las listas internas __world y __next representan respectivamente el espacio principal del autómata celular y el espacio de respaldo empleado durante el proceso de actualización para almacenar el siguiente estado de cada celda tras aplicar las reglas de transición.

Añadimos el constructor y el método reset(). El constructor no recibe ningún parámetro e invoca únicamente el método reset(). Este es responsable de inicializar las listas que conforman el espacio principal (__world) y del de respaldo (__next). Ambas listas contienen inicialmente valores 0 indicando que todas las celdas son AISLANTES.

Programando autómatas celulares Python wireworld 9

Las propiedades iterations y electrons devuelven respectivamente el nº de actualizaciones ejecutadas (también llamadas iteraciones), y el nº de electrones presentes en el circuito:

Programando autómatas celulares Python wireworld 10

Los método read() y write() que permiten obtener y modificar el estado de una celda dadas sus coordenadas X e Y en el espacio del AC:

Programando autómatas celulares Python wireworld 11

El método update() actualiza el estado de cada celda en el espacio del autómata celular. Para ello se toma el estado de cada del espacio principal (__world), se aplican las reglas de transición en función de su estado y el de las celdas vecinas, y se almacena el estado resultante en la misma posición del espacio de respaldo (__next). Una vez procesadas todas las celdas, se vuelca el contenido de la lista de respaldo a la principal actualizando así el espacio del AC definitivamente.

El código del método es el siguiente:

Programando autómatas celulares Python wireworld 12

El método draw() proyecta el espacio del AC en un objeto superficie pygame.Surface donde cada celda se muestran como un rectángulo de 10 x 10 píxeles según posición en el espacio del AC:

Programando autómatas celulares Python wireworld 13

Según cual sea el estado de la celda, esta se proyecta de distinto modo:

  • Si estado es CONDUCTOR ( CONNECTOR ) -> Rectángulo relleno de color azul.
  • Si estado es ELECTRON ( HEAD ) -> Rectángulo relleno de color amarillo.
  • Si estado es COLA ELECTRON ( TAIL ) -> Rectángulo relleno de color rojo.
  • Si estado es AISLANTE ( NONE ) -> Rectángulo vacío con bordes grises.

Los métodos save() y load() permitan salvar y recuperar el espacio del autómata en un fichero de texto. Ambos métodos reciben como argumento una cadena con la ruta y nombre al archivo.

Programando autómatas celulares Python wireworld 14

El método save() guarda los valores de la lista __world en el archivo indicado como argumento. Los valores se inscriben en el archivo separados por comas y entre corchetes:

[ 0,0,1,0,0,0,2,0,2,0,0,0,1,0,0,0,0 …. ]

El método load() recupera los valores de la lista __world a partir de lo contenido del fichero en la ruta indicada como argumento.

Si estás interesado en aprender a programar en Python, visita nuestro curso de python

Implementación del interfaz de usuario con PyGame

Una vez completada la clase que implementa el autómata celular pasamos a preparar la interfaz de usuario en el módulo “main.py”. Para ello vamos a reaprovechar el código del anterior proyecto, pero incluyendo algunas mejoras:

La ventana a mostrar constará del siguiente aspecto:

Programando autómatas celulares Python wireworld 15

Aspecto del interfaz de usuario vacío.

La ventana tiene el tamaño original de 1000 x 564 píxeles dividida en dos partes:

  • El área superior de visualización del espacio del autómata.
  • El área inferior de controles donde se muestran los iconos que nos permitirán iniciar, parar y reiniciar el autómata celular, y cargar y guardar su diseño. A la izquierda se muestra el estado del autómata (PAUSE, RUNNING), y a la derecha el nº de iteraciones y el nº de electrones presentes en cada momento.

Edición de circuitos.

El usuario puede crear cualquier circuito e indicar la posición de los electrones con el ratón empleando las siguientes reglas:

  • Haciendo clic con el botón izquierdo sobre una celda:
    • Si la celda es Aislante -> Se ajusta como Conductor.
    • Si la celda es Conductor -> Se ajusta como Electrón.
    • Si la celda es Electrón -> Se ajusta como Conductor
    • Si la celda es Cola de Electrón -> Se ajusta como Conductor.
  • Haciendo clic con el botón derecho una celda pasa a ser Aislante sea cual sea su estado.

Clases auxiliares Button y Text

Para simplificar la implementación del main() vamos a definir una clases auxiliares para controlar los textos y los botones de la parte inferior. Estas clases las definimos en el fichero: “guihelper.py” y son las siguientes:

Clase Button: Representa una imagen y el área que ocupa en la ventana:

Programando autómatas celulares Python wireworld 16

Clase Text: Representa un texto incluyendo su fuente, tamaño, posición, color y contenido.

Programando autómatas celulares Python wireworld 17

Implementación del módulo principal

El fichero principal “main.py” incluye código del proyecto anterior distinguiéndose en la importación de la clase Wireworld del módulo wireworld.py:

Programando autómatas celulares Python wireworld 18

Inicialización

La función principal main() inicializa primero todos los elementos:

  • Ventana principal
  • Objeto autómata (world)
  • Objetos botón (inicio, parada, limpieza, cargado y guardado)
  • Objetos textos (estado, iteraciones y electrones)
  • Variable de estado running (false). El autómata está inicialmente detenido.

Programando autómatas celulares Python wireworld 19

Si estás interesado en aprender a programar en Python, visita nuestro curso de python

Bucle principal -> Captura de eventos

A continuación, el bucle principal captura los eventos del sistema y de usuario:

  • QUIT -> Cerrado de ventana
  • MOUSEBUTTONDOWN -> Pulsación de ratón

Para comprobar la pulsación sobre cada uno de los iconos mostrados en la parte inferior de la ventana se emplean sus métodos is_clicked() pasando como argumentos las coordenadas del puntero del ratón.

Para editar el espacio del AC se emplea la función auxiliar mouse_click(). Esta función es llamada desde el main() al detectarse la pulsación del ratón sobre el espacio del autómata celular (coordenada y < 500 ). El método recibe como argumentos las coordenadas X e Y (mouse_x, mouse_y) del cursor del ratón y un indicador del botón pulsado (button).

Programando autómatas celulares Python wireworld 20

Programando autómatas celulares Python wireworld 21

El método auxiliar mouse_click() obtiene el estado de la celda señalada por el cursor y le asigna el nuevo estado empleando los métodos read() y write() del objeto world que representa el AC:

Programando autómatas celulares Python wireworld 22

Bucle principal -> Actualización de AC

Tras la captura de eventos, viene el código de ejecución del autómata celular y la actualización de los textos mostrando el estado y el nº de iteraciones y electrones presentes mediante su propiedad text. Para ello se invoca al método update() del objeto world si la variable running es TRUE indicando que el autómata se está ejecutando:

Programando autómatas celulares Python wireworld 23

Bucle principal -> Refresco de pantalla

Por último, se incluye el código de repintado de la ventana que incluye la proyección del espacio actualizado del AC, y los botones y textos de la parte inferior.

Programando autómatas celulares Python wireworld 24

Modo de uso.

Al iniciar la aplicación se muestra el AC con todas las celdas inactivas y en estado parado, por lo que podemos activar las celdas que deseemos para crear una configuración inicial:

Programando autómatas celulares Python wireworld 25

Espacio del AC representando los circuitos de las puertas lógicas XOR, OR y AND.

Inicio del AC

A continuación podemos poner en marcha el AC pulsando sobre el icono PLAY Programando autómatas celulares en Python: El juego de la vida de Conway 25. Se muestra entonces el estado “RUNNING” y El AC muestra la evolución del estado de las celdas al tiempo que se van mostrando el nº de iteraciones y el nº de celdas activas presentes.

Parada del AC

Para detener el AC pulsamos el icono Programando autómatas celulares en Python: El juego de la vida de Conway 26

Se muestra entonces nuevamente el estado “PAUSE”:

Programando autómatas celulares Python wireworld 26

Espacio del AC representando los circuitos de las puertas lógicas XOR, OR y AND en electrones en pausa.

Reinicio del AC

Por último, podemos limpiar el AC desactivando el estado de todas las celdas y poniendo el contador de iteraciones nuevamente a 0. Para ello pulsamos el icono: Programando autómatas celulares en Python: El juego de la vida de Conway 27

Carga y guardado de circuitos

  • El icono Programando autómatas celulares Python wireworld 27 permite guardar el patrón actual en el fichero indicado en el cuadro de diálogo que se muestra después.
  • El icono Programando autómatas celulares Python wireworld 28 permite cargar el patrón guardado previamente en el fichero indicado mediante el cuadro de diálogo mostrado después.

Si estás interesado en aprender a desarrollar videojuegos, visita nuestros cursos de videojuegos

Author

Ángel Aguinaga

Profesor de Programación y Bases de Datos de la Sede Bilbao. Formador experimentado en áreas como .Net, Java, BB.DD., Python, Desarrollo y programación Web.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Recibe de primero nuestras ofertas de empleo y noticias