miércoles, 19 de septiembre de 2012

2° Entrega - Autómatas Celulares

Introducción

Definido con nuestras palabras, un autómata celular es un conjunto de elementos que evolucionan mediante reglas o condiciones previamente definidas.
Se utilizan para representar los cambios en un sistema (natural o artificial).


Objetivo

Representar los cambios o generaciones de un conjunto de células (en nuestro caso las llamamos "genes"), implementando todas las reglas de los autómatas celulares (0-255).


Justificación

En un inicio nos interesó el tema de Swarm Intelligence y pensamos en desarrollar un código que simulara el comportamiento de una comunidad de roedores, pero debido al corto tiempo que teníamos, cambiamos de idea y decidimos cambiar a autómatas celulares.

 

Desarrollo

Al tener el tema definido comenzamos a generar una lluvia de ideas entre los integrantes del equipo para tener clara la lógica del programa y nos dimos cuenta que era posible inlcuir todas las reglas y no sólo limitarnos a 4.
Después de mucho pensar, anotar nuestras ideas en la libreta y tener bien clara la idea del algoritmo que se implementaría en el código, empezamos con la codificación, haciendolo paso a paso para no cometer errores.
Convirtiendo cada regla a binario y haciendo un chequeo del conjunto de genes pudimos crear la siguiente generación y cambiando la nueva generación por la anterior pudimos generar las iteraciones deseadas por el equipo.
Nos pareció adecuado dar la opción al usuario de crear genes aleatorios o que él mismo incluyera la cantidad de genes que desee y la posición de cada uno.
Cada vez que se corre el programa se aplican colores diferentes (random) a los genes.
Se uso el lenguaje de programación Python con su libreria Pygame para la interfaz gráfica.

Código

#! usr/bin/python/

# Importamos las librerías necesarias para correr el programa
import pygame
import random

# Declaramos las variables globales que son el alto y el ancho
de la ventana y los valores iniciales de X y Y
ancho = 1360
alto = 710
x = 5
y = 5

# Funcion automata
def automata(regla, i, genesNuevos, genes, opcion):
    if i == 0:
        if opcion != 2:
            for i in range (272):
                generarGenes = random.randint(0, 1)
                if generarGenes == 0:
                    genes[i] = 0
                else:
                    genes[i] = 1

        for i in range (272):
            if genes[i] == 1:
                screen.blit(cuadro, ((x*i) -5, 0))
        print
        print genes
        
    else:
        for i in range (272):
            genes[i] = genesNuevos[i]

    # Aqui se evaluan la ultima y las primeras dos posiciones de la cadena 
    lista1 = genes[i],genes[i-271],genes[i-270]
    cadena1 = "".join(str(x) for x in lista1)
    binario1 = int(cadena1, 2)
    genesNuevos[0] = int(regla[(binario1 + 1) * -1])
    
    # Si la cadena contiene un elemento se coloca el cuadrito en la posicion
    if genesNuevos[0] == 1:
        screen.blit(cuadro, (x*i, y))
        pygame.display.update()

    for i in range (270):
         # Aqui se evaluan todas las posiciones, a excepcion de la primera y la ultima

    # Aqui se evaluan las ultimas dos posiciones y la primera

    print genesNuevos

# Funcion principal
if __name__ == "__main__":
    # Se declaran la cadena de genes por defecto (llena de ceros)

    # Hacemos un pequeño menu para que el usuario eliga entre la opcion de generar una cadena de valores aleatoria o ingresar la cantidad y posicion de genes manualmente
    print "Generar genes de manera aleatoria -> 1"
    print "Agregar genes manualmente         -> 2"
    opcion = input("Opcion: ")
    if opcion == 2:
        opcion2 = input("Cuantos desea agregar? ")
        for i in range (opcion2):
            opcion3 = input("Posicion: ")
            genes[opcion3] = 1
    else:
        for i in range (272):
            generarGenes = random.randint(0, 1)
            if generarGenes == 0:
                genes[i] = 0
            else:
                genes[i] = 1
    
    # El usuario ingresa la regla deseada y si es mayor que 255 o menor que 0 el programa manda un aviso de error y se cierra
    regla = input('Regla: ')
    if (regla > 255) or (regla < 0):
        print 'Solo se pueden reglas de la 0 a la 255'
        exit()
    
    # Convertimos la regla en un numero binario
    print regla
    
    # Creamos la pantalla
    screen = pygame.display.set_mode((ancho, alto))
    pygame.display.set_caption("Automatas celulares")
    
    # Se elige el color de los cuadritos de manera aleatoria (tenemos 8 imagenes, con 8 colores diferentes)
    colores = random.randint(1, 8)
    if colores == 1:
        cuadro = pygame.image.load("1a.png")
    # Aqui van las demas condiciones de los cuadritos
    
    # Se crean las nuevas generaciones    
    for i in range (143):
        automata(regla, i, genesNuevos, genes, opcion)
        pygame.display.update()
        y += 5
    
    # Funcion para cerrar la ventana
    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                exit()

 

Resultados

Tuvimos resultados muy satisfactorios a comparación con las expectativas que teníamos a un inicio. Nuestro código tiene mucho menos líneas que las que hubiera tenido con nuestra idea inicial de implementar sólo 4 reglas.
Regla 99:
 Regla 90:

Video



Conclusiones

Nos pareció excelente el cambio del tema y la solución que le dimos a nuestro programa de autómatas celulares, estamos muy conformes con el resultado.
Aprendimos nuevos métodos en el lenguaje de programación que utilizamos.


Referencias

Autómatas Celulares - Wikipedia
Algunas reglas de los Autómatas Celulares

jueves, 6 de septiembre de 2012

1° Entrega - Semáforos

Introducción

En esta practica se creó la simulación de un semáforo adaptativo, con esto se quiere decir que el semáforo funcionará según sea le situación de cada carril y así se puede regular el flujo de vehículos y evitar el congestionamiento en las calles.

Como lenguaje de programación se uso Python.
Otro dato importante que cabe mencionar es que hicimos uso de la librería Pygame, con la cual se hizo la interfaz gráfica.


Pre-diseño de cruce



En esta practica se creó un sistema que simula algunas calles y avenidas (carriles) muy concurridas en nuestra ciudad, el objetivo fue crear unos semáforos que tuvieran su parte adaptativa, pero, ¿Cómo lograr esto? 


La parte adaptativa se basó primordialmente en lo siguiente: Las calles con más congestionamiento tienen mayor prioridad para poder avanzar y se les proporciona una mayor cantidad de tiempo en Verde, pero por lógica, en algún momento se les permite a los vehículos de las otras calles avanzar.


¿Qué nos puede salir mal?

Algunas de lo complicaciones que pueden presentarse son la mala programación de los semáforos, que por error o alguna mala lógica algunos de los carriles que no pudieran estar en Verde al mismo tiempo, lo estén y causen un colapso.


Diseño de la solución


Condiciones de los Semáforos

El sentido A y el sentido B podrán avanzar siempre y cuando los demás sentidos estén deshabilitados.

El sentido A y el sentido D podrán avanzar siempre y cuando los demás sentidos estén deshabilitados.

El sentido B y el sentido E podrán avanzar siempre y cuando los demás sentidos estén deshabilitados.
Se puede ver que el sentido C puede avanzar siempre y cuando los demás sentidos estén deshabilitados, sucede lo mismo en el sentido F.


Código

#! /usr/bin/python

#Librerias
import pygame
import sys
from threading import Thread
import time
import random

#Variables globales
carrilA = 0
carrilB = 0
carrilC = 0
carrilD = 0
carrilE = 0
carrilF = 0
mayor = 0
SCREEN_WIDTH = 700
SCREEN_HEIGHT = 700

#Clase semaforo que contiene la funcion run (hilo)
class semaforo(Thread):
    def __init__ (self):
        Thread.__init__(self)
        
    def run (self):
        #Modificamos las variables globales
        global carrilA
        
        #Random para asignar los autos entrantes
        entrantes = random.randint(0, 10)
        for i in range(entrantes):
            # Random que asigna el carril para cada auto
            nuevo = random.randint(1, 6)
            if nuevo == 1:
                carrilA += 1           
            elif nuevo == 2:
                carrilB += 1          
            elif nuevo == 3:
                carrilC += 1          
            elif nuevo == 4:
                carrilD += 1          
            elif nuevo == 5:
                carrilE += 1
            else:
                carrilF += 1

        # Esto se repite para cada uno de los carriles
        if carrilA > 0:
            y = 405
            x = 180
            for i in range (carrilA):
                screen.blit(carroA, (x, y))
                x -= 50
        
        #Imprimir los valores en la terminal
        lista = [carrilA, carrilB, carrilC, carrilD, carrilE, carrilF]
        mayor = max(lista)
        print "(/*-*)/ <<====CARRILES====>> \(^-^\)"
        print "A      B      C      D      E      F"
        print carrilA,'    ',carrilB,'    ',carrilC,'    ',carrilD,'    ',carrilE,'    ',carrilF

#Funcion principal (main)
if __name__ == '__main__':
    
    pygame.init()
    #Se cargan la pantalla y las imagenes
    screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
    pygame.display.set_caption("Semaforos :D")
    fondo = pygame.image.load("callefinal2.png")
    carroA = pygame.image.load("carA2.png").convert_alpha()
    SADrojo = pygame.image.load("SADrojo.png").convert_alpha()

    #Bucle infinito
    while True:
        screen.blit(fondo, (0, 0))
        for event in pygame.event.get():
            if event.type ==pygame.QUIT:
                sys.exit()

        screen.blit(SADrojo, (225, 350))
        
        #Se declara la clase semaforo como hilo y se inicia
        hilo = semaforo()
        hilo.start()
        time.sleep(3)
        print        
        pygame.display.flip()

        #Se compara la cantidad de autos en cada carril para eliminarlos 
        #y se agregan las imagenes de los semaforos, igualmente este if 
        #se repite para los demas carriles
        if ((carrilA >= carrilC) and (carrilA >= carrilD) and (carrilA >= carrilE) and (carrilA >= carrilF)) or ((carrilB >= carrilC) and (carrilB >= carrilD) and (carrilB >= carrilE) and (carrilB >= carrilF)):
            print "Semaforos A y B encendidos"
            if (carrilA >= carrilB):
                for i in range (carrilA):
                    if carrilA > 0:
                        carrilA -= 1
                    if carrilB > 0:
                        carrilB -= 1
                   # Aqui se agregan las imagenes de los semaforos
            
            else:         
                for i in range (carrilB):
                    if carrilA > 0:
                        carrilA -= 1
                    if carrilB > 0:
                        carrilB -= 1
            print
            time.sleep(1)
                    



Video


Conclusiones

Una de las experiencias que tuvimos al momento de realizar el código para nuestro semáforo, fue que nos daba el valor mayor de vehículos en cierto carril, pero al momento de desalojar esa cantidad de vehículos, la desalojaba de un carril distinto, nuestro error fue al momento de declarar los “if” ya que poníamos todas las condiciones seguidas "if (carrilA >= carrilC and carrilB and carrilD and carrilE and carrilF)", al momento de ejecutar el programa, se generaban otros valores con esa instrucción, nuestra solución fue hacer comparaciones individuales.

Alguna mejora que podríamos hacer en nuestro proyecto , sería que los carros tuvieran movimiento, ya que en nuestra interfaz gráfica, solo se van agregando o eliminando vehículos, pero no presentan movimiento, aprendimos a analizar el algoritmo que se presentaba, y el auto-ajuste de parámetros que es el tiempo que dura el semáforo, dependiendo de la cantidad de autos que estuvieran en espera, el monitoreo de variables que vendría siendo la cantidad de carros que pasan, y a simular un sistema inteligente.


Referencias

Threads en Python
Más sobre hilos en Python... 
Ejemplo de hilo simple en Python 
Crear ventanas y cargar imagenes