def test_board_can_tell_if_a_2x2_config_is_solvable(): puzzle = Board([1, None, 3, 2]) assert puzzle.is_solvable()
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"