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
Exemplo n.º 2
0
def test_board_can_provide_lookahead():
    puzzle = Board([1, None, 3, 2])
    assert puzzle.lookahead() == {1: [None, 1, 3, 2], 2: [1, 2, 3, None]}
class Solver:
    def __init__(self, tile_config):
        self.board = Board(tile_config)
        self.moves = []
        self.visited_states = []
        self.status = "Solving..."
        self.locked_tiles = []

    def solve(self):
        if self.board.is_solvable():
            self.visited_states.append(self.get_board_state())
            while (not self.board.solved()) and (self.status != "stuck"):
                self.find_best_move()
        else:
            self.status = "Unsolvable"

    def get_available_moves(self):
        return sorted([tile for tile in self.board.tile_neighbors(None) if isinstance(tile, int)])

    def get_board_state(self):
        board_state = self.board.tiles[:]
        return board_state

    def check_locks(self):
        # this is a really really dumb implementation - TEMPORARY
        # ONLY WORKS for 3x3s, not 4x4s

        self.locked_tiles = []

        # if 1 is in the 1 place, lock it
        if (self.board.tiles[0] == 1):
            self.locked_tiles.append(1)
            # and if 2 AND 3 are in place, lock them
            if (self.board.tiles[1] == 2 and self.board.tiles[2] == 3):
                self.locked_tiles.append(2)
                self.locked_tiles.append(3)

        if ((self.board.dimension == 3) and
                (1 in self.locked_tiles) and
                (self.board.tiles[3] == 4) and
                (self.board.tiles[6] == 7)
        ):
            self.locked_tiles.append(4)
            self.locked_tiles.append(7)

    def find_best_move(self):
        possible_moves = self.board.lookahead()
        move_scores = {}
        for move in possible_moves:
            move_scores[move] = self.board.solution_diff_score_from(possible_moves[move])
            # only consider moves that don't get us back to a known state
            if (move in self.locked_tiles):
                move_scores[move] += 9999
            if len(self.visited_states) > 0 and (possible_moves[move] == self.visited_states[-1]):
                move_scores[move] += 99999
            if (possible_moves[move] in self.visited_states):
                move_scores[move] += 99

        best_move = min(move_scores, key=move_scores.get)
        # print("BEST MOVE: {}".format(best_move))
        self.board.move(best_move)
        self.moves.append(best_move)
        self.visited_states.append(self.get_board_state())
        # if (best_move in self.locked_tiles):
        #     self.locked_tiles.remove(best_move)
        self.check_locks()
        if (len(self.moves) > 500):
            self.status = "stuck"