CAAD

Comunidad de Aventuras Conversacionales y Relatos Interactivos
Fecha actual 23 Jun 2017 06:14

Todos los horarios son UTC + 1 hora




Nuevo tema Responder al tema  [ 11 mensajes ] 
Autor Mensaje
NotaPublicado: 20 Feb 2016 19:24 
Desconectado
Elfito
Elfito

Registrado: 01 Nov 2014 11:29
Mensajes: 11
Hola de nuevo!

Durante un tiempo deje aparcado el tema de la aventura conversacional. Y como al final me ha dado por darle a la programacion orientada a objetos (en Python :mrgreen: ) me surge una duda.

Cuando creamos una clase e instanciamos un objeto ¿Que es lo que coge el personaje? Por ejemplo:

Código:
class Persona:
   
    def __init__(self, nombre):
        self.nombre = nombre
        self.mochila = []
       
    def coger(self, obj):
        self.mochila.append(obj)
       
    def inventario(self):
        print(self.mochila)
       
class Objeto:
    def __init__(self, peso):
        self.peso = peso
   


Instanciamos nuestro jugador:

Código:
jugador = Persona('Yidu')


Y ahora un objeto que sera una botella (que pesara 2 kilos):

Código:
botella = Objeto(2)


Si hacemos esto:

Código:
jugador.coger('botella')


No es correcto. Ya que no deja de ser una cadena o un string. Osea, algo vacio y sin comportamiento.
Aunque si llamamos al metodo inventario si nos la muestra. Pero no dejara de ser una cadena de caracteres.

Código:
jugador.inventario()
['botella']


Lo ideal es coger el objeto botella. Osea, la instanciacion que hemos hecho de la clase:

Código:
jugador.coger(botella)


De esa forma, si que hemos cogido el objeto en cuestion. Con sus atributos y metodos.

Pero si queremos hacer el inventario nos sale:

Código:
jugador.inventario()
[<__main__.Objeto object at 0x0000000002D9C320>]


De ahi me surge la duda. Cuando definimos los objetos a usar ¿Son instanciaciones que podemos manipular?

Lo siguiente ya seria poder dejar y coger ese objeto en diversas localidades. Pero claro, que no fuera un string. Sino, el objeto instanciado.

Saludos!


Arriba
 Perfil  
 
NotaPublicado: 20 Feb 2016 20:23 
Desconectado
Dragón
Dragón
Avatar de Usuario

Registrado: 18 May 2011 15:56
Mensajes: 119
Ubicación: Zaragoza
Pues tienes dos opciones:

Puedes implementar un método en toda clase que tenga capacidad de tener «inventario» (es algo que se puede hacer por ejemplo haciendo derivar todo de una clase «Objeto» o «Entidad» que la lleve incorporada, por ejemplo) y ese método devuelva un «objeto» pasándole su nombre, del estilo:

Código:
objeto = contenedor.get_objeto('nombre')


y que el contenedor haga algo así como un sencillo

Código:
def get_objeto(nombre):
    # Capturamos el objeto
    cosa = inventario[nombre]
    # Lo eliminamos del inventario
    inventario.remove(nombre)
    # Lo devolvemos para ser utilizado en otro sitio
    return cosa


Un error en el paso del objeto de un inventario a otro puede dejar el objeto inaccesible.

La otra opción es poner la función en el modelo de mundo y que compruebe si el objeto está en el inventario dado, lo dé de baja y lo de de alta en el otro... Seguro que hay más opciones y alguna mejor de las que se me han ocurrido en estos cinco minutos.

_________________
Código:
    ___
  |/___\|   "Arto a la Guardia Siví!!!"
   qºLºp
    (-)


Arriba
 Perfil  
 
NotaPublicado: 20 Feb 2016 21:33 
Desconectado
Elfito
Elfito

Registrado: 28 Nov 2013 07:41
Mensajes: 17
Hola, Yidu!
Cuando lanzas print con la instancia de un objeto, python imprime el lugar de la memoria donde se almacenó dicho objeto. Habrás leído que en python todo es un objeto, incluso los strings, entonces ¿por qué los strings imprimen texto en lugar de su dirección en memoria? Bien, porque tienen algo así como un método definido para reaccionar con print que se llama __str__()

Código:
>>> class C1:
...     def __init__(self,texto):
...         self.texto = texto
...
>>> I1=C1("HOLA")
>>> print I1
<__main__.C1 instance at 0xb7233c8c>

Así podemos "engañar" a print escribiendo un método __str__ dentro de nuestra clase:
Código:
>>> class C1:
...     def __init__(self,texto):
...         self.texto = texto
...     def __str__(self):
...         return self.texto
...
>>> I1=C1("HOLA")
>>> print I1
HOLA


Yendo a tu caso...:

Yidu escribió:
Lo ideal es coger el objeto botella. Osea, la instanciacion que hemos hecho de la clase:

Código:
jugador.coger(botella)


De esa forma, si que hemos cogido el objeto en cuestion. Con sus atributos y metodos.

Pero si queremos hacer el inventario nos sale:

Código:
jugador.inventario()
[<__main__.Objeto object at 0x0000000002D9C320>]


La respuesta que ha publicado más arriba Notxor es más elaborada y apunta al diseño, pero desde mi poca experiencia lo que quería señalar es que has olvidado que la clase Objeto tenga una propiedad 'nombre' o 'listarse'! Del modo en que llames a la instancia dentro del código debería ser indiferente (imagina un nombre de cosa con espacios!). No sé si esta observación ayuda a dilucidar tu problema.

Para asegurarte de no coger un string puedes hacer una comprobación utilizando el método isinstance() http://effbot.org/pyfaq/how-do-i-check- ... -of-it.htm

Saludos!


Arriba
 Perfil  
 
NotaPublicado: 20 Feb 2016 22:19 
Desconectado
Implementador
Implementador

Registrado: 13 Feb 2005 18:57
Mensajes: 1853
Citar:
Cuando creamos una clase e instanciamos un objeto ¿Que es lo que coge el personaje?

El personaje no coge nada, es todo abstracto. Tú decides cómo representas el cambio de estado en el programa.

Has decidido que el conjunto cosas que tiene el jugador se almacena en la lista mochila. Has probado por separado a guardar en la lista dos tipos de valores diferentes: nombres o instancias.

Dices que guardar el nombre no es correcto y que guardar la instancia no da los resultados satisfactorios, pero esto es arbitrario. Ambas opciones son perfectamente válidas si el resto del programa lo tiene en cuenta.

¿Qué resultado esperas del método inventario?

¿No podrías obtener ese resultado partiendo tanto de los nombres como de las instancias? ¿Por qué?

Citar:
De ahi me surge la duda. Cuando definimos los objetos a usar ¿Son instanciaciones que podemos manipular?

Sí, claro. Cambiar el estado de las instancias [*] y agruparlas de diferentes maneras es fundamental. Como también es fundamental poder hacer referencia(!) a ellas, de forma más indirecta o menos.

En principio, por sencillez, puedes almacenar las propias instancias en la mochila, pero a la larga encontrarás que almacenar identificadores únicos que "representen" (¡una referencia indirecta!) las instancias es beneficioso.

[*] O, más ortodoxo (en ciertos paradigmas), hacer que las instancias cambien su propio estado.

PS: Los conceptos con los que trabajamos al programar una aventura a tan bajo nivel puede parecer difusos (porque el término "botella" puede aparecer en muchos contextos, incluso puede que haya más de una botella). Esto requiere que sepamos diferenciarlos. Son diferentes el "objeto" que ve el jugador (un texto), las palabras con las que el jugador hace referencia a ese "objeto", el objeto/instancia que representa ese "objeto", el nombre de cierta variable (o variables) que apunta a la instancia, un identificador que nos permite acceder indirectamente a la instancia... y un largo etcétera de etcéteras.


Arriba
 Perfil  
 
NotaPublicado: 21 Feb 2016 13:58 
Desconectado
Elfito
Elfito

Registrado: 01 Nov 2014 11:29
Mensajes: 11
Muchas gracias a los tres. Esta claro que todavia me queda aclarar conceptos con POO en Python. Lo que conozco de este lenguaje a sido (como comente al comienzo del post) con programacion estructurada y algo de funcional. Lo que he tocado de POO a sido la declaracion de clases, atributos y metodos e instantaciones. Me queda todo el tema de metodos especiales y sobrecarga de operadores.

Por ese motivo, he escogido crear una aventura conversacional (aunque sea sencilla) para aclarar conceptos con este paradigma.

Y sobre la duda que iniciaba el post, se trata de eso...que el objeto tenga estados. Cosa, que un string o cadena, no tiene. Al instanciar de la clase Objeto una linterna (por ejemplo) puede tener el estado encendida. Asignando este estado como True o False. Automaticamente si entramos a una localidad y el atributo encendida esta como True, podemos ver en la habitacion. De lo contrario, no.

Y de ahi me surge toda la duda de la implementacion. Si esto lo hacemos con un string, carece de esos estados.

Aunque no tiene nada que ver con el paradigma POO aqui dejo un simple codigo para moverse entre localidades. Con 'exit' se sale del bucle while. Las localidades estan implementadas en diccionarios. Asi como la ubicacion de objetos (al comienzo del juego). Pero si observais, esos objetos no dejan de ser cadenas o strings. Ahi es donde quiero sustituirlos por objetos. Para mas tarde poder cogerlos y dejarlos cuando visitemos esas localidades.

La cosa esta, que ahora veo clases por todos lados. Y no se si es necesario crear tantas. Osea, supongo que se deben crear estas clases basicas:

- clase Mapeado
- clase Objetos
- clase Personaje
- clase enemigos (que puede heredar de clase Personaje)

Con esas clases, creo, se podria hacer un juego basico ¿No?

Bueno, el codigo para moverse entre localidades:

Código:
def mapeado(hab):
    # definimos localidades, direcciones y posicion inicial objetos
    localidades = [['Habitacion 0', {'s': 3, 'e': 1}, ['lampara']],
                    ['Habitacion 1', {'s': 4, 'o': 0}, []],
                    ['Habitacion 2', {'s': 5}, ['Barril']],
                    ['Habitacion 3', {'n': 0, 'e': 4}, []],
                    ['Habitacion 4', {'n':1, 'e':5, 'o':3}, []],
                    ['Habitacion 5', {'n':2, 'o':4}, ['Vaso']]]
   
    habitacion_actual = hab     
    bandera = True
    while bandera:
       
        print(localidades[habitacion_actual][0])
        print('Objetos:', localidades[habitacion_actual][2])                 
        direc = input('Que quieres hacer? ')
       
        if direc in localidades[habitacion_actual][1]:       
            habitacion_actual = localidades[habitacion_actual][1].get(direc)
            print('Hay:', localidades[habitacion_actual][2])
            # no. habitacion
            return habitacion_actual
            # salidas
            #print(habitaciones[habitacion_actual][1])
        elif direc == 'exit':
            return               
        else:
            print('No puedes ir en esa direccion...')
            return habitacion_actual
           


Ejecucion:

Código:
# RUN
hab = 0
a = mapeado(hab)
bandera = True
while bandera:
    if a == None:
        bandera = False
    else:
        b = mapeado(a)
        if b in (0,1,2,3,4,5):
            a = mapeado(b)
   


Arriba
 Perfil  
 
NotaPublicado: 21 Feb 2016 16:28 
Desconectado
Implementador
Implementador

Registrado: 13 Feb 2005 18:57
Mensajes: 1853
Yidu escribió:
todavia me queda aclarar conceptos con POO en Python.

Creo que el problema inicial está más relacionado con a) diseño de APIs: el parámetro del método coger de Persona; b) estructuras de datos: qué almacenar, dónde y cómo acceder a los datos; que con la orientación a objetos.

Yidu escribió:
Y sobre la duda que iniciaba el post, se trata de eso...que el objeto tenga estados. Cosa, que un string o cadena, no tiene. Al instanciar de la clase Objeto una linterna (por ejemplo) puede tener el estado encendida. [...]
Y de ahi me surge toda la duda de la implementacion. Si esto lo hacemos con un string, carece de esos estados.

No deseas que un string se encargue del estado de una cosa, porque para ello quieres utilizar instancias de clases más especializadas, como las que declaraste al principio: Persona y Objeto. Hasta aquí bien.

Pero el string no te deja ver el bosque... ¿Por qué piensas que si en la mochila guardamos strings estamos renunciando a las instancias (y sus estados, etc...)?

Pista:
Spoiler: Mostrar
¿No es cierto que el diccionario de direcciones nos permite obtener un valor a partir de un string?
y...
Spoiler: Mostrar
las preguntas planteadas en mi anterior mensaje :P


Arriba
 Perfil  
 
NotaPublicado: 21 Feb 2016 18:48 
Desconectado
Elfito
Elfito

Registrado: 01 Nov 2014 11:29
Mensajes: 11
Si, como comentas, creo que estoy mezclando conceptos. Como si un paradigma descartase al otro. Cuando empiezas a estudiar la POO, tienes la sensacion que de todo se debe crear una clase y uno ve objetos por todos lados. Bueno, de hecho, en Python todo es un objeto.

Supongo que es un error de concepto. Es como si en la vida real tenemos una bolsa y dentro metemos un papel escrito que pone: botella. Eso no quiere decir que la tengamos fisicamente. Pues me pasa igual que con el string. En cambio, al instanciar ese objeto, parece que es mas 'real'.

Lo que me llama la atencion es que no se hayan creado mas aventuras con este lenguaje (Que no digo que no las haya, sobre todo en el mercado anglosajon). Creo que la persona que domine esta tipo de programacion y la facilidad de este lenguaje, no necesita de parsers. Sobre todo por que hay un sin fin de librerias para tratar los temas graficos.

Bueno, intentare asimilar todo lo leido en este post a ver si me voy aclarando. Saludos!


Arriba
 Perfil  
 
NotaPublicado: 21 Feb 2016 20:15 
Desconectado
Dragón
Dragón
Avatar de Usuario

Registrado: 18 May 2011 15:56
Mensajes: 119
Ubicación: Zaragoza
Yidu escribió:
Si, como comentas, creo que estoy mezclando conceptos. Como si un paradigma descartase al otro. Cuando empiezas a estudiar la POO, tienes la sensacion que de todo se debe crear una clase y uno ve objetos por todos lados. Bueno, de hecho, en Python todo es un objeto.


Bueno, en Python (como en otros lenguajes modernos) no todo son objetos. En smalltalk sí eran todo objetos (incluso las instrucciones «if» eran métodos de la clase «boolean»). Pero empecemos por el principio y no nos liemos con «tecnicismos» y etiquetas.

Sin embargo, Python se hace tan poderoso porque puede ajustarse a varios paradigmas de programación. Lo que no quiere decir que sea bueno mezclarlos porque sí.

Yidu escribió:
Supongo que es un error de concepto. Es como si en la vida real tenemos una bolsa y dentro metemos un papel escrito que pone: botella. Eso no quiere decir que la tengamos fisicamente. Pues me pasa igual que con el string. En cambio, al instanciar ese objeto, parece que es mas 'real'.


Plantea el problema desde otro punto de vista. La POO es un sistema de referencia que se basa en los objetos del mundo. En eso se parece al lenguaje natural. Cuando hablamos o escribimos «botella» estamos utilizando una etiqueta, no el objeto físico. Supongamos que quieres un objeto «botella» y tienes definido lo que se supone que es una clase:

Código:
class Cosa:
    def __init__(nombre):
        self.nombre = nombre
    ...
    ...


Más tarde cuando necesitas la botella la puedes crear con:

Código:
bot = Cosa("botella")


En ese contexto, «bot» es una instancia de la clase «Cosa» que tiene por nombre «botella». Para realizar cualquier acción con la botella, necesitas tener una instancia como lo es «bot». Si guardamos en una lista o diccionario esa instancia, podemos alcanzarla desde otras partes del código, por ejemplo:

Código:
inventario['botella']=bot
...

botella = inventario['botella']
print(botella.get_nombre())


Como puedes observar, lo único que manejas son referencias a esos objetos (que son conjuntos de datos y métodos, a los que se les envían mensajes para que hagan algo). En el ejemplo, lo que hacemos es conseguir una «etiqueta» para trabajar con la instancia guardada en «inventario», porque podríamos haber hecho lo mismo escribiendo toda la referencia como «inventario['botella'].get_nombre()»

Yidu escribió:
Lo que me llama la atencion es que no se hayan creado mas aventuras con este lenguaje (Que no digo que no las haya, sobre todo en el mercado anglosajon). Creo que la persona que domine esta tipo de programacion y la facilidad de este lenguaje, no necesita de parsers. Sobre todo por que hay un sin fin de librerias para tratar los temas graficos.

Bueno, intentare asimilar todo lo leido en este post a ver si me voy aclarando. Saludos!


Pues eso, el que la sigue la consigue. ;-)

_________________
Código:
    ___
  |/___\|   "Arto a la Guardia Siví!!!"
   qºLºp
    (-)


Arriba
 Perfil  
 
NotaPublicado: 21 Feb 2016 21:44 
Desconectado
Betatester
Betatester
Avatar de Usuario

Registrado: 24 Dic 2010 14:37
Mensajes: 859
Hola Yidu,

como ha sido una semana triste, he dedicado un par de horas de este domingo en crear esta estructura de python con algunas de las preguntas que haces. Espero que te ayude a aclarar algunas opciones que tiene:

https://github.com/Johan-Paz/pyif-test

Tienes un paquete 'model' y otro 'parse', que contienen lo justo y necesario para poder correr el 'adventure.py' que hay en la raíz.

Si te sirve de utilidad cualquier parte forkea a placer el proyecto.

Creo que confundes la parte que es complicada. No es el modelo del mundo, que como ves te lo puedes montar de una forma o de otra en un par de horas. Lo complicado de verdad es la parte de parseado, que incluye los problemas de desambiguación y de visibilidad que son mucho más duros que la parte de mapeado, inventario o cambio de estado.

Creo que hay tendencia a pensar que lo difícil es el modelo, cuando lo difícil es el parseado. Por eso yo suelo recomendar que se use un parser que ya exista en lugar de crearse uno de cero, pero como nunca me hacéis caso... :P pues suerte y sigue preguntando...


Arriba
 Perfil  
 
NotaPublicado: 21 Feb 2016 21:53 
Desconectado
Betatester
Betatester
Avatar de Usuario

Registrado: 24 Dic 2010 14:37
Mensajes: 859
Sólo es un ejemplo ilustrativo, ¡ojo!. Seguro que tiene un montón de problemas... -ya he visto un par.

:)


Arriba
 Perfil  
 
NotaPublicado: 22 Feb 2016 18:50 
Desconectado
Elfito
Elfito

Registrado: 01 Nov 2014 11:29
Mensajes: 11
Johan Paz escribió:
Hola Yidu,

como ha sido una semana triste, he dedicado un par de horas de este domingo en crear esta estructura de python con algunas de las preguntas que haces. Espero que te ayude a aclarar algunas opciones que tiene:

https://github.com/Johan-Paz/pyif-test

Tienes un paquete 'model' y otro 'parse', que contienen lo justo y necesario para poder correr el 'adventure.py' que hay en la raíz.

Si te sirve de utilidad cualquier parte forkea a placer el proyecto.

Creo que confundes la parte que es complicada. No es el modelo del mundo, que como ves te lo puedes montar de una forma o de otra en un par de horas. Lo complicado de verdad es la parte de parseado, que incluye los problemas de desambiguación y de visibilidad que son mucho más duros que la parte de mapeado, inventario o cambio de estado.

Creo que hay tendencia a pensar que lo difícil es el modelo, cuando lo difícil es el parseado. Por eso yo suelo recomendar que se use un parser que ya exista en lugar de crearse uno de cero, pero como nunca me hacéis caso... :P pues suerte y sigue preguntando...


Muchas gracias por el codigo en Python. Pero con una simple ojeada, ya he visto que hay muchas cosas que debo aprender. Esta claro que existen parsers ya hechos (tampoco quiero inventar la rueda :wink: ), pero lo que se trata es de practicar con la POO. Y claro, luego me tocara lidiar con el lenguaje y la inteligencia artificial de los personajes. Pero poco a poco.

Casi siempre intento aprender el paradigma de un lenguaje creando un juego o algo que me motive. Esta claro que sera un aventurilla corta ¡Tampoco voy a crear el Hobbit o Juego de Tronos! :lol:

El unico contacto que he tenido con un parser comercial es el PAW del Spectrum :roll:

Lo dicho, ire trasteando con tu codigo que seguro que aprendere algo. Gracias!


Arriba
 Perfil  
 
Mostrar mensajes previos:  Ordenar por  
Nuevo tema Responder al tema  [ 11 mensajes ] 

Todos los horarios son UTC + 1 hora


¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 1 invitado


No puede abrir nuevos temas en este Foro
No puede responder a temas en este Foro
No puede editar sus mensajes en este Foro
No puede borrar sus mensajes en este Foro

Buscar:
Saltar a:  
cron
Desarrollado por phpBB® Forum Software © phpBB Group
Traducción al español por Huan Manwë para phpBB-Es.COM