Re: [Python-es] Programación OO. Un ejemplo con a scensores

Antonio Castro acastro en ciberdroide.com
Mie Dic 1 18:15:33 CET 2004


On Wed, 1 Dec 2004, Joaquin Jose del Cerro Murciano wrote:

En tu primera parte del mensaje me has captado perfectamente lo que
quería decir.

>
> > En mi opiníon, sería chulo terminar con un interfaz gráfico que permita
> > hacer simulaciones y comprobar el funcionamiento de la parte algorítimica,
> > pero eso ya es para nota. En realidad ni siquiera se trata de completar
>
> Suena muy bien lo que dices. Creeis que seria posible desarrollar un poco mas
> ese tema aqui en la lista.Vendria muy bien disponer en python de herramientas
> para hacer cosas de esas.
> - Cuando comentas lo de "terminar con un interface grafico" estas hablando
>    de un modelodar de clases ?
>    A lo mejor podemos contribuir si tienes algo. Y si no tienes y ayudas con
>    la definicion igual nos podria interesar meternos en ello.
> - Cuando hablas de "hacer simulaciones y comprobar el funcionamiento de
>    la parte algorítimica" por donde van tus ideas ?
>
> Si te interesa pordemos ver si se puede colaborar para hacer algo.

;-) Hay formas muy distintas de enfocar el problema. Se trata en principio
de un ejercicio puramente tehorico pero basado en un caso real.

Los ascensores inteligentes muchas veces parecen tontos y esa es la única
razón por la que me interesa este caso.

En cuanto a lo del interfaz gráfico es una idea ambiciosilla.

Yo imagino una representación de un edificio con varias plantas y
varios ascensores y que pulsando con el raton en un pulsador de un
ascensor o en un pulsador de una planta se pueda llamar al ascensor.
Que simule la entrada y salida de gente, y que con todo ello se pueda
emular el comportamiento de un algoritmo.

Si yo lo intentara, lo haría quizás en Tkinter que es lo que conozco.
Lo del interfaz me temo que tenga mucho curro para ser un programita de
propósito educativo pero es bueno cuando se sugiere un ejercicio, plantearlo
como algo que podría llegar a ser algo más que eso. En este caso un
emulador.

Yo para este ejercicio no considero importante implementar ningún
algoritmo concreto.

Lo que si considero esencial para el ejercicio es implementar aunque
sea a modo de meros esbozos todos los objetos posibles y me he puesto
a ello.

Me acabo de dar cuenta de una complicación. Se trata de un problema
en el cual existirá un bucle de eventos. (Gente pulsando potones) y
una serie de ascensores funcionando de forma bastante autónoma. Es
decir tenemos un claro caso de threading. ;-)

Esto ocurre cuando los objetos con los que trabajamos actuan como
si tuvieran vida propia lo cual los hace siempre mucho más interesantes.

De hecho me puse a teclear en cuanto me di cuenta de esto y tengo que
decir que tal conclusion sale de forma natural cuando se emplieza a
analizar el problema orientandolo a objetos. No es necesario tener
esa idea preconcebida. Surge como resultado de ir refinando el diseño
de los objetos.

Yo llevo menos de un año con Python y ni el diseño será perfecto ni
la codificación tampoco pero es un punto de partida.

Lo que siento es que lo dejo a medias y ni siquiera está pensado para
mostrar una traza interesante, pero no debería faltar mucho para eso.

Ya le daré un empujón otro día y si alguien quiere aportar ideas en
la forma que sea pues estupendo.

==================8<-----------------------------------------------

#!/usr/bin/python
# -*- coding: latin1 -*-
# ascensores.py

#-------------------------------------------------------------------
class Boton:
    '''
    Botón con memoria y luz de estado.
    Objeto muy simple.
    '''
    def __init__(self):
        self.PulsadoSN=0 # Luz de estado, 0=No pulsado; 1=Pulsado

    def Pulsar(self):
        self.PulsadoSN=1

    def Olvidar(self):
        '''
        Cuando ya no interese conservar el estado
        '''
        self.PulsadoSN=0

#-------------------------------------------------------------------
class Botonera:
    '''
    Botonera genérica
    '''
    def __init__(self, ListaIdentBotones):
        self.Botonera={}
        for B in ListaIdentBotones:
            self.Botonera[B]=Boton()

    def PulsarBoton(self, B):
        self.Botonera[B].Pulsar()

    def OlvidarBoton(self, B):
        self.Botonera[B].Olvidar()

#-------------------------------------------------------------------
class Ascensor:
    '''
    Ascensor inteligente.
    '''
    def __init__(self, CargaMaxima, PlantaInferior, PlantaSuperior):
        self.EnServicio=1 # 0= Fuera de servicio; 1 En Servicio
        self.CargaMaxima=CargaMaxima
        self.PlantaInferior=PlantaInferior
        self.PlantaSuperior=PlantaSuperior
        # Botonera
        Botones=range(self.PlantaInferior, self.PlantaSuperior+1)
        Botones.append('Stop')
        Botones.append('Alarm')
        self.Botonera=Botonera(Botones)
        self.Puerta=Puerta()
        self.SensorDeCarga=0 # Kg de carga
        self.SensorDePuerta=0 # 0=PasoLibre; 1=PasoOcupado
        self.Motor='P' # P=Parado; B=Bajando; S=Subiendo
        # La ruta indica cual es la ruta asignada al ascensor en este instante
        self.Ruta='P' # P=Parado; B=Bajando; S=Subiendo
        self.SituPlanta=0.0 # 0.0= Planta baja
        self.IncrPos=0.5 # Se consideran los cambios de posicion en incrementos
        self.Delay=0.5 # Tiempo en segundos para cambiar de posicion.

    def GetInfo(self):
        '''
        Retorna la información que interesa a los usuarios que
        esperan por un ascensor.
        '''
        return self.SituPlanta, self.Ruta, self.Puerta.EstadoCierre

    def GetAccionPuertaExt(self, Planta):
        '''
        Dice a una puerta externa lo que tiene que hacer
        '''
        pass # Por implementar

    def Algoritmo(self):
        '''
        Obtiene la orden siguiente para este ascensor.
        Este algoritmo debe funcionar dentro de una región critica para
        evitar problemas de concurrencia.

        * Un ascensor con gente dentro no debe invertir el sentido de su
        marcha hasta que la última persona alcance su destino.

        * Las ordenes recibidas desde el interior desaparecen cuando el
        ascensor (0 Kg) queda vació.

        * Si todos los ascensores están desocupados el más cercano a la planta
        baja debe bajar a esa planta para quedar a la espera de pasageros.

        * Un ascensor con gente dentro no atenderá más ordén externa que la de
        incluir en su memoria una nueva parada que coincida con el sentido de
        la marcha.

        * Cualquier ascensor que pare en una planta elimina la orden pendiente
        si coincide con el sentido de la marcha.

        * Realizada una petición de ascensor, será ajudicada al ascensor más
        favorable. Este será el que esté mas cerca pero en caso de estar parado
        se considerará como si estuviera tres plantas más lejos que un ascensor
        que se acerca en la dirección correcta. El ascensor que viene en la
        dirección correcta será penalizado con una distancia equivalente a
        media planta por cada parada pendiente en su recorrido hasta llegar a
        la planta solicitada.

        * Un ascensor que le falte menos de 70 kilos para alcanzar su limite
        de carga no acepta nuevas peticiones externas.
        '''
        pass # Todo por hacer

    def run(self):
        '''
        Dar vida al ascensor.
        '''
        import time

        while 1:
            # Entrar en la región crítica
            # Aplicar algoritmo
            # Sacar la mejor orden para este ascensor de la lista de ordenes
            # Salir de la región crítica
            # Procesar la orden
            time.sleep(self.Delay)

#-------------------------------------------------------------------
class Puerta:
    '''
    Objeto muy simple
    '''
    def __init__(self):
        self.EstadoCierre=0 # 0=Cerrada; 1=Abierta
        self.Bloqueada=0 # 0=No bloqueada; 1 bloqueada

    def Abrir(self):
        self.PuertaInterior=1

    def Cerrar(self):
        self.PuertaInterior=0

    def Bloquear(self):
        self.Bloqueada=1

#-------------------------------------------------------------------
class Display:
    def __init__(self, ascensor):
        '''
        Muestra en todo momento la informacion relativa a un ascensor.
        '''
        def __init__(self):
            self.ascensor=ascensor
            self.delay=1

        def run(self):
            '''
            Dar vida al display
            '''
            import time

            while 1:
                self.ascensor.GetInfo()
                time.sleep(self.delay)


#-------------------------------------------------------------------
class PuertaExterna:

    def __init__(self, ascensor):
        '''
        '''
        self.ascensor=ascensor
        self.puerta=Puerta()

    def run(self, Planta):
        '''
        Dar vida al display
        '''
        import time

        while 1:
            self.ascensor.GetAccionPuertaExt(Planta)
            time.sleep(self.delay)

#-------------------------------------------------------------------
class Planta:
    '''
    Cada planta tiene una dotación comun y una que depende del número
    de ascencores.
    '''

    def __init__(self, ListaDeAscensores, NumPlanta):
        import threadind

        self.NumPlanta=NumPlanta
        self.Botonera=Botonera(['Subir', 'Bajar'])
        self.Display=[]
        self.Puerta=[]
        for I in ListaDeAscensores:
            displ=Display(I)
            threading.Thread(target=displ.run)
            self.Display.append(displ)
            puerta=PuertaExterna(I)
            threading.Thread(target=puerta.run)
            self.Puerta.append(puerta)

    def PedirSubir(self):
        self.Botonera['Subir'].Pulsar()

    def PedirBajar(self):
        self.Botonera['Bajar'].Pulsar()

#-------------------------------------------------------------------
class Orden:
    def __init__(self, MayorOrig, MinorOrig, PlantaDestino):
        '''
        El MayorOrig' indica si la orden proviene de un ascensor '0' o de una
        planta, '1', o de centralita '2' y el MinorOrig de que ascensor o de
        que planta. Si viene de la centralita el MinorOrig siempre
        será 0 porque hay una sola centralita.
        Objeto muy simple.
        '''
        self.MayorOrig=MayorOrig
        self.MinorOrig=MinorOrig
        self.PlantaDestino=PlantaDestino


#-------------------------------------------------------------------
class Edificio:

    def __init__(self, PlantaInf, PlantaSup, NumAscensores, CargaMaximaAsc):
        import threading

        self.ListaDeAscensores=[]
        self.ListaDePlantas=[]
        self.ListaOrdenes=[]
        for N in range(NumAscensores):
            ascensor=Ascensor(PlantaInf, PlantaSup+1,CargaMaximaAsc)
            self.ListaDeAscensores.append(ascensor)
            t= threading.Thread(target=ascensor.run)

        for N in range(PlantaInf, PlantaSup+1):
            self.ListaDePlantas.append([self.ListaDeAscensores, N] )

edif=Edificio(-2,9,3,400)

import  time, random
# Bucle de eventos aleatorios
while 1:
    MayorOrig=random.randrange(2)
    if MayorOrig==0: # Orden desde un ascensor
        MinorOrig=random.randrange(len(edif.ListaDeAscensores))
    else: # Orden desde una planta
        MinorOrig=random.randrange(len(edif.ListaDePlantas))
    PlantaDestino=random.randrange(len(edif.ListaDePlantas))
    RandOrden=Orden(MayorOrig, MinorOrig, PlantaDestino)
    edif.ListaOrdenes.append(RandOrden)
    time.sleep(1.5)

==================8<-----------------------------------------------



-- 
Un saludo
Antonio Castro

       /\     /\
         \\W//
        _|0 0|_
+-oOOO-(___o___)-OOOo---------------------+
| . . . . U U . Antonio Castro Snurmacher |
| . . . . . . . acastro en ciberdroide.com   |
+()()()---------()()()--------------------+




Más información sobre la lista de distribución Python-es