Example #1
0
def test_board_can_generate_all_valid_2x2_permutations():
    puzzles = Board.get_boards(2)
    assert [1, 2, 3, None] not in puzzles  # does not include solution
    assert [1, 3, 2, None] not in puzzles  # does not include invalid config
    assert [1, 2, None, 3] in puzzles  # does include a known valid config
    for puzzle in puzzles:
        assert Board.valid(puzzle)  # and all the others are valid
Example #2
0
 def __init__(self, tile_config):
     self.start_state = tile_config[:]
     self.board = Board(tile_config)
     self.solutions = {}
     self.recursed = 0
     self.all_paths = []
     self.solution_path = []
 def __init__(self, dimension):
     self.dimension = dimension
     solution = []
     for num in range(1, dimension**2):
         solution.append(num)
     solution.append(None)
     self.starting_state = solution
     self.board = Board(solution)
Example #4
0
class Solver:
    def __init__(self, tile_config):
        self.start_state = tile_config[:]
        self.board = Board(tile_config)
        self.solutions = {}
        self.recursed = 0
        self.all_paths = []
        self.solution_path = []

    def solve(self):
        moves = self.find_shortest_path()
        self.solution_path = moves
        if (moves != None):
            for move in moves:
                self.board.move(move)
        else:
            print("CRUD. Could not find a solution for {}.".format(self.start_state))
        return self.board.solved()

    def find_all_paths_from_point(self, board_state, completed_moves, previous_states, paths_so_far):
        all_paths = paths_so_far[:]
        available_moves = Board(board_state).lookahead()
        for move in available_moves:
            new_board_state = available_moves[move]
            path = completed_moves[:]
            if (new_board_state == self.board.solution):
                # we're done
                path.append(move)
                all_paths.append(path)
            elif (len(completed_moves) > 0) and (move == completed_moves[-1]):
                # ignore attempts to undo
                pass
            elif (len(path) > 2):
                path.append(move)
                path.append("R")
                all_paths.append(path)
            elif (new_board_state in previous_states):
                path.append(move)
                path.append("X")
                all_paths.append(path)
            else:
                path.append(move)
                previous_states.append(board_state)
                all_paths.extend(self.find_all_paths_from_point(new_board_state, path, previous_states, all_paths))
        return all_paths

    def find_shortest_path(self):
        self.all_paths = self.find_all_paths_from_point(self.start_state, [], [], [])
        shortest_path = None
        for path in self.all_paths:
            if (not isinstance(path[-1], int)):
                # skip the ones marked as not viable
                pass
            elif (shortest_path == None) or (len(shortest_path) > len(path)):
                shortest_path = path
        return shortest_path
Example #5
0
def test_board_can_generate_all_2x2_permutations():
    assert Board.get_permutations([1, 2, 3, None]) == [[1, 2, 3, None],
                                                       [1, 2, None, 3],
                                                       [1, 3, 2, None],
                                                       [1, 3, None, 2],
                                                       [1, None, 2, 3],
                                                       [1, None, 3, 2],
                                                       [2, 1, 3, None],
                                                       [2, 1, None, 3],
                                                       [2, 3, 1, None],
                                                       [2, 3, None, 1],
                                                       [2, None, 1, 3],
                                                       [2, None, 3, 1],
                                                       [3, 1, 2, None],
                                                       [3, 1, None, 2],
                                                       [3, 2, 1, None],
                                                       [3, 2, None, 1],
                                                       [3, None, 1, 2],
                                                       [3, None, 2, 1],
                                                       [None, 1, 2, 3],
                                                       [None, 1, 3, 2],
                                                       [None, 2, 1, 3],
                                                       [None, 2, 3, 1],
                                                       [None, 3, 1, 2],
                                                       [None, 3, 2, 1]]
Example #6
0
 def find_all_paths_from_point(self, board_state, completed_moves, previous_states, paths_so_far):
     all_paths = paths_so_far[:]
     available_moves = Board(board_state).lookahead()
     for move in available_moves:
         new_board_state = available_moves[move]
         path = completed_moves[:]
         if (new_board_state == self.board.solution):
             # we're done
             path.append(move)
             all_paths.append(path)
         elif (len(completed_moves) > 0) and (move == completed_moves[-1]):
             # ignore attempts to undo
             pass
         elif (len(path) > 2):
             path.append(move)
             path.append("R")
             all_paths.append(path)
         elif (new_board_state in previous_states):
             path.append(move)
             path.append("X")
             all_paths.append(path)
         else:
             path.append(move)
             previous_states.append(board_state)
             all_paths.extend(self.find_all_paths_from_point(new_board_state, path, previous_states, all_paths))
     return all_paths
Example #7
0
def test_all_2x2s():
    print("\n")
    all_valid_boards = Board.get_boards(2)
    generated_solutions = [[[1, 2, 3, None], []]]
    for move_count in range(1, 10):
        generated_solutions.extend(Generator(2).inmoves(move_count))
    # for thing in solutions:
    #     print(solutions[thing])
    for board in all_valid_boards:
        solved = None
        for solution in generated_solutions:
            if (solution[0] == board):
                if (solved == None or len(solved) > len(solution[1])):
                    solved = solution[1]
                    solved.reverse()
        print("Puzzle {} solution {}".format(board, solved))
class Generator:
    def __init__(self, dimension):
        self.dimension = dimension
        solution = []
        for num in range(1, dimension**2):
            solution.append(num)
        solution.append(None)
        self.starting_state = solution
        self.board = Board(solution)

    def inmoves(self, num_moves):
        paths = []
        check_states = {0: [[self.starting_state, []]]}
        for depth in range(num_moves):
            at_depth = (depth == num_moves - 1)
            check_states[depth + 1] = []
            for state in check_states[depth]:
                if at_depth:
                    paths.extend(
                        self.get_next_paths_from_state(state[0], state[1]))
                else:
                    check_states[depth + 1].extend(
                        self.get_next_paths_from_state(state[0], state[1]))

        return paths

    def get_next_paths_from_state(self, tiles, path_to_state):
        self.board.tiles = tiles
        paths = []
        lookahead = self.board.lookahead()
        for move in lookahead:
            if (len(path_to_state) == 0):
                paths.append([lookahead[move], [move]])
            elif (path_to_state[-1] != move):
                paths.append([lookahead[move], path_to_state + [move]])
        return paths
Example #9
0
def test_board_init_throws_error_if_board_too_small():
    with pytest.raises(RuntimeError) as excinfo:
        puzzle = Board([0, None])
    assert 'Tile configuration invalid' in str(excinfo.value)
Example #10
0
def test_board_knows_when_tiles_numbers_are_not_sequential():
    assert not Board().valid([1, 5, 2, None])
Example #11
0
def test_board_knows_when_there_is_more_than_one_space():
    assert not Board().valid([1, 2, None, None])
Example #12
0
def test_board_knows_when_there_is_no_space():
    assert not Board().valid([1, 2, 3, 4])
Example #13
0
def test_board_knows_8_tiles_is_not_valid():
    assert not Board().valid([1, 2, 3, 4, 5, 6, 7, None])
Example #14
0
def test_board_init():
    puzzle = Board()
    assert isinstance(puzzle.tiles, list)
Example #15
0
def test_default_board():
    puzzle = Board()
    assert puzzle.tiles == [1, 2, 3, 4, 5, 6, 7, 8, None]
Example #16
0
def test_board_can_tell_when_not_solved():
    puzzle = Board([2, 3, 1, None])
    assert not puzzle.solved()
Example #17
0
def test_board_has_a_solution():
    puzzle = Board([1, 3, 2, None])
    assert puzzle.solution == [1, 2, 3, None]
Example #18
0
def test_board_init_throws_error_if_tiles_not_sequential():
    with pytest.raises(RuntimeError) as excinfo:
        puzzle = Board([3, 5, 6, None])
    assert 'Tile configuration invalid' in str(excinfo.value)
Example #19
0
def test_board_can_generate_all_2d_permutations():
    assert sorted(Board.get_permutations([1, 2])) == [[1, 2], [2, 1]]
Example #20
0
def test_board_knows_dimensions():
    puzzle = Board([3, 2, 1, 4, 5, 6, 7, 8, None])
    assert puzzle.dimension == 3
Example #21
0
def test_board_can_report_diff_score_to_possible_new_state():
    puzzle = Board([1, None, 3, 2])
    assert puzzle.solution_diff_score_from([None, 1, 3, 2]) == 3
Example #22
0
def test_board_can_list_available_moves():
    puzzle = Board([1, None, 3, 2])
    assert puzzle.available_moves() == [1, 2]
Example #23
0
def test_board_init_throws_error_if_board_has_no_space():
    with pytest.raises(RuntimeError) as excinfo:
        puzzle = Board([1, 2, 3, 4])
    assert 'Tile configuration invalid' in str(excinfo.value)
Example #24
0
def test_board_knows_0_tiles_is_not_valid():
    assert not Board().valid([])
Example #25
0
def test_board_can_tell_when_solved():
    puzzle = Board([1, 2, 3, None])
    assert puzzle.solved()
Example #26
0
def test_board_knows_1_tile_is_not_valid():
    assert not Board().valid([1])
Example #27
0
def test_board_knows_where_the_blank_is():
    puzzle = Board([2, 3, 1, None])
    assert puzzle.blank_position == 3
Example #28
0
def test_board_knows_4_tiles_is_valid():
    assert Board().valid([1, 2, 3, None])
Example #29
0
def test_board_can_move_piece():
    puzzle = Board([2, 3, 1, None])
    puzzle.move(3)
    assert puzzle.tiles == [2, None, 1, 3]
Example #30
0
def test_board_knows_9_tiles_is_valid_regardless_of_order():
    assert Board().valid([3, 2, 1, 8, 5, 6, 7, 4, None])