Exemplo n.º 1
0
    def probability_guesser(self):
        """

        :return:
        """
        # Get all unrevealed blocks that touch unchecked blocks
        blocks_to_guess = set([])
        numbers_dictionary = {}
        for coordinate in self.unchecked_blocks:
            numbers_dictionary[coordinate] = self.servant.get_real_block_value(
                coordinate)
            unrevealed_blocks = self.servant.get_unrevealed_blocks(coordinate)
            blocks_to_guess.update(unrevealed_blocks)
        # self.servant.custom_pretty_print_field(self.exposed_field, blocks_to_guess)
        self.semi_solver = MineSemiSolver(blocks_to_guess, numbers_dictionary,
                                          self.rows, self.columns)
        self.semi_solver.choose()
Exemplo n.º 2
0
    def probability_guesser(self):
        """

        :return:
        """
        # Get all unrevealed blocks that touch unchecked blocks
        blocks_to_guess = set([])
        numbers_dictionary = {}
        for coordinate in self.unchecked_blocks:
            numbers_dictionary[coordinate] = self.servant.get_real_block_value(coordinate)
            unrevealed_blocks = self.servant.get_unrevealed_blocks(coordinate)
            blocks_to_guess.update(unrevealed_blocks)
        # self.servant.custom_pretty_print_field(self.exposed_field, blocks_to_guess)
        self.semi_solver = MineSemiSolver(blocks_to_guess, numbers_dictionary, self.rows, self.columns)
        self.semi_solver.choose()
Exemplo n.º 3
0
class MineSolver:
    """
    Solves Minesweeper by running through a few algorithms:
    Flag/reveal
    Confined Mine
    Shared Mine
    """

    def __init__(self, load_game=None):
        self.rows = 16
        self.columns = 30
        self.num_mines = 99
        if load_game is None:
            self.mine = Minesweeper(self.rows, self.columns, self.num_mines, gui=False)
        else:
            self.mine = Minesweeper.load_state(load_game)
        self.servant = MineServant(self.mine)
        self.exposed_indices = self.mine.exposed_field
        # Move these to self.exposed_field
        self.newly_exposed = []
        # Add block indices to here as they're revealed
        self.unchecked_blocks = []
        # Blocks scheduled to be removed after some processes for loops
        self.blocks_to_remove = set([])
        self.flags_planted = 0
        # Lose/win status. Both start as false naturally
        self.lose = False
        self.win = False
        self.semi_solver = None

    def reveal_squares(self, coordinate):
        """
        Calls the Minesweeper button_reveal function so progress can be tracked with the GUI.
        :param coordinate:
        :return:
        """
        for coord in coordinate:
            self.lose, self.newly_exposed = self.mine.button_reveal(None, coord)
            self.unchecked_blocks.extend(self.newly_exposed)

    def logical_solver(self):
        """
        Process that loops through unchecked blocks and runs the flag/reveal process.
        :return:
        """
        # Will break out if no moves found
        solver_repeat = True
        while solver_repeat:
            # Try the easy stuff
            solver_repeat = self.flag_reveal_loop()
            # Now try the hard stuff
            for coordinate in self.unchecked_blocks:
                unrevealed = self.servant.get_unrevealed_blocks(coordinate)
                if unrevealed:
                    area_reveal, area_flag = self.confined_mine_process(coordinate, unrevealed)
                    if self.lose:
                        print "Somehow we lost?! It's your fault."
                        return
                    # Break out of hard stuff and go to flag/reveal
                    if area_reveal or area_flag:
                        solver_repeat = True
                        break
                    # Check for a shared mine
                    shared_reveal, shared_flag = self.shared_mine_process(coordinate)
                    if self.lose:
                        print "Somehow we lost?! It's your fault."
                        return
                    if shared_reveal or shared_flag:
                        solver_repeat = True
                        break
                # Schedule block for deletion after for loop.
                else:
                    self.blocks_to_remove.add(coordinate)
            if self.blocks_to_remove:
                self.remove_checked_blocks()
        print "Out of moves. Full field:"
        # Quasi pretty-prints the field for the console.
        self.servant.pretty_print_field()
        if self.win:
            print "You won, because you're the best maybe."

    def probability_guesser(self):
        """

        :return:
        """
        # Get all unrevealed blocks that touch unchecked blocks
        blocks_to_guess = set([])
        numbers_dictionary = {}
        for coordinate in self.unchecked_blocks:
            numbers_dictionary[coordinate] = self.servant.get_real_block_value(coordinate)
            unrevealed_blocks = self.servant.get_unrevealed_blocks(coordinate)
            blocks_to_guess.update(unrevealed_blocks)
        # self.servant.custom_pretty_print_field(self.exposed_field, blocks_to_guess)
        self.semi_solver = MineSemiSolver(blocks_to_guess, numbers_dictionary, self.rows, self.columns)
        self.semi_solver.choose()
        # self.servant.custom_pretty_print_field(self.exposed_field, unrevealed=blocks_to_guess)

    def remove_checked_blocks(self):
        """
        Removes self.blocks_to_remove from self.exposed_field.
        :return:
        """
        for block in self.blocks_to_remove:
            self.unchecked_blocks.remove(block)
        self.blocks_to_remove.clear()

    def flag_reveal_loop(self):
        """
        A loop to call flag_reveal_process in an efficient manner.
        :return:
        """
        solver_repeat = False
        flag_reveal_repeat = True
        # Do the easy stuff first
        while flag_reveal_repeat:
            # Will break out if no flag or reveal
            flag_reveal_repeat = False
            for coordinate in self.unchecked_blocks:
                # Check if there are any unrevealed blocks
                unrevealed = self.servant.get_unrevealed_blocks(coordinate)
                if unrevealed:
                    reveal, flag = self.flag_reveal_process(coordinate, unrevealed)
                    # If it hits even once, repeat flag/reveal
                    if reveal or flag:
                        flag_reveal_repeat = True
                    if self.lose:
                        print "Somehow we lost?! It's your fault."
                        return
                # If not, schedule block for deletion after for loop.
                else:
                    self.blocks_to_remove.add(coordinate)
            # Remove blocks before moving on
            if self.blocks_to_remove:
                self.remove_checked_blocks()
            if self.win:
                solver_repeat = False
                break
        return solver_repeat

    def flag_reveal_process(self, coordinate, unrevealed):
        """
        Main process in which unrevealed blocks are found to reveal or flag.
        :param coordinate:
        :return:
        """
        reveal = False
        flag = False
        num_unrevealed = len(unrevealed)
        real_block_value = self.servant.get_real_block_value(coordinate)
        # All mines accounted for. Reveal rest
        if real_block_value == 0:
            self.reveal_squares(unrevealed)
            self.blocks_to_remove.add(coordinate)
            reveal = True
        # All unrevealed are mines. Flag them
        elif real_block_value == num_unrevealed:
            for coord in unrevealed:
                self.win = self.mine.button_flag(None, coord)
                self.flags_planted += 1
            self.blocks_to_remove.add(coordinate)
            flag = True
        return reveal, flag

    def confined_mine_process(self, coordinate, unrevealed):
        """
        Check if a mine is enclosed in an area, and if surrounding blocks can be flagged or
        revealed.
        :param coordinate:
        :return:
        """
        reveal = False
        flag = False
        mines_in_area = self.servant.get_real_block_value(coordinate)
        # starts with first block, then whittles down
        similar_neighbors = set(self.servant.get_exposed_neighbor_coords(unrevealed[0]))
        for block in unrevealed[1:]:
            # gets the neighbors of the next block
            block_neighbors = self.servant.get_exposed_neighbor_coords(block)
            similar_neighbors.intersection_update(block_neighbors)
        # Now we have a list of shared neighbors. We need to check them all.
        for neighbor in similar_neighbors:
            real_block_value = self.servant.get_real_block_value(neighbor)
            # starts as full
            blocks_out_of_area = set(self.servant.get_unrevealed_blocks(neighbor))
            # Gets rid of blocks in unrevealed
            blocks_out_of_area.difference_update(unrevealed)
            num_outside = len(blocks_out_of_area)
            if num_outside > 0:
                # Flag blocks outside of area.
                if real_block_value == num_outside + mines_in_area:
                    for block in blocks_out_of_area:
                        self.win = self.mine.button_flag(None, block)
                        self.flags_planted += 1
                    flag = True
                # Reveal blocks outside area
                if real_block_value == mines_in_area:
                    self.reveal_squares(blocks_out_of_area)
                    reveal = True
        return reveal, flag

    def shared_mine_process(self, coordinate):
        """
        Loop through all neighbors and check if they share mines.
        :return:
        """
        flag = False
        reveal = False
        neighbor_blocks = self.servant.get_neighbor_blocks(coordinate)
        real_block_value = self.servant.get_real_block_value(coordinate)
        # Loops through all neighbors
        for neighbor in neighbor_blocks:
            # Don't do checked neighbors
            if neighbor not in self.unchecked_blocks:
                continue
            # Find shared unrevealed blocks
            blocks_unrevealed = set(self.servant.get_unrevealed_blocks(coordinate))
            neighbor_unrevealed = set(self.servant.get_unrevealed_blocks(neighbor))
            # Get all unrevealed blocks shared by the neighbors
            shared_unrevealed = blocks_unrevealed.intersection(neighbor_unrevealed)
            num_shared = len(shared_unrevealed)
            neighbor_real_block_value = self.servant.get_real_block_value(neighbor)
            possible_area_mines = min(real_block_value, neighbor_real_block_value, num_shared)
            neighbors_outside_area = len(neighbor_unrevealed) - num_shared
            if neighbors_outside_area > 0 and \
                    neighbor_real_block_value == neighbors_outside_area + possible_area_mines:
                # Flag neighbor blocks not shared with coordinate
                for block in neighbor_unrevealed.difference(blocks_unrevealed):
                    self.win = self.mine.button_flag(None, block)
                    self.flags_planted += 1
                flag = True
                # Check if the original block can reveal things.
                if real_block_value == possible_area_mines:
                    # Reveal blocks not shared with neighbor
                    self.reveal_squares(blocks_unrevealed.difference(neighbor_unrevealed))
                    reveal = True
        return reveal, flag
Exemplo n.º 4
0
class MineSolver:
    """
    Solves Minesweeper by running through a few algorithms:
    Flag/reveal
    Confined Mine
    Shared Mine
    """
    def __init__(self, load_game=None):
        self.rows = 16
        self.columns = 30
        self.num_mines = 99
        if load_game is None:
            self.mine = Minesweeper(self.rows,
                                    self.columns,
                                    self.num_mines,
                                    gui=False)
        else:
            self.mine = Minesweeper.load_state(load_game)
        self.servant = MineServant(self.mine)
        self.exposed_indices = self.mine.exposed_field
        # Move these to self.exposed_field
        self.newly_exposed = []
        # Add block indices to here as they're revealed
        self.unchecked_blocks = []
        # Blocks scheduled to be removed after some processes for loops
        self.blocks_to_remove = set([])
        self.flags_planted = 0
        # Lose/win status. Both start as false naturally
        self.lose = False
        self.win = False
        self.semi_solver = None

    def reveal_squares(self, coordinate):
        """
        Calls the Minesweeper button_reveal function so progress can be tracked with the GUI.
        :param coordinate:
        :return:
        """
        for coord in coordinate:
            self.lose, self.newly_exposed = self.mine.button_reveal(
                None, coord)
            self.unchecked_blocks.extend(self.newly_exposed)

    def logical_solver(self):
        """
        Process that loops through unchecked blocks and runs the flag/reveal process.
        :return:
        """
        # Will break out if no moves found
        solver_repeat = True
        while solver_repeat:
            # Try the easy stuff
            solver_repeat = self.flag_reveal_loop()
            # Now try the hard stuff
            for coordinate in self.unchecked_blocks:
                unrevealed = self.servant.get_unrevealed_blocks(coordinate)
                if unrevealed:
                    area_reveal, area_flag = self.confined_mine_process(
                        coordinate, unrevealed)
                    if self.lose:
                        print "Somehow we lost?! It's your fault."
                        return
                    # Break out of hard stuff and go to flag/reveal
                    if area_reveal or area_flag:
                        solver_repeat = True
                        break
                    # Check for a shared mine
                    shared_reveal, shared_flag = self.shared_mine_process(
                        coordinate)
                    if self.lose:
                        print "Somehow we lost?! It's your fault."
                        return
                    if shared_reveal or shared_flag:
                        solver_repeat = True
                        break
                # Schedule block for deletion after for loop.
                else:
                    self.blocks_to_remove.add(coordinate)
            if self.blocks_to_remove:
                self.remove_checked_blocks()
        print "Out of moves. Full field:"
        # Quasi pretty-prints the field for the console.
        self.servant.pretty_print_field()
        if self.win:
            print "You won, because you're the best maybe."

    def probability_guesser(self):
        """

        :return:
        """
        # Get all unrevealed blocks that touch unchecked blocks
        blocks_to_guess = set([])
        numbers_dictionary = {}
        for coordinate in self.unchecked_blocks:
            numbers_dictionary[coordinate] = self.servant.get_real_block_value(
                coordinate)
            unrevealed_blocks = self.servant.get_unrevealed_blocks(coordinate)
            blocks_to_guess.update(unrevealed_blocks)
        # self.servant.custom_pretty_print_field(self.exposed_field, blocks_to_guess)
        self.semi_solver = MineSemiSolver(blocks_to_guess, numbers_dictionary,
                                          self.rows, self.columns)
        self.semi_solver.choose()
        # self.servant.custom_pretty_print_field(self.exposed_field, unrevealed=blocks_to_guess)

    def remove_checked_blocks(self):
        """
        Removes self.blocks_to_remove from self.exposed_field.
        :return:
        """
        for block in self.blocks_to_remove:
            self.unchecked_blocks.remove(block)
        self.blocks_to_remove.clear()

    def flag_reveal_loop(self):
        """
        A loop to call flag_reveal_process in an efficient manner.
        :return:
        """
        solver_repeat = False
        flag_reveal_repeat = True
        # Do the easy stuff first
        while flag_reveal_repeat:
            # Will break out if no flag or reveal
            flag_reveal_repeat = False
            for coordinate in self.unchecked_blocks:
                # Check if there are any unrevealed blocks
                unrevealed = self.servant.get_unrevealed_blocks(coordinate)
                if unrevealed:
                    reveal, flag = self.flag_reveal_process(
                        coordinate, unrevealed)
                    # If it hits even once, repeat flag/reveal
                    if reveal or flag:
                        flag_reveal_repeat = True
                    if self.lose:
                        print "Somehow we lost?! It's your fault."
                        return
                # If not, schedule block for deletion after for loop.
                else:
                    self.blocks_to_remove.add(coordinate)
            # Remove blocks before moving on
            if self.blocks_to_remove:
                self.remove_checked_blocks()
            if self.win:
                solver_repeat = False
                break
        return solver_repeat

    def flag_reveal_process(self, coordinate, unrevealed):
        """
        Main process in which unrevealed blocks are found to reveal or flag.
        :param coordinate:
        :return:
        """
        reveal = False
        flag = False
        num_unrevealed = len(unrevealed)
        real_block_value = self.servant.get_real_block_value(coordinate)
        # All mines accounted for. Reveal rest
        if real_block_value == 0:
            self.reveal_squares(unrevealed)
            self.blocks_to_remove.add(coordinate)
            reveal = True
        # All unrevealed are mines. Flag them
        elif real_block_value == num_unrevealed:
            for coord in unrevealed:
                self.win = self.mine.button_flag(None, coord)
                self.flags_planted += 1
            self.blocks_to_remove.add(coordinate)
            flag = True
        return reveal, flag

    def confined_mine_process(self, coordinate, unrevealed):
        """
        Check if a mine is enclosed in an area, and if surrounding blocks can be flagged or
        revealed.
        :param coordinate:
        :return:
        """
        reveal = False
        flag = False
        mines_in_area = self.servant.get_real_block_value(coordinate)
        # starts with first block, then whittles down
        similar_neighbors = set(
            self.servant.get_exposed_neighbor_coords(unrevealed[0]))
        for block in unrevealed[1:]:
            # gets the neighbors of the next block
            block_neighbors = self.servant.get_exposed_neighbor_coords(block)
            similar_neighbors.intersection_update(block_neighbors)
        # Now we have a list of shared neighbors. We need to check them all.
        for neighbor in similar_neighbors:
            real_block_value = self.servant.get_real_block_value(neighbor)
            # starts as full
            blocks_out_of_area = set(
                self.servant.get_unrevealed_blocks(neighbor))
            # Gets rid of blocks in unrevealed
            blocks_out_of_area.difference_update(unrevealed)
            num_outside = len(blocks_out_of_area)
            if num_outside > 0:
                # Flag blocks outside of area.
                if real_block_value == num_outside + mines_in_area:
                    for block in blocks_out_of_area:
                        self.win = self.mine.button_flag(None, block)
                        self.flags_planted += 1
                    flag = True
                # Reveal blocks outside area
                if real_block_value == mines_in_area:
                    self.reveal_squares(blocks_out_of_area)
                    reveal = True
        return reveal, flag

    def shared_mine_process(self, coordinate):
        """
        Loop through all neighbors and check if they share mines.
        :return:
        """
        flag = False
        reveal = False
        neighbor_blocks = self.servant.get_neighbor_blocks(coordinate)
        real_block_value = self.servant.get_real_block_value(coordinate)
        # Loops through all neighbors
        for neighbor in neighbor_blocks:
            # Don't do checked neighbors
            if neighbor not in self.unchecked_blocks:
                continue
            # Find shared unrevealed blocks
            blocks_unrevealed = set(
                self.servant.get_unrevealed_blocks(coordinate))
            neighbor_unrevealed = set(
                self.servant.get_unrevealed_blocks(neighbor))
            # Get all unrevealed blocks shared by the neighbors
            shared_unrevealed = blocks_unrevealed.intersection(
                neighbor_unrevealed)
            num_shared = len(shared_unrevealed)
            neighbor_real_block_value = self.servant.get_real_block_value(
                neighbor)
            possible_area_mines = min(real_block_value,
                                      neighbor_real_block_value, num_shared)
            neighbors_outside_area = len(neighbor_unrevealed) - num_shared
            if neighbors_outside_area > 0 and \
                    neighbor_real_block_value == neighbors_outside_area + possible_area_mines:
                # Flag neighbor blocks not shared with coordinate
                for block in neighbor_unrevealed.difference(blocks_unrevealed):
                    self.win = self.mine.button_flag(None, block)
                    self.flags_planted += 1
                flag = True
                # Check if the original block can reveal things.
                if real_block_value == possible_area_mines:
                    # Reveal blocks not shared with neighbor
                    self.reveal_squares(
                        blocks_unrevealed.difference(neighbor_unrevealed))
                    reveal = True
        return reveal, flag