def test_solver_double_parent(self): level = Level() level.upper_layer = np.array([[s, lR, e, lR, f], [kR, w, kR, w, e]], dtype=object) # S--L--L--E # \ |\ | # \| \| # K K start = Start() key1 = Key("key1") lock1 = Lock("lock1") key2 = Key("key2") lock2 = Lock("lock2") end = End() start.add_child_s([key1, lock1]) key1.add_lock_s(lock1) lock1.add_child_s([key2, lock2]) key2.add_lock_s(lock2) lock2.add_child_s(end) positions_map = { start: np.array([0, 0]), key1: np.array([1, 0]), lock1: np.array([0, 1]), key2: np.array([1, 2]), lock2: np.array([0, 3]), end: np.array([0, 4]) } level.mission = start level.positions_map = positions_map does_level_follow_mission, solution = Solver.does_level_follow_mission( level) self.assertEqual(does_level_follow_mission, True)
def test_solver_linear_solvable(self): level = Level() level.upper_layer = np.array([[s, kR, lR, f]], dtype=object) # S--K--L--E start = Start() key = Key() lock = Lock() end = End() start.add_child_s([key, lock]) key.add_lock_s(lock) lock.add_child_s(end) positions_map = { start: np.array([0, 0]), key: np.array([0, 1]), lock: np.array([0, 2]), end: np.array([0, 3]), } level.mission = start level.positions_map = positions_map does_level_follow_mission, solution = Solver.does_level_follow_mission( level) self.assertEqual(does_level_follow_mission, True) expected_steps = [(start, []), (key, rM), (lock, rM), (end, rM)] self.assert_steps_equal(solution.steps, expected_steps)
def test_solver_branch_trivial1(self): level = Level() level.upper_layer = np.array( [[s, kR, lR, e, e, f], [lB, kB, w, w, e, e]], dtype=object) # S--K--L--L--E # \ / # K----- start = Start() key1 = Key("key1") lock1 = Lock("lock1") key2 = Key("key2") lock2 = Lock("lock2") end = End() start.add_child_s([key1, key2]) key1.add_child_s(lock1) key1.add_lock_s(lock1) lock1.add_child_s(lock2) key2.add_lock_s(lock2) lock2.add_child_s(end) positions_map = { start: np.array([0, 0]), key1: np.array([0, 1]), lock1: np.array([0, 2]), key2: np.array([1, 1]), lock2: np.array([1, 0]), end: np.array([0, 5]), } level.mission = start level.positions_map = positions_map does_level_follow_mission, solution = Solver.does_level_follow_mission( level) self.assertEqual(does_level_follow_mission, False)
def test_solver_hazard_unsolvable(self): level = Level() level.upper_layer = np.array( [[s, e, Fb, W, W, W, e, fl, e, F, F, e, F, F, e, f]], dtype=object) # S--K--L--E start = Start() key1 = Key("flippers") lock1 = Lock("water") key2 = Key("fireboots") lock2 = Lock("fire1") lock3 = Lock("fire2") end = End() start.add_child_s([key1, lock1]) key1.add_lock_s(lock1) lock1.add_child_s([key2, lock2]) key2.add_lock_s([lock2, lock3]) lock2.add_child_s(lock3) lock3.add_child_s(end) positions_map = { start: np.array([0, 0]), key1: np.array([0, 7]), lock1: np.array([0, 4]), key2: np.array([0, 2]), lock2: np.array([0, 10]), lock3: np.array([0, 13]), end: np.array([0, 15]), } level.mission = start level.positions_map = positions_map does_level_follow_mission, solution = Solver.does_level_follow_mission( level) self.assertEqual(does_level_follow_mission, False)
def test_sokoban_unsolvable(self): level = Level() level.upper_layer = np.array( [[s, kR, e, e, e, e, g, lR, f], [e, e, b, e, e, e, w, w, e]], dtype=object) start = Start() key = Key("key") block = SokobanKey("block") water = SokobanLock("water") lock = Lock("lock") end = End() start.add_child_s([key, block, water]) block.add_lock_s(water) key.add_lock_s(lock) water.add_child_s(lock) lock.add_child_s(end) positions_map = { start: np.array([0, 0]), key: np.array([0, 1]), block: np.array([1, 2]), water: np.array([0, 6]), lock: np.array([0, 7]), end: np.array([0, 8]), } level.mission = start level.positions_map = positions_map does_level_follow_mission, solution = Solver.does_level_follow_mission( level) self.assertEqual(does_level_follow_mission, False)
def test_solver_collectables_unreachable_collectable(self): level = Level() level.upper_layer = np.array([[s, e, B, f], [c, e, w, c]], dtype=object) level.required_collectable_count = 2 start = Start() c0 = Collectable("c0") c1 = Collectable("c1") barrier = CollectableBarrier("B", collectables=[c0, c1]) end = End() start.add_child_s([c0, barrier]) barrier.add_child_s([c1, end]) positions_map = { start: np.array([0, 0]), c0: np.array([1, 0]), c1: np.array([1, 3]), barrier: np.array([0, 2]), end: np.array([0, 3]), } level.mission = start level.positions_map = positions_map does_level_follow_mission, solution = Solver.does_level_follow_mission( level) self.assertEqual(does_level_follow_mission, False)
def test_solver_linear_trivial(self): level = Level() level.upper_layer = np.array([[s, kR, lR, f], [e, e, e, e]], dtype=object) # S--K--L--E start = Start() key = Key("key") lock = Lock("lock") end = End() start.add_child_s(key) key.add_lock_s(lock) lock.add_child_s(end) positions_map = { start: np.array([0, 0]), key: np.array([0, 1]), lock: np.array([0, 2]), end: np.array([0, 3]), } level.mission = start level.positions_map = positions_map does_level_follow_mission, solution = Solver.does_level_follow_mission( level) self.assertEqual(does_level_follow_mission, False)
def test_wrong_key_color(self): level = Level() level.upper_layer = np.array( [[s, e, lR, kR], [kR, e, w, w], [e, e, lR, f]], dtype=object) start = Start() key1 = Key("key1") lock1 = Lock("lock1") key2 = Key("key2") lock2 = Lock("lock2") end = End() start.add_child_s([key1, lock1, lock2]) lock1.add_child_s(key2) lock2.add_child_s(end) key1.add_lock_s(lock1) key2.add_lock_s(lock2) positions_map = { start: np.array([0, 0]), key1: np.array([1, 0]), lock1: np.array([0, 2]), key2: np.array([0, 3]), lock2: np.array([2, 2]), end: np.array([2, 3]), } level.mission = start level.positions_map = positions_map does_level_follow_mission, solution = Solver.does_level_follow_mission( level) self.assertEqual(does_level_follow_mission, False)
def test_solver_difficult(self): level = Level() level.upper_layer = np.array( [[f, e, e, w, e, W, e, w], [e, w, lG, w, e, w, Fb, w], [e, w, F, w, W, w, e, w], [e, w, s, w, e, w, F, w], [e, w, kR, w, fl, w, e, w], [e, w, e, lR, e, w, kG, w]], dtype=object) start = Start() key_red = Key("red") lock_red = Lock("red") flippers = Key("flippers") water1 = Lock("water1") water2 = Lock("water2") key_green = Key("green") lock_green = Lock("green") fire_boots = Key("fireboots") fire1 = Lock("fire1") fire2 = Lock("fire2") end = End() start.add_child_s([fire2, key_red, lock_red]) key_red.add_lock_s(lock_red) lock_red.add_child_s([flippers, water1]) flippers.add_lock_s([water1, water2]) water1.add_child_s(water2) water2.add_child_s([fire_boots, fire1]) fire_boots.add_lock_s([fire1, fire2]) fire1.add_child_s(key_green) key_green.add_lock_s(lock_green) fire2.add_child_s(lock_green) lock_green.add_child_s(end) # [ f, e, e, w, e, W, e, w], # [ e, w,lG, w, e, w,Fb, w], # [ e, w, F, w, W, w, e, w], # [ e, w, s, w, e, w, F, w], # [ e, w,kR, w,fl, w, e, w], # [ e, w, e,lR, e, w,kG, w]], dtype=object) positions_map = { start: np.array([3, 2]), key_red: np.array([4, 2]), lock_red: np.array([5, 3]), flippers: np.array([4, 4]), water1: np.array([2, 4]), water2: np.array([0, 5]), key_green: np.array([5, 6]), lock_green: np.array([1, 2]), fire_boots: np.array([1, 6]), fire1: np.array([3, 6]), fire2: np.array([2, 2]), end: np.array([0, 0]) } level.mission = start level.positions_map = positions_map does_level_follow_mission, solution = Solver.does_level_follow_mission( level) self.assertEqual(does_level_follow_mission, True)
def test_solver_linear_solvable_multicolored_keys(self): level = Level() level.upper_layer = np.array([[kY, lG, kB, lR, s, kR, lB, kG, lY, f]], dtype=object) # S--K--L--K--L--K--L--K--L--E start = Start() key_red = Key("red") lock_red = Lock("red") key_blue = Key("blue") lock_blue = Lock("blue") key_green = Key("green") lock_green = Lock("green") key_yellow = Key("yellow") lock_yellow = Lock("yellow") end = End() start.add_child_s([lock_red, key_red, lock_blue]) lock_red.add_child_s([lock_green, key_blue]) lock_green.add_child_s(key_yellow) lock_blue.add_child_s([lock_yellow, key_green]) lock_yellow.add_child_s(end) key_red.add_child_s(lock_red) key_red.add_lock_s(lock_red) key_blue.add_child_s(lock_blue) key_blue.add_lock_s(lock_blue) key_green.add_child_s(lock_green) key_green.add_lock_s(lock_green) key_yellow.add_child_s(lock_yellow) key_yellow.add_lock_s(lock_yellow) positions_map = { start: np.array([0, 4]), key_red: np.array([0, 5]), lock_red: np.array([0, 3]), key_blue: np.array([0, 2]), lock_blue: np.array([0, 6]), key_green: np.array([0, 7]), lock_green: np.array([0, 1]), key_yellow: np.array([0, 0]), lock_yellow: np.array([0, 8]), end: np.array([0, 9]), } level.mission = start level.positions_map = positions_map does_level_follow_mission, solution = Solver.does_level_follow_mission( level) self.assertEqual(does_level_follow_mission, True) expected_steps = [(start, []), (key_red, rM), (lock_red, 2 * lM), (key_blue, lM), (lock_blue, 4 * rM), (key_green, rM), (lock_green, 6 * lM), (key_yellow, lM), (lock_yellow, 8 * rM), (end, rM)] self.assert_steps_equal(solution.steps, expected_steps)
def generate_mission(level, mission_aesthetic): node_to_tile = dict() solution_node_order = Node.find_all_nodes(level.mission, method="topological-sort") spatial_graph = SpatialGraph(level.upper_layer) mission_spatial_nodes, mission_to_mission_spatial = MissionGenerator.convert_mission_graph_to_spatial_subgraph_form( solution_node_order) mission_to_spaces_mapping = SubgraphFinder.get_subgraph_mapping( spatial_graph.nodes, mission_spatial_nodes) if mission_to_spaces_mapping is not None: MissionGenerator.apply_mission_mapping_to_level( level, solution_node_order, mission_to_mission_spatial, mission_to_spaces_mapping, node_to_tile, mission_aesthetic) level.required_collectable_count = np.count_nonzero( level.upper_layer == Tiles.collectable) return Solver.does_level_follow_mission(level) return False, None
def test_degenerate_loop_layout(self): level = Level() level.upper_layer = np.array( [[w, w, w, w, w, w, w, w, w], [w, s, w, e, e, e, e, f, w], [w, kR, w, w, w, w, lG, w, w], [w, kG, lR, e, e, e, e, e, w], [w, e, w, e, e, e, e, kR, w], [w, e, w, w, lR, w, e, w, w], [w, e, w, e, e, e, e, e, w], [w, w, w, w, w, w, w, w, w]], dtype=object) start = Start() key0 = Key("key0") lock0 = Lock("lock0") key1 = Key("key1") lock1 = Lock("lock1") key2 = Key("key2") lock2 = Lock("lock2") end = End() start.add_child_s([lock0, key0, key2]) lock0.add_child_s([lock1, key1]) lock1.add_child_s(lock2) lock2.add_child_s(end) key0.add_lock_s(lock0) key1.add_lock_s(lock1) key2.add_lock_s(lock2) positions_map = { start: np.array([1, 1]), key0: np.array([2, 1]), key2: np.array([3, 1]), lock0: np.array([3, 2]), key1: np.array([4, 7]), lock1: np.array([5, 4]), lock2: np.array([2, 6]), end: np.array([1, 7]), } level.mission = start level.positions_map = positions_map does_level_follow_mission, solution = Solver.does_level_follow_mission( level) self.assertEqual(does_level_follow_mission, False)
def test_node_seen_too_soon_incorrect_layout2(self): level = Level() level.upper_layer = np.array( [[s, e, lR, kB], [kR, e, w, w], [e, e, lB, f]], dtype=object) # S---- # | | # L1 K1 # |---- # | | # L2 K2 # | # F start = Start() key1 = Key("key1") lock1 = Lock("lock1") key2 = Key("key2") lock2 = Lock("lock2") end = End() start.add_child_s([key1, lock1]) key1.add_lock_s(lock1) key2.add_lock_s(lock2) lock1.add_child_s([key2, lock2]) lock2.add_child_s(end) positions_map = { start: np.array([0, 0]), key1: np.array([1, 0]), lock1: np.array([0, 2]), key2: np.array([0, 3]), lock2: np.array([2, 2]), end: np.array([2, 3]), } level.mission = start level.positions_map = positions_map does_level_follow_mission, solution = Solver.does_level_follow_mission( level) self.assertEqual(does_level_follow_mission, False)
def test_sokoban_solvable_lock_in_middle(self): level = Level() level.upper_layer = np.array( [[s, kR, b, e, lR, e, g, e, f], [e, e, e, e, w, e, w, w, e]], dtype=object) start = Start() key = Key("key") block = SokobanKey("block") water = SokobanLock("water") lock = Lock("lock") end = End() start.add_child_s([key, block, lock]) block.add_lock_s([water]) key.add_lock_s(lock) lock.add_child_s(water) water.add_child_s(end) positions_map = { start: np.array([0, 0]), key: np.array([0, 1]), block: np.array([0, 2]), water: np.array([0, 6]), lock: np.array([0, 4]), end: np.array([0, 8]), } level.mission = start level.positions_map = positions_map does_level_follow_mission, solution = Solver.does_level_follow_mission( level) self.assertEqual(does_level_follow_mission, True) expected_steps = [(start, []), (key, rM), (block, []), (lock, dM + 2 * rM + uM + rM), (water, lM + dM + 2 * lM + uM + 4 * rM), (end, 3 * rM)] self.assert_steps_equal(solution.steps, expected_steps)
def test_solver_hazard_too_soon(self): level = Level() level.upper_layer = np.array( [[s, e, W, e, fl], [e, fl, w, w, w], [e, e, W, e, f]], dtype=object) # S--K--L--E start = Start() flippers1 = Key("flippers 1") water1 = Lock("water 1") flippers2 = Key("flippers 2") water2 = Lock("water 2") end = End() start.add_child_s([flippers1, water1, water2]) flippers1.add_lock_s(water1) water1.add_child_s(flippers2) flippers2.add_lock_s(water2) water2.add_child_s(end) # [ s, e, W, e,fl], # [ e,fl, w, w, w], # [ e, e, W, e, f]], dtype=object) positions_map = { start: np.array([0, 0]), flippers1: np.array([1, 1]), water1: np.array([0, 2]), flippers2: np.array([0, 4]), water2: np.array([2, 2]), end: np.array([2, 4]), } level.mission = start level.positions_map = positions_map does_level_follow_mission, solution = Solver.does_level_follow_mission( level) self.assertEqual(does_level_follow_mission, False)
def test_two_keys_soon_unneeded(self): level = Level() level.upper_layer = np.array( [[s, kR, lR, e, e, f], [e, kR, lR, e, e, e]], dtype=object) # S---------- # | | | # lR kR kB # | # lB # | # E start = Start() key1 = Key("key1") lock1 = Lock("lock1") key2 = Key("key2") lock2 = Lock("lock2") end = End() start.add_child_s([lock1, key1, key2]) lock1.add_child_s(lock2) lock2.add_child_s(end) key1.add_lock_s(lock1) key2.add_lock_s(lock2) positions_map = { start: np.array([0, 0]), key1: np.array([1, 1]), lock1: np.array([0, 2]), key2: np.array([0, 1]), lock2: np.array([0, 3]), end: np.array([0, 5]), } level.mission = start level.positions_map = positions_map does_level_follow_mission, solution = Solver.does_level_follow_mission( level) self.assertEqual(does_level_follow_mission, False)
def add_mission_node(level, solution_node_order, node, node_index, positions_map, node_to_tile, random_positions, start_position, mission_aesthetic): original_layer = level.upper_layer.copy() for position in random_positions: level.upper_layer = original_layer.copy() MissionGenerator.add_mission_tile(level.upper_layer, node, position, positions_map, node_to_tile, mission_aesthetic) Log.print("\n\n") Log.print(level) if Solver.does_level_follow_mission( level, solution_node_order[:node_index + 1], positions_map): was_successful, level = MissionGenerator._generate_mission( level, node_index + 1, solution_node_order, positions_map, node_to_tile, start_position, mission_aesthetic) if was_successful: return was_successful, level elif not MissionGenerator.is_generator_recursive: return False, level return False, level
def test_solver_collectables(self): level = Level() level.upper_layer = np.array([[s, e, B, f], [c, c, w, e]], dtype=object) level.required_collectable_count = 2 start = Start() c0 = Collectable("c0") c1 = Collectable("c1") barrier = CollectableBarrier("B", collectables=[c0, c1]) end = End() start.add_child_s([c0, c1, barrier]) barrier.add_child_s(end) positions_map = { start: np.array([0, 0]), c0: np.array([1, 0]), c1: np.array([1, 1]), barrier: np.array([0, 2]), end: np.array([0, 3]), } level.mission = start level.positions_map = positions_map does_level_follow_mission, solution = Solver.does_level_follow_mission( level) self.assertEqual(does_level_follow_mission, True) if solution.steps[1][0] == c1: expected_steps = [(start, []), (c1, dM + rM), (c0, lM), (barrier, rM + uM + rM), (end, rM)] else: expected_steps = [(start, []), (c0, dM), (c1, rM), (barrier, uM + rM), (end, rM)] self.assert_steps_equal(solution.steps, expected_steps)
def get_level(self): start = Start() key = Key() lock = Lock() c0 = Collectable() sokoban_key = SokobanKey() sokoban_lock = SokobanLock() c1 = Collectable() key2 = Key() lock2 = Lock() barrier = CollectableBarrier() end = End() start.add_child_s([key, lock, c0]) key.add_lock_s(lock) lock.add_child_s([sokoban_key, sokoban_lock, c1]) sokoban_key.add_lock_s(sokoban_lock) sokoban_lock.add_child_s([key2, lock2]) key2.add_lock_s(lock2) lock2.add_child_s(barrier) barrier.add_key_s([c0, c1]) barrier.add_child_s(end) level = Level() level.mission = start level.upper_layer = np.array([ [s, e, w, e, e, e, w, e], [e, e, w,kB, e, e,lB, B], [e, e, w, e, e, e, w, e], [e,kR, w, g, w, w, w, f], [e, e, w, e, c, e, w, e], [e, e, w, e, e, e, w, e], [c, e,lR, e, b, e, w, e], [e, e, w, e, e, e, w, e] ]) level.positions_map = { start: np.array([0,0]), key: np.array([3,1]), lock: np.array([6,2]), c0: np.array([6,0]), c1: np.array([4,4]), sokoban_key: np.array([6,4]), sokoban_lock: np.array([3,3]), key2: np.array([1,3]), lock2: np.array([1,6]), barrier: np.array([1,7]), end: np.array([3,7])} solution = Solver.does_level_follow_mission(level) level.solution = Solution(np.array([0, 0])) level.solution.add_step(start, []) level.solution.add_step(c0, 6*dM) level.solution.add_step(key, 3*uM + rM) level.solution.add_step(lock, 3*dM + rM) level.solution.add_step(c1, rM + uM + rM + uM) level.solution.add_step(sokoban_key, []) level.solution.add_step(sokoban_lock, dM + rM + dM + lM + dM + lM + 3*uM) level.solution.add_step(key2, 3*uM) level.solution.add_step(lock2, 3*rM) level.solution.add_step(barrier, rM) level.solution.add_step(end, dM) return level