""" mind.py
 Copyright (C) 1998-1999 Aloril
 
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or
 (at your option) any later version.
 
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
"""

from copy import copy
from types import *

from thing import thing
from event import *
from know import know
from mem_map import mem_map
from vmind import vmind
from debug import debug
import wtime,mgoal
import dictlist, const, geometry, mgoal
import interlinguish
il=interlinguish
import ontology
ont=ontology

class dead(Exception): pass
rev_cmp={'>':'<'}

class memory:
    def __init__(self):
        self.events=[]
        self.places={}
    def destroy(self):
        self.events=None
        self.places=None
    def remember_place(self, place):
        self.places[place.get_xyz()]=place
    def recall_place(self, xyz, radius=0):
        if not radius:
            try:
                return [(0.0,self.places[xyz])]
            except KeyError:
                return []
        res=[]
        for p in self.places.keys():
            d=geometry.distance(p,xyz)
            if d<=radius:
                res.append((d,self.places[p]))
        res.sort()
        return res
    def remember_event(self, event):
        "add new memory with age"
        self.events.append([event,1.0])
    def recall_event(self, event, cmp):
        "return list of memories with same command"
        found=[]
        for (e,age) in self.events:
            if apply(cmp,(event,e)): found.append(e)
        return found
    def forget(self):
        "age memories and forgot too old ones"
        for m in self.events:
            m[1]=m[1]-0.1
        #remove forgotten things
        self.events=filter(lambda m:m[1]>const.fzero,self.events)

class eye(thing):
    def __init__(self, mind):
        thing.__init__(self, name=mind.name)
        self.mind=mind
    def destroy(self):
        self.mind=None
    def move_event(self,e):
        m=self.mind
        target=e.loc
        w=e.what
        if e.loc==m: m.add_thing(w)
        #if its part of inventory, use its xyz
        if hasattr(target,"xyz"):
            w.xyz=None
            w.place=target
        else:
            w.xyz=target
            w.place=None
        if w==m and not m.place:
            m.place=m.get_rknowledge("xyz",w.xyz)
    def make_event(self,e):
        m=self.mind
        if e.source==m:
            m.add_thing(e.what)
            if e.desc=="birth":
                return self.mind.teach_children(e.what)
    def change_event(self,e):
        t=e.what
        t.status=t.status+e.amount
    def fire_event(self,e):
        m=self.mind
        if e.loc!=m.place:
            return [event("move",what=m, loc=e.loc)]
        return [event("extinguish",what=e.what, target=e.what)]
    def destroy_event(self,e):
        return self.mind.destroy_event(e)

class speech(thing):
    def __init__(self, mind):
        thing.__init__(self, name=mind.name)
        self.mind=mind
        self.verb_dict={}
        self.iverb_dict={}
    def destroy(self):
        self.mind=None
    #verb handling
    def know_verb(self,e,say):
        m=self.mind
        sub=say.subject
        obj=say.object
        if type(obj)==StringType:
            m.add_knowledge("place",sub,obj)
        else:
            m.add_knowledge("xyz",sub,obj)
    def learn_verb(self,e,say):
        self.mind.add_goal(say.subject,say.object)
    def own_verb(self,e,say):
        m=self.mind
        if say.subject==m:
            m.add_thing(say.object)
    def buy_verb(self,e,say):
        self=self.mind
        if e.source.id!=self.id:
            t=self.things.get(say.subject)
            if t:
                t=t[0]
                self.remove_thing(t)
                return [event("move", what=t, loc=e.source)]
    def _verb(self, e, say):
        if say.interlinguish:
            return self.interlinguish(e,say.interlinguish)
        print "<",e.command,":",`say`,">"
    #Interlinguish handling
    def be_verb1_i(self, e, say):
        m=self.mind
        res=il.match_importance(say)
        if res:
            return m.add_importance(res['sub'].id,'>',res['obj'].id)
        else:
            return self.print_ui("Unkown assertion:",e)
    def print_ui(self, msg, e):
        print msg,`e`,e.what.interlinguish[0].lexlink.id[1:]
    def _i(self, e,say):
        return self.print_ui("Unknown Interlinguish 'verb':",e)
    def interlinguish(self, e,say):
        v=say[0].lexlink.id[1:]
        method=get_dict_func(self,self.iverb_dict,v+"_i",self._i)
        return method(e,say)
    def analyse(self, e):
        say=e.what
        method=get_dict_func(self,self.verb_dict,
                             say.verb+"_verb",self._verb)
        return method(e,say)

class mind(vmind):
    "minds: (=npc)"
    def __init__(self,id):
        vmind.__init__(self,id)
        self.eyes=eye(self)
        self.speech_center=speech(self)
        self.knowledge=know()
        self.mem=memory()
        self.things={}
        self.reverse_knowledge()
        self.goals=[]
        self.debug=debug(self.name+".mind.log")
    def __str__(self):
        s="\n"
        return s+">\n"
    def destroy(self):
        thing.destroy(self)
        self.things=None
        self.mem.destroy()
        self.eyes.destroy()
        self.eyes=None
        raise dead
    def reverse_knowledge(self):
        self.rknow=know()
        for (k,v) in self.knowledge.xyz.items():
            if not self.rknow.xyz.get(v):
                self.rknow.add("xyz",v,k)
    def get_rknowledge(self, what, key):
        d=getattr(self.rknow,what)
        return d.get(key)
    def get_knowledge(self, what, key):
        d=getattr(self.knowledge,what)
        return d.get(key)
    def add_knowledge(self,what,key,value):
        self.knowledge.add(what,key,value)
        if what=="xyz":
            self.rknow.add("xyz",value,key)
    def add_importance(self, sub, cmp, obj):
        self.add_knowledge('importance',(sub,obj),cmp)
        self.add_knowledge('importance',(obj,sub),rev_cmp[cmp])
    def cmp_goal_importance(self, g1, g2):
        id1=g1.key[1]
        id2=g2.key[1]
        l1=ont.get_isa(id1)
        l2=ont.get_isa(id2)
        for s1 in l1:
            for s2 in l2:
                cmp=self.knowledge.importance.get((s1.id,s2.id))
                if cmp:
                    return cmp=='>'
        return 1
    def add_goal(self, name, str_goal):
        goal=eval("mgoal."+str_goal)
        goal.str=str_goal
        if type(name)==StringType: goal.key=eval(name)
        else: goal.key=name
        self.add_knowledge("goal",name,goal)
        for i in range(len(self.goals)-1,-1,-1):
            if self.cmp_goal_importance(self.goals[i],goal):
                self.goals.insert(i+1,goal)
                return
        self.goals.insert(0,goal)
    def add_thing(self,thing): 
        if not thing.xyz:
            thing.xyz=self.get_knowledge("xyz",thing.place)
        dictlist.add_value(self.things,thing.name,thing)
    def find_thing(self, thing):
        if StringType==type(thing):
            #return found list or empty list
            return self.things.get(thing,[])
        found=[]
        for t in self.things.get(thing.name,[]):
            if t==thing: found.append(t)
        return found
    def remove_thing(self, thing):
        #I don't own this anymore (it may not exist)
        dictlist.remove_value(self.things, thing)
    #goal section
    def fulfill_goals(self,time):
        "see if all goals are fulfilled: if not try to fulfill them"
        for g in self.goals:
            res=g.check_goal(self,time)
            if res!=None: return res
    def teach_children(self, child):
        res=[]
        for k in self.knowledge.xyz.keys():
            es=esay('',verb='know',subject=k,object=self.knowledge.xyz[k])
            res.append(event('say',target=child,what=es))
        for k in self.knowledge.place.keys():
            es=esay('',verb='know',subject=k,object=self.knowledge.place[k])
            res.append(event('say',target=child,what=es))
        for g in self.goals:
            es=esay('',verb='learn',subject=g.key,object=g.str)
            res.append(event('say',target=child,what=es))
        for im in self.knowledge.importance.keys():
            cmp=self.knowledge.importance[im]
            if cmp=='>':
                s,i=il.importance(im[0],cmp,im[1])
                es=esay(s,interlinguish=i)
                res.append(event('say',target=child,what=es))
        return res
    #event handling: 
    #e is current input event
    #may return new events
    def sight_event(self,e):
        t=e.what
        if hasattr(t,"command"):
            return self.eyes.analyse_event(t)
        elif hasattr(t,"is_thing"): #CHEAT: will be removed
            if string.find(t.type,"house")>=0:
                self.mem.remember_place(t)
        elif t.id==self.id: #CHEAT: not anymore used
            self.__dict__.update(t.kw)
            if type(self.place)==StringType and not self.xyz:
                self.xyz=self.get_knowledge("xyz",self.place)
    def destroy_event(self,e):
        self.remove_thing(e.what)
        id=e.what.id
        if self.map.things.has_key(id):
            del self.map.things[id]
        if e.what.id==self.id:
            self.destroy()
            return []
    def say_event(self,e):
        #need something easier that just plain text
        #CHEAT!
        w=e.what
        if isinstance(w,esay):
            return self.speech_center.analyse(e)
        if hasattr(w,"is_thing"):
            self.add_thing(w)
            w.place=self.get_rknowledge("xyz",w.xyz)
    def think(self,time,input):
        output=None
        for e in input:
            res=self.analyse_event(e)
            #empty list is output too
            if res!=None and output==None:
                output=res
        if output!=None:
            return output
        output=self.fulfill_goals(time)
        if output==None: output=[]
        return output
    def run_step(self,time,input):
        """run one time step:
           try to achive all goals"""
        try:
            self.mem.forget()
            output=self.think(time,input)
            for e in output:
                self.mem.remember_event(e)
                if e.command=="move":
                    if type(e.loc)==StringType:
                        e.loc=self.get_knowledge("xyz",e.loc)
        except dead:
            output=[]
        self.debug([str(time),input,output])
        return output

    Source: geocities.com/siliconvalley/station/4279/src

               ( geocities.com/siliconvalley/station/4279)                   ( geocities.com/siliconvalley/station)                   ( geocities.com/siliconvalley)