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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy