Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 58f663a

Browse files
kunwar31norvig
authored andcommitted
Implemented plan_route and plan_shot (aimacode#872)
* define plan_route, plan_shot and refactor code * minor changes * Added PlanRoute Problem class * update plan_route return list of actions ( node.solution() ) instead of node itself in plan_route
1 parent bf5b8dc commit 58f663a

File tree

2 files changed

+177
-45
lines changed

2 files changed

+177
-45
lines changed

logic.py

Lines changed: 73 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
isnumber, issequence, Expr, expr, subexpressions
3737
)
3838
import agents
39+
from search import astar_search, PlanRoute
3940

4041
import itertools
4142
import random
@@ -763,7 +764,7 @@ def location(x, y, time = None):
763764
def implies(lhs, rhs):
764765
return Expr('==>', lhs, rhs)
765766

766-
def implies_and_implies(lhs, rhs):
767+
def equiv(lhs, rhs):
767768
return Expr('<=>', lhs, rhs)
768769

769770
# Helper Function
@@ -811,8 +812,8 @@ def __init__(self,dimrow):
811812
pits_in.append(pit(x, y - 1))
812813
wumpus_in.append(wumpus(x, y - 1))
813814

814-
self.tell(implies_and_implies(breeze(x, y), new_disjunction(pits_in)))
815-
self.tell(implies_and_implies(stench(x, y), new_disjunction(wumpus_in)))
815+
self.tell(equiv(breeze(x, y), new_disjunction(pits_in)))
816+
self.tell(equiv(stench(x, y), new_disjunction(wumpus_in)))
816817

817818

818819
## Rule that describes existence of at least one Wumpus
@@ -837,8 +838,8 @@ def __init__(self,dimrow):
837838
self.tell(location(1, 1, 0))
838839
for i in range(1, dimrow+1):
839840
for j in range(1, dimrow + 1):
840-
self.tell(implies(location(i, j, 0), implies_and_implies(percept_breeze(0), breeze(i, j))))
841-
self.tell(implies(location(i, j, 0), implies_and_implies(percept_stench(0), stench(i, j))))
841+
self.tell(implies(location(i, j, 0), equiv(percept_breeze(0), breeze(i, j))))
842+
self.tell(implies(location(i, j, 0), equiv(percept_stench(0), stench(i, j))))
842843
if i != 1 or j != 1:
843844
self.tell(~location(i, j, 0))
844845

@@ -903,13 +904,13 @@ def add_temporal_sentences(self, time):
903904
## current location rules
904905
for i in range(1, self.dimrow+1):
905906
for j in range(1, self.dimrow+1):
906-
self.tell(implies(location(i, j, time), implies_and_implies(percept_breeze(time), breeze(i, j))))
907-
self.tell(implies(location(i, j, time), implies_and_implies(percept_stench(time), stench(i, j))))
907+
self.tell(implies(location(i, j, time), equiv(percept_breeze(time), breeze(i, j))))
908+
self.tell(implies(location(i, j, time), equiv(percept_stench(time), stench(i, j))))
908909

909910
s = list()
910911

911912
s.append(
912-
implies_and_implies(
913+
equiv(
913914
location(i, j, time), location(i, j, time) & ~move_forward(time) | percept_bump(time)))
914915

915916
if i != 1:
@@ -929,72 +930,79 @@ def add_temporal_sentences(self, time):
929930

930931
## add sentence about safety of location i,j
931932
self.tell(
932-
implies_and_implies(ok_to_move(i, j, time), ~pit(i, j) & ~wumpus(i, j) & wumpus_alive(time))
933+
equiv(ok_to_move(i, j, time), ~pit(i, j) & ~wumpus(i, j) & wumpus_alive(time))
933934
)
934935

935936
## Rules about current orientation
936937

937938
a = facing_north(t) & turn_right(t)
938939
b = facing_south(t) & turn_left(t)
939940
c = facing_east(t) & ~turn_left(t) & ~turn_right(t)
940-
s = implies_and_implies(facing_east(time), a | b | c)
941+
s = equiv(facing_east(time), a | b | c)
941942
self.tell(s)
942943

943944
a = facing_north(t) & turn_left(t)
944945
b = facing_south(t) & turn_right(t)
945946
c = facing_west(t) & ~turn_left(t) & ~turn_right(t)
946-
s = implies_and_implies(facing_west(time), a | b | c)
947+
s = equiv(facing_west(time), a | b | c)
947948
self.tell(s)
948949

949950
a = facing_east(t) & turn_left(t)
950951
b = facing_west(t) & turn_right(t)
951952
c = facing_north(t) & ~turn_left(t) & ~turn_right(t)
952-
s = implies_and_implies(facing_north(time), a | b | c)
953+
s = equiv(facing_north(time), a | b | c)
953954
self.tell(s)
954955

955956
a = facing_west(t) & turn_left(t)
956957
b = facing_east(t) & turn_right(t)
957958
c = facing_south(t) & ~turn_left(t) & ~turn_right(t)
958-
s = implies_and_implies(facing_south(time), a | b | c)
959+
s = equiv(facing_south(time), a | b | c)
959960
self.tell(s)
960961

961962
## Rules about last action
962-
self.tell(implies_and_implies(move_forward(t), ~turn_right(t) & ~turn_left(t)))
963+
self.tell(equiv(move_forward(t), ~turn_right(t) & ~turn_left(t)))
963964

964965
##Rule about the arrow
965-
self.tell(implies_and_implies(have_arrow(time), have_arrow(t) & ~shoot(t)))
966+
self.tell(equiv(have_arrow(time), have_arrow(t) & ~shoot(t)))
966967

967968
##Rule about Wumpus (dead or alive)
968-
self.tell(implies_and_implies(wumpus_alive(time), wumpus_alive(t) & ~percept_scream(time)))
969+
self.tell(equiv(wumpus_alive(time), wumpus_alive(t) & ~percept_scream(time)))
969970

970971

971972
def ask_if_true(self, query):
972973
return pl_resolution(self, query)
973-
974-
974+
975+
975976
# ______________________________________________________________________________
976977

977978

978979
class WumpusPosition():
979-
def __init__(self, X, Y, orientation):
980-
self.X = X
981-
self.Y = Y
980+
def __init__(self, x, y, orientation):
981+
self.X = x
982+
self.Y = y
982983
self.orientation = orientation
983984

984985

985986
def get_location(self):
986987
return self.X, self.Y
987988

989+
def set_location(self, x, y):
990+
self.X = x
991+
self.Y = y
992+
988993
def get_orientation(self):
989994
return self.orientation
990995

991-
def equals(self, wumpus_position):
992-
if wumpus_position.get_location() == self.get_location() and \
993-
wumpus_position.get_orientation()==self.get_orientation():
996+
def set_orientation(self, orientation):
997+
self.orientation = orientation
998+
999+
def __eq__(self, other):
1000+
if other.get_location() == self.get_location() and \
1001+
other.get_orientation()==self.get_orientation():
9941002
return True
9951003
else:
9961004
return False
997-
1005+
9981006
# ______________________________________________________________________________
9991007

10001008

@@ -1041,9 +1049,8 @@ def execute(self, percept):
10411049
goals = list()
10421050
goals.append([1, 1])
10431051
self.plan.append('Grab')
1044-
actions = plan_route(self.current_position,goals,safe_points)
1045-
for action in actions:
1046-
self.plan.append(action)
1052+
actions = self.plan_route(self.current_position,goals,safe_points)
1053+
self.plan.extend(actions)
10471054
self.plan.append('Climb')
10481055

10491056
if len(self.plan) == 0:
@@ -1059,9 +1066,8 @@ def execute(self, percept):
10591066
if u not in unvisited_and_safe and s == u:
10601067
unvisited_and_safe.append(u)
10611068

1062-
temp = plan_route(self.current_position,unvisited_and_safe,safe_points)
1063-
for t in temp:
1064-
self.plan.append(t)
1069+
temp = self.plan_route(self.current_position,unvisited_and_safe,safe_points)
1070+
self.plan.extend(temp)
10651071

10661072
if len(self.plan) == 0 and self.kb.ask_if_true(have_arrow(self.t)):
10671073
possible_wumpus = list()
@@ -1070,26 +1076,23 @@ def execute(self, percept):
10701076
if not self.kb.ask_if_true(wumpus(i, j)):
10711077
possible_wumpus.append([i, j])
10721078

1073-
temp = plan_shot(self.current_position, possible_wumpus, safe_points)
1074-
for t in temp:
1075-
self.plan.append(t)
1079+
temp = self.plan_shot(self.current_position, possible_wumpus, safe_points)
1080+
self.plan.extend(temp)
10761081

10771082
if len(self.plan) == 0:
10781083
not_unsafe = list()
10791084
for i in range(1, self.dimrow+1):
10801085
for j in range(1, self.dimrow+1):
10811086
if not self.kb.ask_if_true(ok_to_move(i, j, self.t)):
10821087
not_unsafe.append([i, j])
1083-
temp = plan_route(self.current_position, not_unsafe, safe_points)
1084-
for t in temp:
1085-
self.plan.append(t)
1088+
temp = self.plan_route(self.current_position, not_unsafe, safe_points)
1089+
self.plan.extend(temp)
10861090

10871091
if len(self.plan) == 0:
10881092
start = list()
10891093
start.append([1, 1])
1090-
temp = plan_route(self.current_position, start, safe_points)
1091-
for t in temp:
1092-
self.plan.append(t)
1094+
temp = self.plan_route(self.current_position, start, safe_points)
1095+
self.plan.extend(temp)
10931096
self.plan.append('Climb')
10941097

10951098
action = self.plan[0]
@@ -1100,12 +1103,37 @@ def execute(self, percept):
11001103
return action
11011104

11021105

1103-
def plan_route(current, goals, allowed):
1104-
raise NotImplementedError
1106+
def plan_route(self, current, goals, allowed):
1107+
problem = PlanRoute(current, goals, allowed, self.dimrow)
1108+
return astar_search(problem).solution()
1109+
11051110

1106-
1107-
def plan_shot(current, goals, allowed):
1108-
raise NotImplementedError
1111+
def plan_shot(self, current, goals, allowed):
1112+
shooting_positions = set()
1113+
1114+
for loc in goals:
1115+
x = loc[0]
1116+
y = loc[1]
1117+
for i in range(1, self.dimrow+1):
1118+
if i < x:
1119+
shooting_positions.add(WumpusPosition(i, y, 'EAST'))
1120+
if i > x:
1121+
shooting_positions.add(WumpusPosition(i, y, 'WEST'))
1122+
if i < y:
1123+
shooting_positions.add(WumpusPosition(x, i, 'NORTH'))
1124+
if i > y:
1125+
shooting_positions.add(WumpusPosition(x, i, 'SOUTH'))
1126+
1127+
# Can't have a shooting position from any of the rooms the Wumpus could reside
1128+
orientations = ['EAST', 'WEST', 'NORTH', 'SOUTH']
1129+
for loc in goals:
1130+
for orientation in orientations:
1131+
shooting_positions.remove(WumpusPosition(loc[0], loc[1], orientation))
1132+
1133+
actions = list()
1134+
actions.extend(self.plan_route(current, shooting_positions, allowed))
1135+
actions.append('Shoot')
1136+
return actions
11091137

11101138

11111139
# ______________________________________________________________________________

search.py

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,110 @@ def h(self, node):
485485

486486
return sum(s != g for (s, g) in zip(node.state, self.goal))
487487

488+
# ______________________________________________________________________________
489+
490+
491+
class PlanRoute(Problem):
492+
""" The problem of moving the Hybrid Wumpus Agent from one place to other """
493+
494+
def __init__(self, initial, goal, allowed, dimrow):
495+
""" Define goal state and initialize a problem """
496+
497+
self.dimrow = dimrow
498+
self.goal = goal
499+
self.allowed = allowed
500+
Problem.__init__(self, initial, goal)
501+
502+
def actions(self, state):
503+
""" Return the actions that can be executed in the given state.
504+
The result would be a list, since there are only three possible actions
505+
in any given state of the environment """
506+
507+
possible_actions = ['Forward', 'TurnLeft', 'TurnRight']
508+
x, y = state.get_location()
509+
orientation = state.get_orientation()
510+
511+
# Prevent Bumps
512+
if x == 1 and orientation == 'LEFT':
513+
if 'Forward' in possible_actions:
514+
possible_actions.remove('Forward')
515+
if y == 1 and orientation == 'DOWN':
516+
if 'Forward' in possible_actions:
517+
possible_actions.remove('Forward')
518+
if x == self.dimrow and orientation == 'RIGHT':
519+
if 'Forward' in possible_actions:
520+
possible_actions.remove('Forward')
521+
if y == self.dimrow and orientation == 'UP':
522+
if 'Forward' in possible_actions:
523+
possible_actions.remove('Forward')
524+
525+
return possible_actions
526+
527+
def result(self, state, action):
528+
""" Given state and action, return a new state that is the result of the action.
529+
Action is assumed to be a valid action in the state """
530+
x, y = state.get_location()
531+
proposed_loc = list()
532+
533+
# Move Forward
534+
if action == 'Forward':
535+
if state.get_orientation() == 'UP':
536+
proposed_loc = [x, y + 1]
537+
elif state.get_orientation() == 'DOWN':
538+
proposed_loc = [x, y - 1]
539+
elif state.get_orientation() == 'LEFT':
540+
proposed_loc = [x - 1, y]
541+
elif state.get_orientation() == 'RIGHT':
542+
proposed_loc = [x + 1, y]
543+
else:
544+
raise Exception('InvalidOrientation')
545+
546+
# Rotate counter-clockwise
547+
elif action == 'TurnLeft':
548+
if state.get_orientation() == 'UP':
549+
state.set_orientation('LEFT')
550+
elif state.get_orientation() == 'DOWN':
551+
state.set_orientation('RIGHT')
552+
elif state.get_orientation() == 'LEFT':
553+
state.set_orientation('DOWN')
554+
elif state.get_orientation() == 'RIGHT':
555+
state.set_orientation('UP')
556+
else:
557+
raise Exception('InvalidOrientation')
558+
559+
# Rotate clockwise
560+
elif action == 'TurnRight':
561+
if state.get_orientation() == 'UP':
562+
state.set_orientation('RIGHT')
563+
elif state.get_orientation() == 'DOWN':
564+
state.set_orientation('LEFT')
565+
elif state.get_orientation() == 'LEFT':
566+
state.set_orientation('UP')
567+
elif state.get_orientation() == 'RIGHT':
568+
state.set_orientation('DOWN')
569+
else:
570+
raise Exception('InvalidOrientation')
571+
572+
if proposed_loc in self.allowed:
573+
state.set_location(proposed_loc[0], [proposed_loc[1]])
574+
575+
return state
576+
577+
def goal_test(self, state):
578+
""" Given a state, return True if state is a goal state or False, otherwise """
579+
580+
return state.get_location() == tuple(self.goal)
581+
582+
def h(self, node):
583+
""" Return the heuristic value for a given state."""
584+
585+
# Manhattan Heuristic Function
586+
x1, y1 = node.state.get_location()
587+
x2, y2 = self.goal
588+
589+
return abs(x2 - x1) + abs(y2 - y1)
590+
591+
488592
# ______________________________________________________________________________
489593
# Other search algorithms
490594

0 commit comments

Comments
 (0)