/[ambar]/ambar/visita.py
ViewVC logotype

Diff of /ambar/visita.py

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 2.0 by pabloruiz, Sat Aug 17 21:11:09 2002 UTC revision 2.1 by amoyav, Fri Aug 23 12:51:18 2002 UTC
# Line 19  Line 19 
19  #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA  #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20  #  #
21  #  #
22  #Fichero: visita.py  #Fichero: visita.py
23    
24  """Clase Visita."""  """Clase Visita."""
25    
26  from xml.dom import minidom  from xml.dom import minidom
27  import random  import random
28  import sys  import sys
29  import string  import string
30  import os  import os
31    
32  from bloquedialogo import *  from bloquedialogo import *
33  from tema import *  from tema import *
34  from contexto import *  from contexto import *
35  from conversacion import *  from conversacion import *
36    
37  class Visita:  class Visita:
38      """Control de dialogos de los personajes no jugadores.      """Control de dialogos de los personajes no jugadores.
39            
40      Representa el estado de la conversación entre el PNJ y un grupo de PJs.      Representa el estado de la conversación entre el PNJ y un grupo de PJs.
41      Contiene los siguientes atributos:      Contiene los siguientes atributos:
42      - _conversacion: objeto de conversacion utilizado durante la visita.      - _conversacion: objeto de conversacion utilizado durante la visita.
43      - _items: secuencia de textos visitados durante el dialogo      - _items: secuencia de textos visitados durante el dialogo
44      - _items_especiales: secuencia de textos especiales visitados durante el dialogo      - _items_especiales: secuencia de textos especiales visitados durante el dialogo
45      - _hitos: diccionario de variables definidas durante la conversacion      - _hitos: diccionario de variables definidas durante la conversacion
46            
47      - _estado: tipo de mensaje devuelto en la última pregunta.      - _estado: tipo de mensaje devuelto en la última pregunta.
48      - pnj: personaje que posee la conversacion      - pnj: personaje que posee la conversacion
49      - pj_activo: personaje que realizó la última intervención en el diálogo      - pj_activo: personaje que realizó la última intervención en el diálogo
50      - participantes: diccionario con los personajes jugadores que han escuchado la conversación, y la lista de temas que han oido      - participantes: diccionario con los personajes jugadores que han escuchado la conversación, y la lista de temas que han oido
51      - _comando: último comando solicitado.      - _comando: último comando solicitado.
52      - _nombretema: último tema por el que se preguntó (independientemente de que se haya encontrado o no)      - _nombretema: último tema por el que se preguntó (independientemente de que se haya encontrado o no)
53      - _temas_especiales: diccionario con las lista de temas especiales por defecto en este diálogo.      - _temas_especiales: diccionario con las lista de temas especiales por defecto en este diálogo.
54            
55          self.activo <-> hay un item de texto activo          self.activo <-> hay un item de texto activo
56      """      """
57                    
58      ENCONTRADO = "encontrado"      ENCONTRADO = "encontrado"
59      BUSCANDO = "busqueda"      BUSCANDO = "busqueda"
# Line 61  class Visita: Line 61  class Visita:
61      NO_ENCONTRADO = "no encontrado"      NO_ENCONTRADO = "no encontrado"
62      OFFTOPIC = "offtopic"      OFFTOPIC = "offtopic"
63            
64      def __init__(self, conversacion, personajenojugador, temasEspeciales = None):      def __init__(self, conversacion, personajenojugador, temasEspeciales = None):
65          """Crea un controlador de dialogo para la conversacion a partir de un fichero de descripción de conversacion.          """Crea un controlador de dialogo para la conversacion a partir de un fichero de descripción de conversacion.
66    
67          conversacion: jerarquía de conversación cargada en memoria          conversacion: jerarquía de conversación cargada en memoria
68          personajenojugador: objeto PNJ que responde durante la conversación          personajenojugador: objeto PNJ que responde durante la conversación
69          temasEspeciales: respuestas por defecto en caso de fallo          temasEspeciales: respuestas por defecto en caso de fallo
70                    
71          Requiere:          Requiere:
72            id != None            id != None
73            personajenojugador != None            personajenojugador != None
74          """          """
75                    
76          self._estado = Visita.BUSCANDO          self._estado = Visita.BUSCANDO
77          self.pnj = personajenojugador          self.pnj = personajenojugador
78          self.pj_activo = None          self.pj_activo = None
79          self.activo = None          self.activo = None
80          self._conversacion = conversacion          self._conversacion = conversacion
81          self._items = []          self._items = []
82          self._items_especiales = []          self._items_especiales = []
83          self._hitos = {}          self._hitos = {}
84          self._comando = None          self._comando = None
85          if temasEspeciales == None:          if temasEspeciales == None:
86              temasEspeciales = temasEspecialesDefault              temasEspeciales = temasEspecialesDefault
87          self._temas_especiales = temasEspeciales          self._temas_especiales = temasEspeciales
88                    
89      def asignar_hito(self, nombre, valor="definido"):      def asignar_hito(self, nombre, valor="definido"):
90          escribir ("Definido hito " + str(nombre) + "=" + str(valor))          escribir ("Definido hito " + str(nombre) + "=" + str(valor))
# Line 103  class Visita: Line 103  class Visita:
103          self._items.insert(0, items["tema"])          self._items.insert(0, items["tema"])
104            
105      def buscar_items(self, tema):      def buscar_items(self, tema):
106          """Determina si el tema encontrado tiene algún item presentable. Devuelve el item correspondiente.          """Determina si el tema encontrado tiene algún item presentable. Devuelve el item correspondiente.
107                    
108          Un item es presentable si no ha sido ya utilizado y se cumplen sus requisitos.          Un item es presentable si no ha sido ya utilizado y se cumplen sus requisitos.
109          Si el tema tiene algún item presentable, lo devuelve.          Si el tema tiene algún item presentable, lo devuelve.
110          Si no hay ningún item presentable y el tema no se ha usado ninguna vez, es un tema nulo.          Si no hay ningún item presentable y el tema no se ha usado ninguna vez, es un tema nulo.
111          Si no hay items presentables y el tema ya se ha usado alguna vez, devuelve un item de tema agotado.          Si no hay items presentables y el tema ya se ha usado alguna vez, devuelve un item de tema agotado.
112                    
113          Requiere:          Requiere:
114            tema != None            tema != None
115            comando != None            comando != None
116                        
117          Asegura:          Asegura:
118            tema nulo  <->  return == None            tema nulo  <->  return == None
119            tema activado  <->  self._items := self._items.insert(0, item) y return == item            tema activado  <->  self._items := self._items.insert(0, item) y return == item
120            tema agotado   <->  return == itemAgotado            tema agotado   <->  return == itemAgotado
121          """          """
122                    
123          itemEncontrado = None          itemEncontrado = None
124          # Busca el primer item que cumpla los requisitos y no haya sido ya devuelto en esta conversación.          # Busca el primer item que cumpla los requisitos y no haya sido ya devuelto en esta conversación.
125          for item in tema.items():          for item in tema.items():
126              if item.satisfecho_en(self) and (item._comando == "ambos" or self.comando() == item._comando) and not self._item_gastado(item):              if item.satisfecho_en(self) and (item._comando == "ambos" or self.comando() == item._comando) and not self._item_gastado(item):
127                  itemEncontrado = item                  itemEncontrado = item
128                  self.estado_encontrado()                  self.estado_encontrado()
129                  return itemEncontrado                  return itemEncontrado
130                    
131          # -- Tema sin items activos --          # -- Tema sin items activos --
132          # Si el tema no está en ningún item de self._items, es un tema nulo          # Si el tema no está en ningún item de self._items, es un tema nulo
133          if not filter(lambda item: item.tema() == tema, self._items): # tema in map(lambda item: item.tema(), self._items):          if not filter(lambda item: item.tema() == tema, self._items): # tema in map(lambda item: item.tema(), self._items):
134              return None              return None
135          # Tema agotado          # Tema agotado
136          self.estado_agotado()          self.estado_agotado()
137          # Busca item de tema agotado en el contexto del tema          # Busca item de tema agotado en el contexto del tema
138          return self.item_tema_especial([tema.contexto(), tema.contexto().conversacion(), self], "temaAgotado")          return self.item_tema_especial([tema.contexto(), tema.contexto().conversacion(), self], "temaAgotado")
139    
140      def _item_gastado(self, item):      def _item_gastado(self, item):
141          """Indica si el item está repetido."""          """Indica si el item está repetido."""
# Line 168  class Visita: Line 168  class Visita:
168          # Error: debería haber encontrado el tema especial          # Error: debería haber encontrado el tema especial
169          raise ValueError("Tema especial de tipo " + tipo + " no ha encontrado items." )          raise ValueError("Tema especial de tipo " + tipo + " no ha encontrado items." )
170          return None          return None
171    
172      def _item_tema_especial(self, objeto, tipo):      def _item_tema_especial(self, objeto, tipo):
173          """Encuentra un item satisfecho. Si no hay ninguno o el elegido está gastado, devuelve None"""          """Encuentra un item satisfecho. Si no hay ninguno o el elegido está gastado, devuelve None"""
174          # Control de error en el objeto pasado como parámetro          # Control de error en el objeto pasado como parámetro
175  #        if not objeto.__dict__.has_key("_temas_especiales"):  #        if not objeto.__dict__.has_key("_temas_especiales"):
176  #            return none  #            return none
177                    
178          temas = objeto.temas_especiales()[tipo]          temas = objeto.temas_especiales()[tipo]
179          for tema in temas:          for tema in temas:
180              items = filter (lambda i: i.satisfecho_en(self), tema.items())              items = filter (lambda i: i.satisfecho_en(self), tema.items())
181              if items:              if items:
182                  item = random.choice(items)                  item = random.choice(items)
183                  #Item especial gastado?                  #Item especial gastado?
184                  if not item in self._items_especiales:                  if not item in self._items_especiales:
# Line 187  class Visita: Line 187  class Visita:
187                  if self._item_repeticiones(item, self._items_especiales)!= 0:                  if self._item_repeticiones(item, self._items_especiales)!= 0:
188                      # Quedan repeticiones por gastar                      # Quedan repeticiones por gastar
189                      return item                      return item
190          return None          return None
191                    
192      def temas_especiales(self):      def temas_especiales(self):
193          return self._temas_especiales          return self._temas_especiales
194            
195            
196      def responder(self, personaje, comando, nombretema):      def responder(self, personaje, comando, nombretema):
197          """Encuentra los items que debe responder el PNJ para responder al tema preguntado"""          """Encuentra los items que debe responder el PNJ para responder al tema preguntado"""
198    
199          nuevoItem = None          nuevoItem = None
200          resultado = {"especiales":[],"tema":None}          resultado = {"especiales":[],"tema":None}
201          self.activo = "si"          self.activo = "si"
202          self.pj_activo = personaje          self.pj_activo = personaje
203          self._nombretema = nombretema          self._nombretema = nombretema
204          self.estado_buscando()          self.estado_buscando()
205          if not self._conversacion._sinonimos.has_key(nombretema):          if not self._conversacion._sinonimos.has_key(nombretema):
206              # Tema no encontrado              # Tema no encontrado
207              self.estado_no_encontrado()              self.estado_no_encontrado()
208              if len(self._items)>0:              if len(self._items)>0:
209                  objetos = [self._items[0].tema().contexto()]                  objetos = [self._items[0].tema().contexto()]
210              else:              else:
211                  objetos = []                  objetos = []
212              objetos.append(self._conversacion)              objetos.append(self._conversacion)
213              objetos.append(self)              objetos.append(self)
214              # Busca item de tema no encontrado en el último contexto visitado              # Busca item de tema no encontrado en el último contexto visitado
215              resultado["especiales"] = [self.item_tema_especial(objetos, "temaNoEncontrado")]              resultado["especiales"] = [self.item_tema_especial(objetos, "temaNoEncontrado")]
216                    
217          if self.estado() == Visita.BUSCANDO:          if self.estado() == Visita.BUSCANDO:
218              nombretema = self._conversacion._sinonimos[nombretema]              nombretema = self._conversacion._sinonimos[nombretema]
219              self.pj_activo = personaje              self.pj_activo = personaje
220              self._comando = comando              self._comando = comando
221                            
222              # Busca el tema en cada uno de los items pasados              # Busca el tema en cada uno de los items pasados
223              for i in range(len(self._items)):              for i in range(len(self._items)):
224                  item = self._items[i]                  item = self._items[i]
225                  # Busca si el tema está repetido                  # Busca si el tema está repetido
226                  if item.tema().nombre() == nombretema:                  if item.tema().nombre() == nombretema:
227                      nuevoItem = self.buscar_items(item.tema())                      nuevoItem = self.buscar_items(item.tema())
228                      if self.estado() == Visita.AGOTADO:  resultado["especiales"] = [nuevoItem]                      if self.estado() == Visita.AGOTADO:  resultado["especiales"] = [nuevoItem]
229                      if self.estado() != Visita.BUSCANDO: break                      if self.estado() != Visita.BUSCANDO: break
230                  # Busca en los temas relacionados del item                  # Busca en los temas relacionados del item
231                  nombrecontexto_relacionado = item.relacionado(nombretema)                  nombrecontexto_relacionado = item.relacionado(nombretema)
232                  if nombrecontexto_relacionado:                  if nombrecontexto_relacionado:
233                      nuevoItem = self.buscar_items(self._conversacion.contexto(nombrecontexto_relacionado).tema(nombretema))                      nuevoItem = self.buscar_items(self._conversacion.contexto(nombrecontexto_relacionado).tema(nombretema))
234                      if self.estado() == Visita.AGOTADO:  resultado["especiales"] = [nuevoItem]                      if self.estado() == Visita.AGOTADO:  resultado["especiales"] = [nuevoItem]
235                      if self.estado() != Visita.BUSCANDO: break                      if self.estado() != Visita.BUSCANDO: break
236                  # Busca en el mismo contexto del item, si el contexto está dentro de la tolerancia a offtopics                  # Busca en el mismo contexto del item, si el contexto está dentro de la tolerancia a offtopics
237                  if i < self._conversacion.tolerancia():                  if i < self._conversacion.tolerancia():
238                      tema = item.tema().contexto().tema(nombretema)                      tema = item.tema().contexto().tema(nombretema)
239                      if tema:                      if tema:
240                          nuevoItem = self.buscar_items(tema)                          nuevoItem = self.buscar_items(tema)
241                          if self.estado() == Visita.AGOTADO:  resultado["especiales"] = [nuevoItem]                          if self.estado() == Visita.AGOTADO:  resultado["especiales"] = [nuevoItem]
242                          if self.estado() != Visita.BUSCANDO: break                          if self.estado() != Visita.BUSCANDO: break
243                    
# Line 246  class Visita: Line 246  class Visita:
246              for contexto in self._conversacion.contextos():              for contexto in self._conversacion.contextos():
247                  tema = contexto.tema(nombretema)                  tema = contexto.tema(nombretema)
248                  if tema:                  if tema:
249                      nuevoItem = self.buscar_items(tema)                      nuevoItem = self.buscar_items(tema)
250                      if self.estado() == Visita.AGOTADO:                      if self.estado() == Visita.AGOTADO:
251                          resultado["especiales"] = [nuevoItem]                          resultado["especiales"] = [nuevoItem]
252                          break                          break
253                      # Comprueba si el tema encontrado está offtopic                      # Comprueba si el tema encontrado está offtopic
254                      if self.estado() == Visita.ENCONTRADO:                      if self.estado() == Visita.ENCONTRADO:
255                          if tema.contexto() not in self._conversacion._contextos_iniciales:                          if tema.contexto() not in self._conversacion._contextos_iniciales:
256                              # Tema offtopic                              # Tema offtopic
257                              self.estado_offtopic()                              self.estado_offtopic()
258                              if len(self._items)>0:                              if len(self._items)>0:
259                                  objetos = [self._items[0].tema().contexto()]                                  objetos = [self._items[0].tema().contexto()]
260                              else:                              else:
261                                  objetos = []                                  objetos = []
262                              objetos.append(self._conversacion)                              objetos.append(self._conversacion)
263                              objetos.append(self)                              objetos.append(self)
264                              # Busca item de tema offtopic en el último contexto visitado                              # Busca item de tema offtopic en el último contexto visitado
265                              resultado["especiales"] = [self.item_tema_especial(objetos, "temaOfftopic")]                              resultado["especiales"] = [self.item_tema_especial(objetos, "temaOfftopic")]
# Line 276  class Visita: Line 276  class Visita:
276          elif self.estado() == Visita.BUSCANDO:          elif self.estado() == Visita.BUSCANDO:
277              # Tema no encontrado              # Tema no encontrado
278              self.estado_no_encontrado()              self.estado_no_encontrado()
279              if len(self._items)>0:              if len(self._items)>0:
280                  objetos = [self._items[0].tema().contexto()]                  objetos = [self._items[0].tema().contexto()]
281              else:              else:
282                  objetos = []                  objetos = []
283              objetos.append(self._conversacion)              objetos.append(self._conversacion)
284              objetos.append(self)              objetos.append(self)
285              # Busca item de tema offtopic en el último contexto visitado              # Busca item de tema offtopic en el último contexto visitado
286              resultado["especiales"] = [self.item_tema_especial(objetos, "temaNoEncontrado")]              resultado["especiales"] = [self.item_tema_especial(objetos, "temaNoEncontrado")]
287          return resultado          return resultado
288            
289      def comando(self):      def comando(self):
290          return self._comando          return self._comando
291                    
# Line 307  class Visita: Line 307  class Visita:
307      def estado_no_encontrado(self):      def estado_no_encontrado(self):
308          self._estado = Visita.NO_ENCONTRADO          self._estado = Visita.NO_ENCONTRADO
309                    
310      def items(self):      def items(self):
311          return self._items          return self._items
312    
313  # Inicializa las respuestas por defecto  # Inicializa las respuestas por defecto
314  archivo = os.path.join(BloqueDialogo.DIR_DESC_DIALOGOS, "general", "general-texto_por_defecto" + BloqueDialogo.EXT_DESC_DIALOGOS)  archivo = os.path.join(BloqueDialogo.DIR_DESC_DIALOGOS, "general", "general-texto_por_defecto" + BloqueDialogo.EXT_DESC_DIALOGOS)
315  #print archivo  #print archivo
316  stream = open(archivo)  stream = open(archivo)
317  doc_xml = minidom.parse(stream).documentElement  doc_xml = minidom.parse(stream).documentElement
318  stream.close()  stream.close()
319    
320  #temasEspecialesDefault: lista de respuestas por defecto  #temasEspecialesDefault: lista de respuestas por defecto
321  temasEspecialesDefault = parserXMLconversacion._parsear_temas_especiales(doc_xml)  temasEspecialesDefault = parserXMLconversacion._parsear_temas_especiales(doc_xml)
322    
323    
324  # Código para pruebas unitarias del módulo.  # Código para pruebas unitarias del módulo.
325    
326  def test():  def test():
327      conversacion = Conversacion("tutora")      conversacion = Conversacion("tutora")
328      c = Visita(conversacion, None)      c = Visita(conversacion, None)
329      while (1):      while (1):
330          texto = raw_input("? +preguntar por ")          texto = raw_input("? +preguntar por ")
331          respuesta = c.responder(None, None, texto.encode('ISO-8859-1'))          respuesta = c.responder(None, None, texto.encode('ISO-8859-1'))
332          for item in respuesta:          for item in respuesta:
333              print str(item)              print str(item)
334            
335  if (__name__ == '__main__'):  if (__name__ == '__main__'):
336      test()      test()

Legend:
Removed from v.2.0  
changed lines
  Added in v.2.1

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26