# Draw board cells = [] for i inrange(HEIGHT): row = [] for j inrange(WIDTH):
# Draw rectangle for cell rect = pygame.Rect( board_origin[0] + j * cell_size, board_origin[1] + i * cell_size, cell_size, cell_size ) pygame.draw.rect(screen, GRAY, rect) pygame.draw.rect(screen, WHITE, rect, 3)
# Add a mine, flag, or number if needed if game.is_mine((i, j)) and lost: screen.blit(mine, rect) elif (i, j) in flags: screen.blit(flag, rect) elif (i, j) in revealed: neighbors = smallFont.render( str(game.nearby_mines((i, j))), True, BLACK ) neighborsTextRect = neighbors.get_rect() neighborsTextRect.center = rect.center screen.blit(neighbors, neighborsTextRect)
# If AI button clicked, make an AI move if aiButton.collidepoint(mouse) andnot lost: move = ai.make_safe_move() if move isNone: move = ai.make_random_move() if move isNone: flags = ai.mines.copy() print("No moves left to make.") else: print("No known safe moves, AI making random move.") else: print("AI making safe move.") time.sleep(0.2)
# use flags to mark mines for i inrange(HEIGHT): for j inrange(WIDTH): if (i, j) in ai.mines: flags.add((i, j))
classMinesweeper(): """ Minesweeper game representation """
def__init__(self, height=8, width=8, mines=8):
# Set initial width, height, and number of mines self.height = height self.width = width self.mines = set()
# Initialize an empty field with no mines self.board = [] for i inrange(self.height): row = [] for j inrange(self.width): row.append(False) self.board.append(row)
classSentence(): """ Logical statement about a Minesweeper game A sentence consists of a set of board cells, and a count of the number of those cells which are mines. """
...
defknown_mines(self): """ Returns the set of all cells in self.cells known to be mines. """ iflen(self.cells) == self.count: return self.cells returnset()
defknown_safes(self): """ Returns the set of all cells in self.cells known to be safe. """ if self.count == 0: return self.cells returnset()
defmark_mine(self, cell): """ Updates internal knowledge representation given the fact that a cell is known to be a mine. """ if cell in self.cells: self.cells.remove(cell) self.count -= 1
defmark_safe(self, cell): """ Updates internal knowledge representation given the fact that a cell is known to be safe. """ if cell in self.cells: self.cells.remove(cell)
classMinesweeperAI(): """ Minesweeper game player """
def__init__(self, height=8, width=8):
# Set initial height and width self.height = height self.width = width
# Keep track of which cells have been clicked on self.moves_made = set()
# Keep track of cells known to be safe or mines self.mines = set() self.safes = set()
# List of sentences about the game known to be true self.knowledge = []
defmark_mine(self, cell): """ Marks a cell as a mine, and updates all knowledge to mark that cell as a mine as well. """ self.mines.add(cell) for sentence in self.knowledge: sentence.mark_mine(cell)
defmark_safe(self, cell): """ Marks a cell as safe, and updates all knowledge to mark that cell as safe as well. """ self.safes.add(cell) for sentence in self.knowledge: sentence.mark_safe(cell)
...
defmake_safe_move(self): """ Returns a safe cell to choose on the Minesweeper board. The move must be known to be safe, and not already a move that has been made. This function may use the knowledge in self.mines, self.safes and self.moves_made, but should not modify any of those values. """ for safe_cell in self.safes: if safe_cell notin self.moves_made: return safe_cell returnNone
defmake_random_move(self): """ Returns a move to make on the Minesweeper board. Should choose randomly among cells that: 1) have not already been chosen, and 2) are not known to be mines """ possible_moves = set() for i inrange(self.height): for j inrange(self.width): if (i, j) notin self.moves_made and (i, j) notin self.mines: possible_moves.add((i, j)) if possible_moves: return random.choice(list(possible_moves)) returnNone
defadd_knowledge(self, cell, count): """ Called when the Minesweeper board tells us, for a given safe cell, how many neighboring cells have mines in them. """
self.moves_made.add(cell) self.mark_safe(cell)
# Add new sentence to knowledge base new_sentence_cells = set() for i inrange(cell[0] - 1, cell[0] + 2): for j inrange(cell[1] - 1, cell[1] + 2): if0 <= i < self.height and0 <= j < self.width: if (i, j) in self.mines: count -= 1 elif (i, j) notin self.safes: new_sentence_cells.add((i, j)) new_sentence = Sentence(new_sentence_cells, count) self.knowledge.append(new_sentence)
# Mark additional cells as safe or as mines for sentence in self.knowledge: for safe_cell in sentence.known_safes(): self.safes.add(safe_cell) for mine_cell in sentence.known_mines(): self.mines.add(mine_cell)
# Add new sentences to knowledge base for sentence1, sentence2 in itertools.combinations(self.knowledge, 2): if sentence1.cells.issubset(sentence2.cells): new_sentence = Sentence(sentence2.cells - sentence1.cells, sentence2.count - sentence1.count) elif sentence2.cells.issubset(sentence1.cells): new_sentence = Sentence(sentence1.cells - sentence2.cells, sentence1.count - sentence2.count) if new_sentence notin self.knowledge: self.knowledge.append(new_sentence)
# Remove empty sentences self.knowledge = [sentence for sentence in self.knowledge if sentence.cells]
# Mark additional cells as safe or as mines for sentence in self.knowledge: for safe_cell in sentence.known_safes(): self.safes.add(safe_cell) for mine_cell in sentence.known_mines(): self.mines.add(mine_cell)
# Mark safe cells and mines for safe_cell in self.safes: self.mark_safe(safe_cell) for mine_cell in self.mines: self.mark_mine(mine_cell)