def main_loop(): # Obtain the width and height of the screen. width = field_width * tile_width + 10 height = field_height * tile_height + digit_height + 15 smiley_offset = (width // 2 - digit_height // 2, 5) win = pygame.display.set_mode((width, height)) pygame.display.set_caption('Minesweeper') clock = pygame.time.Clock() minesweeper = MineSweeper(field_width, field_height, field_mines) steps = solver(minesweeper) run = True while run: for event in pygame.event.get(): if (event.type == pygame.QUIT or (event.type == pygame.KEYDOWN and event.key in [pygame.K_q, pygame.K_ESCAPE])): run = False # Handle mouse clicks. if handle_clicks(event, minesweeper, offset=(5, digit_height + 10)): # On user input, just in case reset the solver. steps = solver(minesweeper) if handle_click_smiley(event, minesweeper, offset=smiley_offset): # On reset, create a new solver. steps = solver(minesweeper) if event.type == pygame.KEYDOWN and event.key == pygame.K_r: # Reset the minesweeper. minesweeper.reset() print('RESET') steps = solver(minesweeper) if event.type == pygame.KEYDOWN and event.key == pygame.K_n: # Try twice if in case generator was exhausted in which case we use a newer one. # If solver can't solve it in second try don't simply keep calling it. tries = 0 while tries <= 1: try: # Obtain the step from the solver. position, operation = next(steps) if operation == MARK: print(f'[AI] MARK {position[0]}, {position[1]}') minesweeper.toggle(position, force_mark=True) elif operation == UNCOVER: print(f'[AI] UNCOVER {position[0]}, {position[1]}') minesweeper.uncover(position) break except StopIteration: # reset the solver in case previous one exhausted and check if it can solve steps = solver(minesweeper) tries += 1 win.fill((255, 255, 255)) # Render the time and number of mines. count_surf = number_surface(minesweeper.pending_mines()) win.blit(count_surf, (5, 5)) time_surf = number_surface(minesweeper.time_progressed()) time_rect = time_surf.get_rect() win.blit(time_surf, (width - time_rect.width - 5, 5)) # Render the smiley draw_smiley(win, minesweeper, offset=smiley_offset) # Render the minesweeper field draw_minesweeper(win, minesweeper, offset=(5, digit_height + 10)) pygame.display.update() clock.tick(60)
class QMineSweeper(QWidget): class QTile(QPushButton): def __init__(self, mineSweeper: 'QMineSweeper', tile: MineSweeper.Tile): super(QMineSweeper.QTile, self).__init__() self.setFocusPolicy(Qt.NoFocus) self.setContextMenuPolicy(Qt.CustomContextMenu) self.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) self.mineSweeper = mineSweeper self.marked = False self.tile = tile def leftClick(self): if self.marked: return self.tile.reveal() self.mineSweeper.score() self.repaint() def rightClick(self): self.marked = not self.marked self.refresh() def resizeEvent(self, resizeEvent: QResizeEvent): font = self.font() font.setBold(True) font.setPixelSize(round(0.50 * min(self.width(), self.height()))) self.setFont(font) def refresh(self): self.setEnabled(not self.tile.revealed) text = "★" if self.marked else str(self.tile) self.setText(text) def sizeHint(self) -> QSize: return QSize(40, 40) def __init__(self, size: int): super(QMineSweeper, self).__init__() self.size = size self.mineSweeper = MineSweeper(self.size, 0.10) self.initUI() self.show() def initUI(self): self.setWindowTitle(self.tr("Minesweeper")) layout = QGridLayout() layout.setSpacing(5) self.setLayout(layout) for tile in self.mineSweeper: qTile = QMineSweeper.QTile(self, tile) layout.addWidget(qTile, tile.row, tile.column) qTile.clicked.connect(qTile.leftClick) qTile.customContextMenuRequested.connect(qTile.rightClick) tile.delegate = qTile def score(self): score = self.mineSweeper.score() if score is not None: self.mineSweeper.reveal() if score == +1: QMessageBox.information(self, self.tr("Victory!"), self.tr("You won :)"), QMessageBox.Ok) if score == -1: QMessageBox.critical(self, self.tr("Defeat!"), self.tr("You lost :("), QMessageBox.Ok) for tile in self.mineSweeper: tile.delegate.marked = False self.mineSweeper.reset() def sizeHint(self) -> QSize: return QSize(300, 300)