def setUp(self): self.firstState = State("First") self.secondState = State("Second") self.thirdState = State("Third") self.fourthState = State("Fourth") self.fifthState = State("Fifth") self.sixthState = State("Sixth") self.seventhState = State("Seventh") self.firstAction = Action("<Action One>") self.secondAction = Action("<Action Two>") self.thirdAction = Action("<Action Three>") self.fourthAction = Action("<Action Four>") self.successorFunction = SuccessorFunction() self.successorFunction.addMapping(self.firstState, self.firstAction,\ self.firstState) self.successorFunction.addMapping(self.firstState, self.secondAction,\ self.secondState) self.successorFunction.addMapping(self.firstState, self.thirdAction,\ self.firstState) self.searchProblem = SearchProblem(self.firstState,\ self.successorFunction,\ self.secondState)
def testSuccessorFunctionDefinition(self): simpleFunction = SuccessorFunction() simpleFunction.addMapping(self.firstState, self.firstAction, self.secondState) simpleFunctionString = str(simpleFunction) #Verbose output: # print(simpleFunctionString) # print("--------------------------------------------\n") # print("Trying to execute:\naddMapping((State First with conditions: \ # (None)) ->\n\t(Action <Action One>, State Second with conditions: (None)))\n") # print("This is a duplicate of the first mapping in a Successor Function \ # and should not be reflected at all.\n") simpleFunction.addMapping(self.firstState, self.firstAction, self.secondState) simpleFunctionDupString = str(simpleFunction) # print(simpleFunctionDupString) self.assertEqual(simpleFunctionString, simpleFunctionDupString, \ "Duplicate mappings in a Successor Function should not \ be reflected at all.") # print("--------------------------------------------\n") # print("Trying to execute:\naddMapping((State First with conditions: \ # (None)) ->\n\t(Action <Action One>, State Third with conditions: (None)))\n") # print("Applying the same action in the same state should not be allowed to\ # result in two different states.\n") # print("Adding this mapping should replace the original mapping.\n") simpleFunction.addMapping(self.firstState, self.firstAction, self.thirdState) simpleFunctionReplaceString = str(simpleFunction) #print(simpleFunctionReplaceString) self.assertNotEqual(simpleFunctionString, simpleFunctionReplaceString, \ "Mapping one State to one Action with multiple \ resulting States keeps only the last-most State.")
def main(): move_one_missionary = Action("Move One Missionary") move_two_missionaries = Action("Move Two Missionaries") move_one_cannibal = Action("Move One Cannibal") move_two_cannibals = Action("Move Two Cannibals") move_one_and_one = Action("Move One Missionary + One Cannibal") initial_state = State("Init", {'L':{'3m','3c','b'}, 'R':{'0m','0c'}}) goal_state = State("Goal", {'L':{'0m','0c'}, 'R':{'3m','3c','b'}}) # Any state where cannibals outnumber missionaries is not a valid state one_and_one_over = State("1m1c Over", {'L':{'2m','2c'}, 'R':{'1m','1c','b'}}) one_and_one_over_without_boat = State("1m1c Over w/o Boat", {'L':{'2m','2c','b'}, 'R':{'1m','1c'}}) two_cannibals_over = State("2c Over", {'L':{'3m','1c'}, 'R':{'0m','2c','b'}}) two_cannibals_over_without_boat = State("2c Over w/o Boat", {'L':{'3m','1c', 'b'}, 'R':{'0m','2c'}}) one_cannibal_over = State("1c Over", {'L':{'3m','2c'}, 'R':{'0m','1c','b'}}) one_cannibal_over_without_boat = State("1c Over w/o Boat", {'L':{'3m','2c','b'}, 'R':{'0m','1c'}}) two_and_two_over = State("2m2c Over", {'L':{'1m','1c'}, 'R':{'2m','2c','b'}}) two_and_two_over_without_boat = State("2m2c Over", {'L':{'1m','1c','b'}, 'R':{'2m','2c'}}) three_cannibals_over = State("3c Over", {'L':{'3m','0c'}, 'R':{'0m','3c','b'}}) three_missionaries_over_without_boat = State("3m Over w/o Boat", {'L':{'0m','3c', 'b'}, 'R':{'3m','0c'}}) three_missionaries_one_cannibal_over = State("3m3c Over", {'L':{'0m','1c'}, 'R':{'3m','1c','b'}}) three_missionaries_one_cannibal_over_without_boat = State("3m1c Over w/o Boat", {'L':{'0m','2c', 'b'}, 'R':{'3m','1c'}}) three_missionaries_two_cannibals_over = State("3m2c Over", {'L':{'0m','1c'}, 'R':{'3m','2c','b'}}) #Example invalid states: #two_cannibals_over_without_boat = State("2c Over w/o Boat", {'L':{'3m','1c', 'b'}, 'R':{'0m','2c'}}) #one_missionary_two_cannibals_over = State("1m2c Over", {'L':{'2m','1c'}, 'R':{'1m','2c','b'}}) #Successor Function successor_fn = SuccessorFunction() successor_fn.addMapping(initial_state, move_two_cannibals, two_cannibals_over) successor_fn.addMapping(initial_state, move_one_and_one, one_and_one_over) successor_fn.addMapping(initial_state, move_one_cannibal, one_cannibal_over) #be careful w/mappings that result in the initial_state #you could descend in an infinte loop... #Beginning in (two_cannibals_over) successor_fn.addMapping(two_cannibals_over, move_two_cannibals, initial_state) successor_fn.addMapping(two_cannibals_over, move_one_cannibal, one_cannibal_over_without_boat) #Beginning in (one_and_one_over) successor_fn.addMapping(one_and_one_over, move_one_and_one, initial_state) successor_fn.addMapping(one_and_one_over, move_one_missionary, one_cannibal_over_without_boat) #Beginning in (one_cannibal_over) successor_fn.addMapping(one_cannibal_over, move_one_cannibal, initial_state) #Beginning in (one_cannibal_over_without_boat) successor_fn.addMapping(one_cannibal_over_without_boat, move_one_cannibal, two_cannibals_over) successor_fn.addMapping(one_cannibal_over_without_boat, move_one_missionary, one_and_one_over) successor_fn.addMapping(one_cannibal_over_without_boat, move_two_cannibals, three_cannibals_over) #Beginning in (three_cannibals_over) successor_fn.addMapping(three_cannibals_over, move_one_cannibal, two_cannibals_over_without_boat) successor_fn.addMapping(three_cannibals_over, move_two_cannibals, one_cannibal_over_without_boat) #Beginning in (two_cannibals_over_without_boat) successor_fn.addMapping(two_cannibals_over_without_boat, move_two_missionaries, two_and_two_over) successor_fn.addMapping(two_cannibals_over_without_boat, move_one_cannibal, three_cannibals_over) #Beginning in (two_and_two_over) successor_fn.addMapping(two_and_two_over, move_two_missionaries, two_cannibals_over_without_boat) successor_fn.addMapping(two_and_two_over, move_one_and_one, one_and_one_over_without_boat) #Beginning in (one_and_one_over_without_boat) successor_fn.addMapping(one_and_one_over_without_boat, move_one_and_one, two_and_two_over) successor_fn.addMapping(one_and_one_over_without_boat, move_two_missionaries, three_missionaries_one_cannibal_over) #Beginning in (three_missionaries_one_cannibal_over) successor_fn.addMapping(three_missionaries_one_cannibal_over, move_two_missionaries, one_and_one_over_without_boat) successor_fn.addMapping(three_missionaries_one_cannibal_over, move_one_cannibal, three_missionaries_over_without_boat) #Beginning in (three_missionaries_over_without_boat) successor_fn.addMapping(three_missionaries_over_without_boat, move_one_cannibal, three_missionaries_one_cannibal_over) successor_fn.addMapping(three_missionaries_over_without_boat, move_two_cannibals, three_missionaries_two_cannibals_over) #Beginning in (three_missionaries_two_cannibals_over) successor_fn.addMapping(three_missionaries_two_cannibals_over, move_two_cannibals, three_missionaries_over_without_boat) successor_fn.addMapping(three_missionaries_two_cannibals_over, move_one_cannibal, three_missionaries_one_cannibal_over_without_boat) successor_fn.addMapping(three_missionaries_two_cannibals_over, move_one_missionary, two_and_two_over_without_boat) #Beginning in (two_and_two_over_without_boat) successor_fn.addMapping(two_and_two_over_without_boat, move_one_missionary, three_missionaries_one_cannibal_over) successor_fn.addMapping(two_and_two_over_without_boat, move_one_and_one, goal_state) #Beginning in (three_missionaries_one_cannibal_over_without_boat) successor_fn.addMapping(three_missionaries_one_cannibal_over_without_boat, move_one_cannibal, three_missionaries_two_cannibals_over) successor_fn.addMapping(three_missionaries_one_cannibal_over_without_boat, move_two_cannibals, goal_state) #Define the Search Problem missionaries_and_cannibals = SearchProblem(initial_state, successor_fn, goal_state) plan = tree_search(missionaries_and_cannibals) print(missionaries_and_cannibals) print("\nSolution: \n") for plan_step in plan: if plan_step.action is None: print ("<start>") else: print ("\t"), print (plan_step.action) print("<end>") print("\nExpanded Nodes: \n") for plan_step in plan: print(plan_step)
class Test(unittest.TestCase): def setUp(self): self.firstState = State("First") self.secondState = State("Second") self.thirdState = State("Third") self.fourthState = State("Fourth") self.fifthState = State("Fifth") self.sixthState = State("Sixth") self.seventhState = State("Seventh") self.firstAction = Action("<Action One>") self.secondAction = Action("<Action Two>") self.thirdAction = Action("<Action Three>") self.fourthAction = Action("<Action Four>") self.successorFunction = SuccessorFunction() self.successorFunction.addMapping(self.firstState, self.firstAction,\ self.firstState) self.successorFunction.addMapping(self.firstState, self.secondAction,\ self.secondState) self.successorFunction.addMapping(self.firstState, self.thirdAction,\ self.firstState) self.searchProblem = SearchProblem(self.firstState,\ self.successorFunction,\ self.secondState) def tearDown(self): pass def testStateNameEquality(self): left = State("Left") leftToo = State("Left") right = State("Right") self.assertEqual(left, leftToo, "States should be equal") self.assertNotEqual(left, right, "States should not be equal") def testStateConditionsEquality(self): allLeft = State("AllLeft", {'L':{'3m','3c','b'}, 'R':{'0m','0c'}}) allLeftToo = State("AllLeft", {'L':{'3m','3c','b'}, 'R':{'0m','0c'}}) allRight = State("AllRight", {'L':{'0m','0c'}, 'R':{'3m','3c','b'}}) self.assertEqual(allLeft, allLeftToo, "These two States have identical\ names and conditions") self.assertNotEqual(allLeft, allRight, "These two States have different\ names and conditions") def testSuccessorFunctionDefinition(self): simpleFunction = SuccessorFunction() simpleFunction.addMapping(self.firstState, self.firstAction, self.secondState) simpleFunctionString = str(simpleFunction) #Verbose output: # print(simpleFunctionString) # print("--------------------------------------------\n") # print("Trying to execute:\naddMapping((State First with conditions: \ # (None)) ->\n\t(Action <Action One>, State Second with conditions: (None)))\n") # print("This is a duplicate of the first mapping in a Successor Function \ # and should not be reflected at all.\n") simpleFunction.addMapping(self.firstState, self.firstAction, self.secondState) simpleFunctionDupString = str(simpleFunction) # print(simpleFunctionDupString) self.assertEqual(simpleFunctionString, simpleFunctionDupString, \ "Duplicate mappings in a Successor Function should not \ be reflected at all.") # print("--------------------------------------------\n") # print("Trying to execute:\naddMapping((State First with conditions: \ # (None)) ->\n\t(Action <Action One>, State Third with conditions: (None)))\n") # print("Applying the same action in the same state should not be allowed to\ # result in two different states.\n") # print("Adding this mapping should replace the original mapping.\n") simpleFunction.addMapping(self.firstState, self.firstAction, self.thirdState) simpleFunctionReplaceString = str(simpleFunction) #print(simpleFunctionReplaceString) self.assertNotEqual(simpleFunctionString, simpleFunctionReplaceString, \ "Mapping one State to one Action with multiple \ resulting States keeps only the last-most State.") def testGettingApplicableActionsForStates(self): applicable_actions = \ self.successorFunction.getApplicableActionsInState(self.firstState) self.assertTrue(type(applicable_actions)==type(set()), \ "The returned value should be a Set") for action in applicable_actions: self.assertTrue(type(action)==Action, \ "Each element of the Set should be an Action") self.assertIn(self.firstAction, applicable_actions, \ "<Action One> should be in the returned Set") self.assertNotIn(self.fourthAction, applicable_actions, \ "<Action Four> should not be in the returned Set") def testResolveActionInState(self): resulting_state = \ self.successorFunction.resolveActionInState(self.firstState, self.firstAction) self.assertTrue(type(resulting_state)==State, \ "Resulting state should be a State") self.assertEqual(resulting_state, self.firstState, \ "Correct State is returned for applying corresponding Action") self.assertIsNone(self.successorFunction.resolveActionInState(self.thirdState, \ self.firstAction), \ "If State is not mapped, resulting State is None") self.assertIsNone(self.successorFunction.resolveActionInState(self.firstState, \ self.fourthAction), \ "If State is not mapped to given Action, resulting State is None") def testGoalTest(self): secondStateNode = SearchNode(self.secondState) self.assertTrue(self.searchProblem.goalTest(secondStateNode), \ "The SearchNode for the second State is the goal of this toy Search Problem") self.assertFalse(self.searchProblem.goalTest(self.secondState), \ "The Second State should be the goal of this toy Search Problem, \ but we're passing in a State, not a Node") self.assertFalse(self.searchProblem.goalTest(self.firstState), \ "The First State should not be the goal of this toy Search Problem") self.assertFalse(self.searchProblem.goalTest(1), "A number is not a State! This should be False") def testPathTo(self): root = SearchNode(self.firstState) child = SearchNode(self.secondState, root) grandchild = SearchNode(self.thirdState, child) true_path = [root, child, grandchild] test_path = path_to(grandchild) self.assertEqual(test_path, true_path, "Test and True Paths should be equal") def testExpand(self): #the expand function can actually have repeated nodes, so this is normal. true_expanded_nodes = [SearchNode(self.firstState,SearchNode(self.firstState),self.firstAction,0,1), SearchNode(self.firstState,SearchNode(self.firstState),self.thirdAction,0,1), SearchNode(self.secondState,SearchNode(self.firstState),self.secondAction,0,1) ] test_expanded_nodes = expand(self.searchProblem, SearchNode(self.firstState)) self.assertEqual(len(test_expanded_nodes), 3, "There should be three nodes in the Test Expansion") self.assertEqual(test_expanded_nodes[0], true_expanded_nodes[0], "Test and True Expansions should be the same") self.assertEqual(test_expanded_nodes[1], true_expanded_nodes[1], "Test and True Expansions should be the same") self.assertEqual(test_expanded_nodes[2], true_expanded_nodes[2], "Test and True Expansions should be the same")