Report abuse

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
/*
For this environment simulator we will represent the environment
in a dictionary of key/value pairs. This isn't the most efficient,
but it's easy to implement.
*/
% hashtable manipulation utilities
% get the value for a key
% get_attr(key,list,value).
get_attr(Attr,[],[]). 
get_attr(Attr,[[Attr,Result]|T],Result).
get_attr(Attr,[H|T],Result) :- get_attr(Attr,T,Result).

% set the value for a key
% set_attr(key,value,list,newlist).
set_attr(Attr,Value,[],[[Attr,Value]]).
set_attr(Attr,Value,[[Attr,V]|T],[[Attr,Value]|T]). 
set_attr(Attr,Value,[[I,M]|T],[[I,M]|Result]) :- 
	set_attr(Attr,Value,T,Result).

% display the world
write_state([]).
write_state([[A,B]|T]) :-
	write('['),write(A),write(','),write(B),write(']'),
	write_state(T).

/* Here we use some abstract rules that rely on agent specific rules.
this allows us to keep the system generic, and promotes code reuse */
% useful prototypes
% change the state by applying an action rule to it.
actuate(Action,State,NewState) :- action(Action,State,NewState).
% example action rule. Called by actuate.
action(end,State,NewState) :- fail.

agent_loop([],State,State,Models,Models).
agent_loop([A|Agents],State,NewState,Models,NewModels) :- 
	sensor(A,State,Percept),
	get_attr(A,Models,Model),
	agent_program(A,Percept,Action,Model,NewModel),
	write(A),write(' does '),write(Action),nl,
	actuate(Action,State,MidState),
	write('  After state:'),write_state(MidState),nl,
	set_attr(A,NewModel,Models,MidModels),
	agent_loop(Agents,MidState,NewState,MidModels,NewModels).

% main loop
% start: load the initial state, and execute the first step.
start :- initial_state(X),initial_models(M),step(X,M).
% display the state, build the percept, get the agent's action
% actuate that action, display the results
% step on the new state.
step(State,Models) :-  !,write('Step? [Y|N] '),read(X),X='y',nl,
	write('Before state: '),write_state(State),nl,
	exogenous_action(State,EState),
	agents(A),agent_loop(A,EState,MidState,Models,NewModels),
	!,step(MidState,NewModels).
% NB: step/1 is recursive, and uses tail-call recursion to pass the
% state between calls. This is a common prolog technique. The execution
% is actually iterative.

% vacuum world initial state
% this is where the code gets specific to this domain.
location(a). %this isn't really useful, but I wanted to make it clear
             %what my locations are.
location(b).
%this is important. This defines the relationship between the two 
%locations in this very simple universe.
connect(a,b).
%and here's my initial state.
%The vacuum is at location a, a is dirty, b is clean.
initial_state([[location,a],[a,dirty],[b,clean]]).
initial_models([]).
agents([sra]).

% use this hook to make the world mutate.
exogenous_action(State,State).

% global actions - these are the things we can do in Vacuum World
% these define how an action performed by the vacuum impacts the state.
% clean: change the location's state to clean.
action(clean,State,NewState) :- get_attr(location,State,L),
	set_attr(L,clean,State,NewState).
% move_left: if my current location(L) is connected like so connect(X,L)
% change my location to X.
action(move_left,State,NewState) :- get_attr(location,State,L),
	connect(X,L),set_attr(location,X,State,NewState).
% move_right: reverse of move_left.
action(move_right,State,NewState) :- get_attr(location,State,L),
	connect(L,X),set_attr(location,X,State,NewState).

% vacuum perceptions
% the vacuum's sensor lets it know which location it's in
% and whether the current location is dirty or clean.
% it cannot tell the cleanliness of other locations.
% This is the Sensor for ALL agents in Vacuum World.
% In a more advanced setting, we could have different sensors for each
% agent.
sensor(X,State,[[location,L],[L,CoD],[moves,Moves]]) :- 
	get_attr(location,State,L),
	get_attr(L,State,CoD),possible_moves(State,Moves).
possible_moves(State,[[left, LP],[right, RP]]) :- 
	get_attr(location,State,L), can_go(left,L,LP), can_go(right,L,RP).
can_go(left,Loc,R) :- connect(X,Loc),R = true.
can_go(right,Loc,R) :- connect(Loc,X),R = true.
can_go(_,_,R) :- R = false.

% finally, the agent program that implements my agent function.
% this example is a simple reflex agent.
% if my current location is dirty, clean it
% 
% the simple reflex agent
agent_program(sra,Percept,Action,_,[]) :- 
	write('Percept:'),nl,
	write_state(Percept),nl,
	get_attr(location,Percept,L),
	get_attr(L,Percept,dirty),Action = clean.
% if I can go right, go right.
agent_program(sra,Percept,Action,_,[]) :- get_attr(moves,Percept,M),
	get_attr(right,M,true), Action = move_right.
% if I can go left, go left
agent_program(sra,Percept,Action,_,[]) :- get_attr(moves,Percept,M),
	get_attr(left,M,true), Action = move_left.