class TestGame(unittest.TestCase): def setUp(self): self.game = Game() self.game_with_full_board = Game(225, 15) self.game_with_empty_board = Game(0, 15) def test_board_is_correct_width(self): self.assertEqual(self.game.size, len(self.game.board[0])) def test_board_is_correct_hight(self): self.assertEqual(self.game.size, len(self.game.board)) def test_board_has_correct_amount_of_bombs(self): bomb_count = 0 for row in self.game.board: for block in row: if block.bomb: bomb_count += 1 self.assertEqual(self.game.bombs, bomb_count) def test_handles_rightclick(self): self.game.handle_rightclick_on_board(4, 6) self.assertEqual(True, self.game.board[6][4].flag) def test_handles_leftclick_on_board_if_bomb(self): self.assertEqual( self.game_with_full_board.handle_leftclick_on_board(0, 6), False) def test_count_bombs(self): self.game_with_full_board._count_bombs_around_block(0, 0) self.assertEqual(self.game_with_full_board.board[0][0].bombs_around, 3) self.game_with_full_board._count_bombs_around_block(14, 0) self.assertEqual(self.game_with_full_board.board[0][14].bombs_around, 3) self.game_with_full_board._count_bombs_around_block(0, 14) self.assertEqual(self.game_with_full_board.board[14][0].bombs_around, 3) self.game_with_full_board._count_bombs_around_block(14, 14) self.assertEqual(self.game_with_full_board.board[14][14].bombs_around, 3) def test_handles_leftclick_on_board_if_not_bomb(self): self.assertEqual( self.game_with_empty_board.handle_leftclick_on_board(5, 7), True) def test_cant_open_flagged_block(self): self.game.handle_rightclick_on_board(4, 6) self.game.handle_leftclick_on_board(4, 6) self.assertEqual(self.game.board[6][4].open, False) def test_wont_open_neighbours_if_bomb_neighbour(self): self.game.board[6][5].bomb = True self.game.handle_leftclick_on_board(4, 6) self.assertEqual(self.game.board[6][3].open, False) def test_count_bomb_as_flagged_if_rightclikked(self): self.game_with_full_board.handle_rightclick_on_board(4, 6) self.assertEqual(self.game_with_full_board.bombs_without_flag, 224) def test_count_bomb_as_not_flagged_if_rightclikked(self): self.game_with_full_board.handle_rightclick_on_board(4, 6) self.game_with_full_board.handle_rightclick_on_board(4, 6) self.assertEqual(self.game_with_full_board.bombs_without_flag, 225)
class Ui: def __init__(self): pygame.init() self.font = pygame.font.SysFont("Arial", 24) self.font2 = pygame.font.SysFont("Arial", 19) self.screen = pygame.display.set_mode((640, 480)) pygame.display.set_caption("Minesweeper") self.view = "menu" self.game = None self.block_size = 20 self.game_won = None self.repo = game_repo self._run() def _run(self): while True: self._draw_view() self._handle_events() def _handle_events(self): for event in pygame.event.get(): if event.type == pygame.QUIT: exit() if self.view == "menu": self._handle_events_in_menu(event) elif self.view == "game": self._handle_events_in_game(event) elif self.view == "stats": self._handle_events_in_stats(event) elif self.view == "game_over": self._handle_events_in_game_over(event) def _handle_events_in_menu(self, event): if event.type == pygame.MOUSEBUTTONDOWN: if event.button == 1: if event.pos[0] > 273 and event.pos[0] < 383 and event.pos[ 1] > 106 and event.pos[1] < 122: self.view = "game" self.game = Game() elif event.pos[0] > 270 and event.pos[0] < 325 and event.pos[ 1] > 155 and event.pos[1] < 173: self.view = "stats" def _handle_events_in_game(self, event): if event.type == pygame.MOUSEBUTTONDOWN: if event.button == 1: if event.pos[0] > 5 and event.pos[0] < 55 and event.pos[ 1] > 10 and event.pos[1] < 33: self.view = "menu" elif event.pos[0] > 2 * self.block_size and event.pos[ 0] < 300 + (2 * self.block_size) and event.pos[ 1] > 4 * self.block_size and event.pos[1] < ( 4 * self.block_size) + 300: x = event.pos[0] - 20 - self.block_size y = event.pos[1] - 60 - self.block_size x = x // 20 y = y // 20 if not self.game.handle_leftclick_on_board(x, y): self.game_won = False self.view = "game_over" elif event.button == 3: if event.pos[0] > 2 * self.block_size and event.pos[ 0] < 300 + (2 * self.block_size) and event.pos[ 1] > 4 * self.block_size and event.pos[1] < ( 4 * self.block_size) + 300: x = event.pos[0] - 20 - self.block_size y = event.pos[1] - 60 - self.block_size x = x // 20 y = y // 20 self.game.handle_rightclick_on_board(x, y) if self.game.bombs_without_flag == 0: self.game_won = True self.view = "game_over" def _draw_view(self): self.screen.fill((255, 255, 255)) if self.view == "menu": self._draw_menu() elif self.view == "game": self._draw_game() elif self.view == "stats": self._draw_stats() elif self.view == "game_over": self._draw_game_over() pygame.display.flip() def _draw_game(self): self._draw_grid() self._draw_board() text_minesweeper = self.font.render("Minesweeper", True, (0, 0, 0)) self.screen.blit(text_minesweeper, (280, 10)) text_back = self.font.render("Back", True, (0, 0, 0)) self.screen.blit(text_back, (5, 10)) def _draw_grid(self): for x in range(2 * self.block_size, 300 + (2 * self.block_size), self.block_size): for y in range(4 * self.block_size, (4 * self.block_size) + 300, self.block_size): rect = pygame.Rect(x, y, self.block_size, self.block_size) pygame.draw.rect(self.screen, (127, 127, 127), rect, 1) def _draw_board(self): for i in range(self.game.size): for j in range(self.game.size): if self.game.board[i][j].flag: flag = self.font2.render("F", True, (0, 0, 0)) self.screen.blit( flag, (20 + self.block_size + (j * self.block_size), 60 + self.block_size + (i * self.block_size))) elif self.game.board[i][j].open: num = self.font2.render( str(self.game.board[i][j].bombs_around), True, (0, 0, 0)) self.screen.blit( num, (20 + self.block_size + (j * self.block_size), 60 + self.block_size + (i * self.block_size))) def _draw_menu(self): text_new_game = self.font.render("New game", True, (0, 0, 0)) self.screen.blit(text_new_game, (270, 100)) text_stats = self.font.render("Stats", True, (0, 0, 0)) self.screen.blit(text_stats, (270, 150)) def _draw_stats(self): text_back = self.font.render("Back", True, (0, 0, 0)) self.screen.blit(text_back, (5, 10)) wins = self.repo.get_win_amound() loses = self.repo.get_lost_amound() text_wins_loses = self.font.render("won/lost", True, (0, 0, 0)) self.screen.blit(text_wins_loses, (270, 100)) color = (0, 0, 0) # white if wins > loses: color = (0, 255, 0) # green elif wins < loses: color = (255, 0, 0) # red text_wins_loses_amount = self.font.render(f"{wins}/{loses}", True, color) self.screen.blit(text_wins_loses_amount, (270, 150)) def _handle_events_in_stats(self, event): if event.type == pygame.MOUSEBUTTONDOWN: if event.button == 1: if event.pos[0] > 5 and event.pos[0] < 55 and event.pos[ 1] > 10 and event.pos[1] < 33: self.view = "menu" def _draw_game_over(self): if self.game_won: text_game_over = self.font.render("You won", True, (0, 0, 0)) elif not self.game_won: text_game_over = self.font.render("You lost", True, (0, 0, 0)) self.screen.blit(text_game_over, (270, 100)) def _handle_events_in_game_over(self, event): timestamp = datetime.now() if self.game_won: win_or_loss = "Win" else: win_or_loss = "Loss" self.repo.add_game(timestamp, win_or_loss) sleep(4) self.view = "menu"