def the_person_who_is(predicate, with_this, new_predicate, assign_this, state): """ If the person matches a predicate then assing another predicate. eg. The brit lives in a red house. If you find a brit assign the house red. Else if you find a red house assign the brit. Else propose the following If a house has no british posibilities remove red. If a house has no red possibilities remove british. :param str predicate: The predicate we are looking for. :param str with_this: Value to search with. :param str predicate: The predicate we will asign. :param str assign_this: Value to assign. :param dict state: The current state of the universe. """ house_is_this = einstein.get_position(with_this, state) house_assigned_this = einstein.get_position(assign_this, state) if house_is_this and house_assigned_this: return state elif house_is_this: return einstein.assign_value(house_is_this, new_predicate, assign_this, state) elif house_assigned_this: return einstein.assign_value(house_assigned_this, predicate, with_this, state) else: return einstein.propose_link(predicate, with_this, new_predicate, assign_this, state)
def test_propose_link(self): """ Proposing a value doesn't officially make an assignment. If the Swede keeps a bird then no one else can. If the Swede doesn't live in that house then neither can the bird. """ # Proposing a value with no assignments made won't change state new_state = deepcopy(einstein.START_STATE) new_state = einstein.propose_link('nationality', 'swedish', 'pet', 'bird', new_state) self.assertEqual(new_state, einstein.START_STATE) # The norweigen cannot own a bird, because the swede does. new_state = einstein.assign_value('1', 'nationality', 'norweigen', new_state) new_state = einstein.propose_link('nationality', 'swedish', 'pet', 'bird', new_state) self.assertNotIn('bird', new_state['1']['pet']) # If house 3 owns a horse then the swede cannot live there, because he owns a bird. new_state = einstein.assign_value('3', 'pet', 'horse', new_state) new_state = einstein.propose_link('nationality', 'swedish', 'pet', 'bird', new_state) self.assertNotIn('swedish', new_state['3']['nationality'])
def the_neighbour_of(predicate, with_this, new_predicate, can_have_this, state): """ If the house contains a predicate then the neighbouring house can have another predicate eg. The man who keeps horses lives next to the one who plays hockey. If this house has horses THEN next door can have hockeybut not horses AND this house cannot have hockey :param str predicate: The predicate we are looking for. :param str with_this: Value to search with. :param str predicate: The predicate we will asign. :param str can_have_this: Value to the neighbour can have. :param dict state: The current state of the universe. """ found_with_this = einstein.get_position(with_this, state) found_have_this = einstein.get_position(can_have_this, state) if found_with_this and found_have_this: #We have assigned these rules already return state elif found_with_this: #We only know where the horse lives houses = einstein.next_to(found_with_this) if len(houses) == 1: return einstein.assign_value(houses[0], new_predicate, can_have_this, state) else: return einstein.propose_house(houses, new_predicate, can_have_this, state) elif found_have_this: #We only know where the hockey is played houses = einstein.next_to(found_have_this) if len(houses) == 1: return einstein.assign_value(houses[0], predicate, with_this, state) else: return einstein.propose_house(houses, predicate, with_this, state) else: #We don't know where either the hockey or horse live return state
def test_double_assignment(self): """ If we attempt to assign the same value to two places we have gone wrong and should raise an error. """ new_state = einstein.assign_value('1', 'nationality', 'norweigen', einstein.START_STATE) self.assertEqual(new_state['1']['nationality'], set(['norweigen'])) self.assertNotIn('blue', new_state['2']['nationality']) self.assertNotIn('blue', new_state['3']['nationality']) self.assertNotIn('blue', new_state['4']['nationality']) self.assertNotIn('blue', new_state['5']['nationality']) # We whould see state error on a double assignment with self.assertRaises(einstein.StateError): new_state = einstein.assign_value('2', 'nationality', 'norweigen', new_state)
def rule4(state): """The green house is on the left of the white house.""" green_house = einstein.get_position('green', state) white_house = einstein.get_position('white', state) # Green and white are already defined if green_house and white_house: return state # Green is defined so we can define white elif green_house: return einstein.assign_value(einstein.right_of(house), 'house_color', 'white', state) # White is defined so we can define green elif white_house: return einstein.assign_value(einstein.right_of(house), 'house_color', 'white', state) # Neither Green or White are defined else: # Go through all houses and make the following assertions for house in state.keys(): house_to_right = einstein.right_of(house) house_to_left = einstein.left_of(house) # Nothing on the left so this cannot be the white house if not house_to_left: state = einstein.remove_value(house, 'house_color', 'white', state) # nothing o the right so this cannot be the green house elif not house_to_right: state = einstein.remove_value(house, 'house_color', 'green', state) if house_to_right: has_green = 'green' in state[house]['house_color'] white_to_right = 'white' in state[house_to_right][ 'house_color'] # If this house_color is green # BUT the house on the right is not white # THEN green must be removed from this house if has_green and not white_to_right: state = einstein.remove_value(house, 'house_color', 'green', state) # If this house is NOT green # THEN the house to the right cannot be white elif not has_green and white_to_right: state = einstein.remove_value(house_to_right, 'house_color', 'white', state) return state
def test_duplicate_assignment(self): """ If we make the same assignment twice it won't cause a problem. We will however like to see a message logged. """ new_state = einstein.assign_value('1', 'nationality', 'norweigen', einstein.START_STATE) self.assertEqual(new_state['1']['nationality'], set(['norweigen'])) self.assertNotIn('blue', new_state['2']['nationality']) self.assertNotIn('blue', new_state['3']['nationality']) self.assertNotIn('blue', new_state['4']['nationality']) self.assertNotIn('blue', new_state['5']['nationality']) new_state = einstein.assign_value('1', 'nationality', 'norweigen', new_state) self.assertEqual(new_state['1']['nationality'], set(['norweigen'])) self.assertNotIn('blue', new_state['2']['nationality']) self.assertNotIn('blue', new_state['3']['nationality']) self.assertNotIn('blue', new_state['4']['nationality']) self.assertNotIn('blue', new_state['5']['nationality'])
def test_assign_norweigen_to_first_house(self): """ Assert rule 9 the norweigen lives in the first house. """ # How do we represent this rule using a step from one state to the next new_state = einstein.assign_value('1', 'nationality', 'norweigen', einstein.START_STATE) self.assertEqual(new_state['1']['nationality'], set(['norweigen'])) self.assertNotIn('blue', new_state['2']['nationality']) self.assertNotIn('blue', new_state['3']['nationality']) self.assertNotIn('blue', new_state['4']['nationality']) self.assertNotIn('blue', new_state['5']['nationality'])
def test_get_position(self): """ If a value like 'norweigen' or 'dog' is the only value in a set of potential values then its been assigned. In this case return the house. If there is no such case return None """ new_state = deepcopy(einstein.START_STATE) # Not assigned so it won't be found self.assertIsNone(einstein.get_position('norweigen', new_state)) # Assign it and we will find it new_state = einstein.assign_value('1', 'nationality', 'norweigen', new_state) self.assertEqual(new_state['1']['nationality'], set(['norweigen'])) self.assertEqual(einstein.get_position('norweigen', new_state), '1') # It also won't feature anywhere else self.assertNotIn('blue', new_state['2']['nationality']) self.assertNotIn('blue', new_state['3']['nationality']) self.assertNotIn('blue', new_state['4']['nationality']) self.assertNotIn('blue', new_state['5']['nationality'])
def rule9(state): """The Norwegian lives in the first house.""" if einstein.get_position('norweigen', state): # Don't set twice return state else: return einstein.assign_value('1', 'nationality', 'norweigen', state)
def rule8(state): """The man living in the house right in the center drinks milk.""" if einstein.get_position('milk', state): # Don't set twice return state else: return einstein.assign_value('3', 'drink', 'milk', state)
def test_bogus_assignment(self): """ If we attemp to assign a bogus value we gat a KeyError """ with self.assertRaises(KeyError): einstein.assign_value('1', 'vehicle', 'car', einstein.START_STATE)