From 659b08b0074454f8b6e790ceaac809bc0b769111 Mon Sep 17 00:00:00 2001 From: ZennilGreenherald <144579645+ZennilGreenherald@users.noreply.github.com> Date: Fri, 14 Feb 2025 22:28:29 -0800 Subject: [PATCH 01/12] Update minesweeperLVLs.py better mine placement, etc. --- minesweeperLVLs.py | 206 +++++++++++++++++++++------------------------ 1 file changed, 98 insertions(+), 108 deletions(-) diff --git a/minesweeperLVLs.py b/minesweeperLVLs.py index 7a3718f..ea7c526 100644 --- a/minesweeperLVLs.py +++ b/minesweeperLVLs.py @@ -9,11 +9,32 @@ class Color: YELLOW = "\033[33m" END = "\033[0m" +levels = ["beginner", "intermediate", "advanced", "custom"] + +# beginner = 9x9 w/ 10 mines +# intermediate = 16x16 w/ 40 mines +# advanced = 30x16 w/ 99 mines +board_size_settings = [ + { + 'board_rows': 9, + 'board_cols': 9, + 'num_mines': 10 + }, { + 'board_rows': 16, + 'board_cols': 16, + 'num_mines': 40 + }, { + 'board_rows': 16, + 'board_cols': 30, + 'num_mines': 99 + } +] + class Minesweeper: # build board and define how many mines/level def __init__(self): self.dict_board = {} - self.dict_space = {} + self.mines_and_nums = {} self.count_mines = 0 self.count_flags = 0 self.board_rows = 0 @@ -21,81 +42,67 @@ def __init__(self): self.num_mines = 0 def get_level(self): - choice = input("Please choose a level (Beginner, Intermediate, Advanced, Custom): ").lower() - return choice - - def define_level(self): while True: - level = ["beginner", "intermediate", "advanced", "custom"] - choice = self.get_level() - if choice in level: - # beginner = 9x9 w/ 10 mines - if choice == level[0]: - self.board_rows = 9 - self.board_cols = 9 - self.num_mines = 10 - break - # intermediate = 16x16 w/ 40 mines - elif choice == level[1]: - self.board_rows = 16 - self.board_cols = 16 - self.num_mines = 40 - break - # advanced = 30x16 w/ 99 mines - elif choice == level[2]: - self.board_rows = 16 - self.board_cols = 30 - self.num_mines = 99 - break - # custom = user inputs their custom level - elif choice == level[3]: - while True: - try: - ### This causes the program to go on forever placing bombs :( - self.board_rows = int(input("Please enter a number 1-80 for rows: ")) - self.board_cols = int(input("Please enter a number 1-80 for columns: ")) - self.num_mines = int(input("Please enter a number 1-99 for bombs: ")) - if 0 < self.board_rows <= 80 and 0 < self.board_cols <= 80 and 0 < self.num_mines <= 99 and self.num_mines < (self.board_rows * self.board_cols) / 2: - break - else: - print("Can't make a board like that! D:") - except: - print("Can't make a board like that! D:") - break + choice = input("Please choose a level (Beginner, Intermediate, Advanced, Custom, Quit): ").lower() + if choice == 'quit': + raise SystemExit() + elif choice in levels: + return choice else: print("What kind of level is that?!?!?! >:O") + def define_level(self): + choice = self.get_level() + if choice in levels[:3]: + i = levels.index(choice) + self.board_rows = board_size_settings[i]['board_rows'] + self.board_cols = board_size_settings[i]['board_cols'] + self.num_mines = board_size_settings[i]['num_mines'] + # custom level + else: + while True: + try: + self.board_rows = int(input("Please enter a number 1-80 for rows: ")) + self.board_cols = int(input("Please enter a number 1-80 for columns: ")) + self.num_mines = int(input("Please enter a number 1-99 for bombs: ")) + if 0 < self.board_rows <= 80 and 0 < self.board_cols <= 80 and 0 < self.num_mines <= 99 and self.num_mines < (self.board_rows * self.board_cols) / 2: + break + else: + print("Can't make a board like that! D:") + except: + print("Can't make a board like that! D:") + def make_board(self): - # starts with board being printed in the terminal - # self.board = [["O" for _ in range(self.boardRows)] for _ in range(self.boardCols)] - # for x in self.board: # try to use 2 loops to print without list - # self.gameBoard = " ".join(x) - # print(self.gameBoard) for r in range(self.board_rows): for c in range(self.board_cols): self.dict_board[(r, c)] = "O" - self.countSpaces = (self.board_rows * self.board_cols) + self.countSpaces = self.board_rows * self.board_cols self.print_board() def print_board(self): + print(' ' + ' '.join(str(c) for c in range(self.board_cols))) + print(' ' + '-' * (self.board_cols * 2 + 1)) + for r in range(self.board_rows): + print(r, end = ' | ') for c in range(self.board_cols): print(self.dict_board[(r,c)], end = " ") print() def get_user_move(self): # when coordinate is inputed (row x column) checks the space - self.user = input("Please enter a 'coordinate' to uncover a space or 'X, coordinate' to place or remove a flag: ").upper() - self.user = self.user.translate(str.maketrans(string.punctuation, (" " * len(string.punctuation)))) - self.user = self.user.split() + return (input("Please enter a 'coordinate' to uncover a space or 'X, coordinate' to place or remove a flag: ") + .upper() + .translate(str.maketrans(string.punctuation, (" " * len(string.punctuation)))) + .split()) def make_move(self): while True: - self.get_user_move() + user = self.get_user_move() # determines if the user is inputting a space - if len(self.user) == 2: + if len(user) == 2: try: - self.move = tuple(map(int, self.user)) + self.move = tuple(map(int, user)) if self.move in self.dict_board: self.is_flagging = False break @@ -104,13 +111,13 @@ def make_move(self): except: print("NO! >:O") # determines if a user is inputting a flag - elif len(self.user) == 3 and self.user[0] == "X": + elif len(user) == 3 and user[0] == "X": try: - self.flag = tuple(map(int, self.user[1:])) + self.flag = tuple(map(int, user[1:])) if self.count_mines == 0: print("You really want to place a flag on your first move?") elif self.flag in self.dict_board: - self.place_flag() + self.toggle_flag() self.is_flagging = True break else: @@ -120,7 +127,7 @@ def make_move(self): else: print("Invalid input. Please try again.") - def place_flag(self): + def toggle_flag(self): if self.count_flags <= self.num_mines: if self.dict_board[self.flag] == "O": self.dict_board[self.flag] = f"{Color.RED}X{Color.END}" @@ -134,58 +141,49 @@ def place_flag(self): print("You want to waste flag on a space you already uncovered??? o_O") def place_mines(self): - # check how many mines we have placed - while self.count_mines < self.num_mines: - # randomly place the mines / find coordinates for row and colum - mine_row = random.choice(range(self.board_rows)) - mine_cols = random.choice(range(self.board_cols)) - coor_mine = mine_row, mine_cols - # check if a mine is already there - # if there is a mine already there, pass - if (coor_mine in self.dict_space and self.dict_space[coor_mine] == "*") or coor_mine == self.move: - # print(self.countMines) - pass - # if the no mine / replace the space with mine - # else: - elif coor_mine not in self.dict_space or self.dict_space[coor_mine] != "*": - self.dict_space[coor_mine] = "*" - # if true will add a mine to the counter - self.count_mines += 1 - self.place_nums(mine_row, mine_cols) - - # def printMines(self): - # print(self.dictSpace) + mines_to_place = ['*'] * self.num_mines + [' '] * ((self.board_rows * self.board_cols) - self.num_mines) + random.shuffle(mines_to_place) + for r in range(self.board_rows): + for c in range(self.board_cols): + m = mines_to_place.pop() + if m == '*': + coord = (r, c) + if coord not in self.mines_and_nums or self.mines_and_nums[coord] != "*": + self.mines_and_nums[coord] = "*" + self.place_nums(r, c) + self.count_mines += 1 + + def neighbors(self, row, col): + for r in range(row - 1, row + 2): + for c in range(col - 1, col + 2): + if r >= 0 and c >= 0 and r < self.board_rows and c < self.board_cols and (r != row or c != col): + yield r, c # method will use the coordinates of the mines that are placed def place_nums(self, row, col): # finds coordinate of top left, top center, top right, left side, right side, bottom left, bottom center, bottom right surrounding the mine - spaceList = [(row - 1, col - 1), (row - 1, col), (row - 1, col + 1), (row, col - 1), (row, col + 1), (row + 1, col - 1), (row + 1, col), (row + 1, col + 1)] - # goes through the coordinates one by one - for space in spaceList: - # checks to see if the coordinate is a valid coordinate on the board - skips it if it is not - if space[0] < 0 or space[1] < 0 or space[0] > (self.board_rows - 1) or space[1] > (self.board_cols - 1): - continue + for space in self.neighbors(row, col): # if the coordinate is not in the dictionary yet, adds key and value - if space not in self.dict_space: - self.dict_space[space] = 1 + if space not in self.mines_and_nums: + self.mines_and_nums[space] = 1 # if the coordinate is already a key, increments the value up by 1 - elif space in self.dict_space and self.dict_space[space] != "*": #and self.dictSpace[space] != "M": - self.dict_space[space] += 1 + elif space in self.mines_and_nums and self.mines_and_nums[space] != "*": + self.mines_and_nums[space] += 1 def check_move(self): if self.is_flagging == False: # if mine is there at coordinate - game over if self.dict_board[self.move] == "O": - if self.move in self.dict_space: - if self.dict_space[self.move] != "*": - self.dict_board[self.move] = self.dict_space[self.move] + if self.move in self.mines_and_nums: + if self.mines_and_nums[self.move] != "*": + self.dict_board[self.move] = self.mines_and_nums[self.move] self.countSpaces -= 1 self.print_board() else: - self.dict_board[self.move] = self.dict_space[self.move] + self.dict_board[self.move] = self.mines_and_nums[self.move] self.print_board() print("Game Over!") - exit() + raise SystemExit() else: self.dict_board[self.move] = " " self.countSpaces -= 1 @@ -198,23 +196,21 @@ def check_move(self): def uncover_space(self, row, col): - spaceList = [(row - 1, col - 1), (row - 1, col), (row - 1, col + 1), (row, col - 1), (row, col + 1), (row + 1, col - 1), (row + 1, col), (row + 1, col + 1)] - for space in spaceList: - if space[0] < 0 or space[1] < 0 or space[0] > (self.board_rows - 1) or space[1] > (self.board_cols - 1): - continue + for space in self.neighbors(row, col): if self.dict_board[space] == "O": - if space not in self.dict_space: + if space not in self.mines_and_nums: self.dict_board[space] = " " self.countSpaces -= 1 self.uncover_space(space[0], space[1]) - elif space in self.dict_space and self.dict_space[space] != "*": - self.dict_board[space] = self.dict_space[space] + elif space in self.mines_and_nums and self.mines_and_nums[space] != "*": + self.dict_board[space] = self.mines_and_nums[space] self.countSpaces -= 1 - + def user_win(self): + # when all the blank spaces are uncovered - winner is pronounced! if self.countSpaces == self.num_mines: print("Congrats you won! :D") - exit() + raise SystemExit() def game_play(self): self.user_win() @@ -232,9 +228,3 @@ def start_game(self): minesweeper = Minesweeper() minesweeper.start_game() -# minesweeper.chooseLevel() -# minesweeper.makeBoard() -# minesweeper.gamePlay() - -# print out the board again so user can see what is available -# when all the blank spaces are uncovered - winner is pronounced! \ No newline at end of file From b6384e130df4a8a89d1ce4e1e0c6a75e8ded4a90 Mon Sep 17 00:00:00 2001 From: ZennilGreenherald <144579645+ZennilGreenherald@users.noreply.github.com> Date: Fri, 14 Feb 2025 23:01:41 -0800 Subject: [PATCH 02/12] place_mines called by make_board place_mines called by make_board --- minesweeperLVLs.py | 40 +++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/minesweeperLVLs.py b/minesweeperLVLs.py index ea7c526..2b3a9f3 100644 --- a/minesweeperLVLs.py +++ b/minesweeperLVLs.py @@ -77,8 +77,22 @@ def make_board(self): for c in range(self.board_cols): self.dict_board[(r, c)] = "O" self.countSpaces = self.board_rows * self.board_cols + self.place_mines() self.print_board() + def place_mines(self): + mines_to_place = ['*'] * self.num_mines + [' '] * ((self.board_rows * self.board_cols) - self.num_mines) + random.shuffle(mines_to_place) + for r in range(self.board_rows): + for c in range(self.board_cols): + m = mines_to_place.pop() + if m == '*': + coord = (r, c) + if coord not in self.mines_and_nums or self.mines_and_nums[coord] != "*": + self.mines_and_nums[coord] = "*" + self.place_nums(r, c) + self.count_mines += 1 + def print_board(self): print(' ' + ' '.join(str(c) for c in range(self.board_cols))) print(' ' + '-' * (self.board_cols * 2 + 1)) @@ -140,19 +154,6 @@ def toggle_flag(self): else: print("You want to waste flag on a space you already uncovered??? o_O") - def place_mines(self): - mines_to_place = ['*'] * self.num_mines + [' '] * ((self.board_rows * self.board_cols) - self.num_mines) - random.shuffle(mines_to_place) - for r in range(self.board_rows): - for c in range(self.board_cols): - m = mines_to_place.pop() - if m == '*': - coord = (r, c) - if coord not in self.mines_and_nums or self.mines_and_nums[coord] != "*": - self.mines_and_nums[coord] = "*" - self.place_nums(r, c) - self.count_mines += 1 - def neighbors(self, row, col): for r in range(row - 1, row + 2): for c in range(col - 1, col + 2): @@ -172,9 +173,19 @@ def place_nums(self, row, col): def check_move(self): if self.is_flagging == False: - # if mine is there at coordinate - game over + # if mine is there at coordinate - game over if self.dict_board[self.move] == "O": if self.move in self.mines_and_nums: + # don't let user hit a bomb on the first move + is_first_move = self.countSpaces == self.board_rows * self.board_cols + if is_first_move and self.mines_and_nums[self.move] == "*": + ls = [coord for coord, x in self.mines_and_nums.items() if x != '*'] + random.shuffle(ls) + free_coord = ls[0] + self.mines_and_nums[self.move] = ' ' + self.mines_and_nums[free_coord] = '*' + self.place_nums(free_coord[0], free_coord[1]) + if self.mines_and_nums[self.move] != "*": self.dict_board[self.move] = self.mines_and_nums[self.move] self.countSpaces -= 1 @@ -222,7 +233,6 @@ def start_game(self): self.define_level() self.make_board() self.make_move() - self.place_mines() self.check_move() self.game_play() From 28727e43514a2150eb122b27baeceab6d90626e3 Mon Sep 17 00:00:00 2001 From: ZennilGreenherald <144579645+ZennilGreenherald@users.noreply.github.com> Date: Fri, 14 Feb 2025 23:09:27 -0800 Subject: [PATCH 03/12] Improved main loop Improved main loop --- minesweeperLVLs.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/minesweeperLVLs.py b/minesweeperLVLs.py index 2b3a9f3..5a1cf0f 100644 --- a/minesweeperLVLs.py +++ b/minesweeperLVLs.py @@ -140,6 +140,7 @@ def make_move(self): print("*BOOM* No flag for you! >:D") else: print("Invalid input. Please try again.") + self.print_board() def toggle_flag(self): if self.count_flags <= self.num_mines: @@ -204,6 +205,7 @@ def check_move(self): print("Uhmmm, you want to dig up a flag you put down??") elif self.dict_board[self.move] != "O": print("You already uncovered this space -_-") + self.print_board() def uncover_space(self, row, col): @@ -223,18 +225,13 @@ def user_win(self): print("Congrats you won! :D") raise SystemExit() - def game_play(self): - self.user_win() - self.make_move() - self.check_move() - self.game_play() - def start_game(self): self.define_level() self.make_board() - self.make_move() - self.check_move() - self.game_play() + while True: + self.make_move() + self.check_move() + self.user_win() minesweeper = Minesweeper() minesweeper.start_game() From e2822bad512f9b79444b203f6bcd4e8fdbb69fe1 Mon Sep 17 00:00:00 2001 From: ZennilGreenherald <144579645+ZennilGreenherald@users.noreply.github.com> Date: Sat, 15 Feb 2025 00:53:55 -0800 Subject: [PATCH 04/12] Better row and col numbering Better row and col numbering --- minesweeperLVLs.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/minesweeperLVLs.py b/minesweeperLVLs.py index 5a1cf0f..568851f 100644 --- a/minesweeperLVLs.py +++ b/minesweeperLVLs.py @@ -94,11 +94,14 @@ def place_mines(self): self.count_mines += 1 def print_board(self): - print(' ' + ' '.join(str(c) for c in range(self.board_cols))) - print(' ' + '-' * (self.board_cols * 2 + 1)) + max_row_num_width = len(str(self.board_rows - 1)) + print(' ' * (max_row_num_width + 3) + ' '.join(str(c // 10) if c >= 10 else ' ' for c in range(self.board_cols))) + print(' ' * (max_row_num_width + 3) + ' '.join(str(c % 10) for c in range(self.board_cols))) + print(' ' * (max_row_num_width + 1) + '-' * (self.board_cols * 2 + 1)) for r in range(self.board_rows): - print(r, end = ' | ') + row_prefix = f'{" " * max_row_num_width}{r} | '[-(max_row_num_width + 3):] + print(row_prefix, end = '') for c in range(self.board_cols): print(self.dict_board[(r,c)], end = " ") print() From b2780dd40afc3eff2e2c20ac5945262836ae8c76 Mon Sep 17 00:00:00 2001 From: ZennilGreenherald <144579645+ZennilGreenherald@users.noreply.github.com> Date: Sat, 15 Feb 2025 01:56:34 -0800 Subject: [PATCH 05/12] Better input parsing Better input parsing --- minesweeperLVLs.py | 183 ++++++++++++++++++++++----------------------- 1 file changed, 91 insertions(+), 92 deletions(-) diff --git a/minesweeperLVLs.py b/minesweeperLVLs.py index 568851f..0c3ad1e 100644 --- a/minesweeperLVLs.py +++ b/minesweeperLVLs.py @@ -9,6 +9,8 @@ class Color: YELLOW = "\033[33m" END = "\033[0m" +red_x = f"{Color.RED}X{Color.END}" + levels = ["beginner", "intermediate", "advanced", "custom"] # beginner = 9x9 w/ 10 mines @@ -35,7 +37,6 @@ class Minesweeper: def __init__(self): self.dict_board = {} self.mines_and_nums = {} - self.count_mines = 0 self.count_flags = 0 self.board_rows = 0 self.board_cols = 0 @@ -78,7 +79,6 @@ def make_board(self): self.dict_board[(r, c)] = "O" self.countSpaces = self.board_rows * self.board_cols self.place_mines() - self.print_board() def place_mines(self): mines_to_place = ['*'] * self.num_mines + [' '] * ((self.board_rows * self.board_cols) - self.num_mines) @@ -91,7 +91,17 @@ def place_mines(self): if coord not in self.mines_and_nums or self.mines_and_nums[coord] != "*": self.mines_and_nums[coord] = "*" self.place_nums(r, c) - self.count_mines += 1 + + # method will use the coordinates of the mines that are placed + def place_nums(self, row, col): + # finds coordinate of top left, top center, top right, left side, right side, bottom left, bottom center, bottom right surrounding the mine + for space in self.neighbors(row, col): + # if the coordinate is not in the dictionary yet, adds key and value + if space not in self.mines_and_nums: + self.mines_and_nums[space] = 1 + # if the coordinate is already a key, increments the value up by 1 + elif space in self.mines_and_nums and self.mines_and_nums[space] != "*": + self.mines_and_nums[space] += 1 def print_board(self): max_row_num_width = len(str(self.board_rows - 1)) @@ -106,108 +116,97 @@ def print_board(self): print(self.dict_board[(r,c)], end = " ") print() + def neighbors(self, row, col): + for r in range(row - 1, row + 2): + for c in range(col - 1, col + 2): + if r >= 0 and c >= 0 and r < self.board_rows and c < self.board_cols and (r != row or c != col): + yield r, c + def get_user_move(self): - # when coordinate is inputed (row x column) checks the space - return (input("Please enter a 'coordinate' to uncover a space or 'X, coordinate' to place or remove a flag: ") - .upper() - .translate(str.maketrans(string.punctuation, (" " * len(string.punctuation)))) - .split()) + s = input("Please enter ' ' to uncover a space or 'X ' to place or remove a flag: ") + ls = s.upper().translate(str.maketrans(string.punctuation, (" " * len(string.punctuation)))).split() + try: + coords = tuple(map(int, ls[-2:])) + if len(ls) == 2: + return (False, ) + coords + elif len(ls) == 3 and ls[0] == 'X': + return (True, ) + coords + except Exception as e: + print(f'Bad input: {e}. Please try again.') + return self.get_user_move() def make_move(self): while True: - user = self.get_user_move() - # determines if the user is inputting a space - if len(user) == 2: - try: - self.move = tuple(map(int, user)) - if self.move in self.dict_board: - self.is_flagging = False - break - else: - print("That's not even a space on the board >_>") - except: - print("NO! >:O") - # determines if a user is inputting a flag - elif len(user) == 3 and user[0] == "X": - try: - self.flag = tuple(map(int, user[1:])) - if self.count_mines == 0: - print("You really want to place a flag on your first move?") - elif self.flag in self.dict_board: - self.toggle_flag() - self.is_flagging = True - break - else: - print("Sure. I can place a flag in the middle of nowhere for you! :D") - except: - print("*BOOM* No flag for you! >:D") + is_flagging, row, col = self.get_user_move() + move_coord = row, col + + if move_coord not in self.dict_board: + print("That's not even a space on the board >_>") + break + + elif not is_flagging: + self.check_move(move_coord) + break + elif is_flagging: + is_first_move = self.countSpaces == self.board_rows * self.board_cols + if is_first_move: + print("You really want to place a flag on your first move?") + else: + self.toggle_flag(move_coord) + break else: - print("Invalid input. Please try again.") + print("Invalid input. Please try again.") self.print_board() - def toggle_flag(self): - if self.count_flags <= self.num_mines: - if self.dict_board[self.flag] == "O": - self.dict_board[self.flag] = f"{Color.RED}X{Color.END}" - self.count_flags += 1 - self.print_board() - elif self.dict_board[self.flag] == f"{Color.RED}X{Color.END}": - self.dict_board[self.flag] = "O" + def toggle_flag(self, move_coord): + if self.dict_board[move_coord] == "O": + if self.count_flags < self.num_mines: + self.dict_board[move_coord] = red_x + self.count_flags += 1 + self.print_board() + else: + print('You already placed as many flags as there are bombs.') + elif self.dict_board[move_coord] == red_x: + self.dict_board[move_coord] = "O" self.count_flags -= 1 self.print_board() else: print("You want to waste flag on a space you already uncovered??? o_O") - def neighbors(self, row, col): - for r in range(row - 1, row + 2): - for c in range(col - 1, col + 2): - if r >= 0 and c >= 0 and r < self.board_rows and c < self.board_cols and (r != row or c != col): - yield r, c - - # method will use the coordinates of the mines that are placed - def place_nums(self, row, col): - # finds coordinate of top left, top center, top right, left side, right side, bottom left, bottom center, bottom right surrounding the mine - for space in self.neighbors(row, col): - # if the coordinate is not in the dictionary yet, adds key and value - if space not in self.mines_and_nums: - self.mines_and_nums[space] = 1 - # if the coordinate is already a key, increments the value up by 1 - elif space in self.mines_and_nums and self.mines_and_nums[space] != "*": - self.mines_and_nums[space] += 1 - - def check_move(self): - if self.is_flagging == False: - # if mine is there at coordinate - game over - if self.dict_board[self.move] == "O": - if self.move in self.mines_and_nums: - # don't let user hit a bomb on the first move - is_first_move = self.countSpaces == self.board_rows * self.board_cols - if is_first_move and self.mines_and_nums[self.move] == "*": - ls = [coord for coord, x in self.mines_and_nums.items() if x != '*'] - random.shuffle(ls) - free_coord = ls[0] - self.mines_and_nums[self.move] = ' ' - self.mines_and_nums[free_coord] = '*' - self.place_nums(free_coord[0], free_coord[1]) - - if self.mines_and_nums[self.move] != "*": - self.dict_board[self.move] = self.mines_and_nums[self.move] - self.countSpaces -= 1 - self.print_board() - else: - self.dict_board[self.move] = self.mines_and_nums[self.move] - self.print_board() - print("Game Over!") - raise SystemExit() - else: - self.dict_board[self.move] = " " + def check_move(self, move_coord): + if self.dict_board[move_coord] == red_x: + print("Uhmmm, you want to dig up a flag you put down??") + + elif self.dict_board[move_coord] != "O": + print("You already uncovered this space -_-") + self.print_board() + + elif self.dict_board[move_coord] == "O": + if move_coord in self.mines_and_nums: + # don't let user hit a bomb on the first move + is_first_move = self.countSpaces == self.board_rows * self.board_cols + if is_first_move and self.mines_and_nums[move_coord] == "*": + ls = [coord for coord, x in self.mines_and_nums.items() if x != '*'] + random.shuffle(ls) + free_coord = ls[0] + self.mines_and_nums[move_coord] = ' ' + self.mines_and_nums[free_coord] = '*' + self.place_nums(free_coord[0], free_coord[1]) + + if self.mines_and_nums[move_coord] != "*": + self.dict_board[move_coord] = self.mines_and_nums[move_coord] self.countSpaces -= 1 - self.uncover_space(self.move[0], self.move[1]) self.print_board() - elif self.dict_board[self.move] == f"{Color.RED}X{Color.END}": - print("Uhmmm, you want to dig up a flag you put down??") - elif self.dict_board[self.move] != "O": - print("You already uncovered this space -_-") + else: + # mine is at coordinate - game over, man + self.dict_board[move_coord] = self.mines_and_nums[move_coord] + self.print_board() + print("Game Over!") + raise SystemExit() + else: + self.dict_board[move_coord] = " " + self.countSpaces -= 1 + self.uncover_space(move_coord[0], move_coord[1]) self.print_board() @@ -231,9 +230,9 @@ def user_win(self): def start_game(self): self.define_level() self.make_board() + self.print_board() while True: self.make_move() - self.check_move() self.user_win() minesweeper = Minesweeper() From 4836b8ed9e1387d6f72738425626fa304358046a Mon Sep 17 00:00:00 2001 From: ZennilGreenherald <144579645+ZennilGreenherald@users.noreply.github.com> Date: Sat, 15 Feb 2025 14:10:27 -0800 Subject: [PATCH 06/12] separating model methods separating model methods --- minesweeperLVLs.py | 224 ++++++++++++++++++++++++++------------------- 1 file changed, 129 insertions(+), 95 deletions(-) diff --git a/minesweeperLVLs.py b/minesweeperLVLs.py index 0c3ad1e..0c5510a 100644 --- a/minesweeperLVLs.py +++ b/minesweeperLVLs.py @@ -3,6 +3,21 @@ import random import string +from enum import Enum, unique + +@unique +class FlagResult(Enum): + SPOT_CLEAR = 1 + NO_FLAGS_LEFT = 2 + OK = 3 + +@unique +class CheckResult(Enum): + SPOT_FLAGGED = 1 + SPOT_ALREADY_SHOWN = 2 + OK = 3 + EXPLODE = 4 + class Color: RED = "\033[31m" GREEN = "\033[32m" @@ -42,37 +57,6 @@ def __init__(self): self.board_cols = 0 self.num_mines = 0 - def get_level(self): - while True: - choice = input("Please choose a level (Beginner, Intermediate, Advanced, Custom, Quit): ").lower() - if choice == 'quit': - raise SystemExit() - elif choice in levels: - return choice - else: - print("What kind of level is that?!?!?! >:O") - - def define_level(self): - choice = self.get_level() - if choice in levels[:3]: - i = levels.index(choice) - self.board_rows = board_size_settings[i]['board_rows'] - self.board_cols = board_size_settings[i]['board_cols'] - self.num_mines = board_size_settings[i]['num_mines'] - # custom level - else: - while True: - try: - self.board_rows = int(input("Please enter a number 1-80 for rows: ")) - self.board_cols = int(input("Please enter a number 1-80 for columns: ")) - self.num_mines = int(input("Please enter a number 1-99 for bombs: ")) - if 0 < self.board_rows <= 80 and 0 < self.board_cols <= 80 and 0 < self.num_mines <= 99 and self.num_mines < (self.board_rows * self.board_cols) / 2: - break - else: - print("Can't make a board like that! D:") - except: - print("Can't make a board like that! D:") - def make_board(self): for r in range(self.board_rows): for c in range(self.board_cols): @@ -92,10 +76,16 @@ def place_mines(self): self.mines_and_nums[coord] = "*" self.place_nums(r, c) + def model_neighbors(self, row, col): + for r in range(row - 1, row + 2): + for c in range(col - 1, col + 2): + if r >= 0 and c >= 0 and r < self.board_rows and c < self.board_cols and (r != row or c != col): + yield r, c + # method will use the coordinates of the mines that are placed def place_nums(self, row, col): # finds coordinate of top left, top center, top right, left side, right side, bottom left, bottom center, bottom right surrounding the mine - for space in self.neighbors(row, col): + for space in self.model_neighbors(row, col): # if the coordinate is not in the dictionary yet, adds key and value if space not in self.mines_and_nums: self.mines_and_nums[space] = 1 @@ -116,15 +106,95 @@ def print_board(self): print(self.dict_board[(r,c)], end = " ") print() - def neighbors(self, row, col): - for r in range(row - 1, row + 2): - for c in range(col - 1, col + 2): - if r >= 0 and c >= 0 and r < self.board_rows and c < self.board_cols and (r != row or c != col): - yield r, c + def model_toggle_flag(self, move_coord): + if self.dict_board[move_coord] == "O": + if self.count_flags < self.num_mines: + self.dict_board[move_coord] = red_x + self.count_flags += 1 + return FlagResult.OK + else: + return FlagResult.NO_FLAGS_LEFT + elif self.dict_board[move_coord] == red_x: + self.dict_board[move_coord] = "O" + self.count_flags -= 1 + return FlagResult.OK + else: + return FlagResult.SPOT_CLEAR + + def model_check_move(self, move_coord): + if self.dict_board[move_coord] == red_x: + return CheckResult.SPOT_FLAGGED + + elif self.dict_board[move_coord] != "O": + return CheckResult.SPOT_ALREADY_SHOWN + + else: + # if first move, don't let user hit a bomb + is_first_move = self.countSpaces == self.board_rows * self.board_cols + if is_first_move and move_coord in self.mines_and_nums and self.mines_and_nums[move_coord] == "*": + ls = [coord for coord, x in self.mines_and_nums.items() if x != '*'] + random.shuffle(ls) + free_coord = ls[0] + self.mines_and_nums[move_coord] = ' ' + self.mines_and_nums[free_coord] = '*' + self.place_nums(free_coord[0], free_coord[1]) + + self.dict_board[move_coord] = self.mines_and_nums[move_coord] if move_coord in self.mines_and_nums else ' ' + self.countSpaces -= 1 + if move_coord not in self.mines_and_nums: + self.uncover_space(move_coord[0], move_coord[1]) + return CheckResult.OK + else: + if self.mines_and_nums[move_coord] == "*": + return CheckResult.EXPLODE + else: + return CheckResult.OK + + def uncover_space(self, row, col): + for space in self.model_neighbors(row, col): + if self.dict_board[space] == "O": + if space not in self.mines_and_nums: + self.dict_board[space] = " " + self.countSpaces -= 1 + self.uncover_space(space[0], space[1]) + elif space in self.mines_and_nums and self.mines_and_nums[space] != "*": + self.dict_board[space] = self.mines_and_nums[space] + self.countSpaces -= 1 + + def get_level(self): + while True: + choice = input("Please choose a level (Beginner, Intermediate, Advanced, Custom, Quit): ").lower() + if choice == 'quit': + raise SystemExit() + elif choice in levels: + return choice + else: + print("What kind of level is that?!?!?! >:O") + + def define_level(self): + choice = self.get_level() + if choice in levels[:3]: + i = levels.index(choice) + self.board_rows = board_size_settings[i]['board_rows'] + self.board_cols = board_size_settings[i]['board_cols'] + self.num_mines = board_size_settings[i]['num_mines'] + # custom level + else: + while True: + try: + self.board_rows = int(input("Please enter a number 1-80 for rows: ")) + self.board_cols = int(input("Please enter a number 1-80 for columns: ")) + self.num_mines = int(input("Please enter a number 1-99 for bombs: ")) + if 0 < self.board_rows <= 80 and 0 < self.board_cols <= 80 and 0 < self.num_mines <= 99 and self.num_mines < (self.board_rows * self.board_cols) / 2: + break + else: + print("Can't make a board like that! D:") + except: + print("Can't make a board like that! D:") def get_user_move(self): s = input("Please enter ' ' to uncover a space or 'X ' to place or remove a flag: ") - ls = s.upper().translate(str.maketrans(string.punctuation, (" " * len(string.punctuation)))).split() + ls = s.upper().translate(str.maketrans(string.punctuation, " " * len(string.punctuation))).split() try: coords = tuple(map(int, ls[-2:])) if len(ls) == 2: @@ -147,79 +217,43 @@ def make_move(self): elif not is_flagging: self.check_move(move_coord) break - elif is_flagging: + else: is_first_move = self.countSpaces == self.board_rows * self.board_cols if is_first_move: print("You really want to place a flag on your first move?") else: self.toggle_flag(move_coord) break - else: - print("Invalid input. Please try again.") - self.print_board() def toggle_flag(self, move_coord): - if self.dict_board[move_coord] == "O": - if self.count_flags < self.num_mines: - self.dict_board[move_coord] = red_x - self.count_flags += 1 - self.print_board() - else: - print('You already placed as many flags as there are bombs.') - elif self.dict_board[move_coord] == red_x: - self.dict_board[move_coord] = "O" - self.count_flags -= 1 - self.print_board() - else: - print("You want to waste flag on a space you already uncovered??? o_O") + res = self.model_toggle_flag(move_coord) + + if res == FlagResult.NO_FLAGS_LEFT: + print('You already placed as many flags as there are bombs.') + + elif res == FlagResult.SPOT_CLEAR: + print("You want to waste flag on a space you already uncovered??? o_O") + + else: + self.print_board() def check_move(self, move_coord): - if self.dict_board[move_coord] == red_x: + res = self.model_check_move(move_coord) + + if res == CheckResult.SPOT_FLAGGED: print("Uhmmm, you want to dig up a flag you put down??") - elif self.dict_board[move_coord] != "O": + elif res == CheckResult.SPOT_ALREADY_SHOWN: print("You already uncovered this space -_-") - self.print_board() - elif self.dict_board[move_coord] == "O": - if move_coord in self.mines_and_nums: - # don't let user hit a bomb on the first move - is_first_move = self.countSpaces == self.board_rows * self.board_cols - if is_first_move and self.mines_and_nums[move_coord] == "*": - ls = [coord for coord, x in self.mines_and_nums.items() if x != '*'] - random.shuffle(ls) - free_coord = ls[0] - self.mines_and_nums[move_coord] = ' ' - self.mines_and_nums[free_coord] = '*' - self.place_nums(free_coord[0], free_coord[1]) - - if self.mines_and_nums[move_coord] != "*": - self.dict_board[move_coord] = self.mines_and_nums[move_coord] - self.countSpaces -= 1 - self.print_board() - else: - # mine is at coordinate - game over, man - self.dict_board[move_coord] = self.mines_and_nums[move_coord] - self.print_board() - print("Game Over!") - raise SystemExit() - else: - self.dict_board[move_coord] = " " - self.countSpaces -= 1 - self.uncover_space(move_coord[0], move_coord[1]) - self.print_board() + elif res == CheckResult.OK: + pass + elif res == CheckResult.EXPLODE: + print("Game Over!") + raise SystemExit() - def uncover_space(self, row, col): - for space in self.neighbors(row, col): - if self.dict_board[space] == "O": - if space not in self.mines_and_nums: - self.dict_board[space] = " " - self.countSpaces -= 1 - self.uncover_space(space[0], space[1]) - elif space in self.mines_and_nums and self.mines_and_nums[space] != "*": - self.dict_board[space] = self.mines_and_nums[space] - self.countSpaces -= 1 + self.print_board() def user_win(self): # when all the blank spaces are uncovered - winner is pronounced! From c3ea7b4231c571c2d1e4ccfc391c9a5b93e1ea1b Mon Sep 17 00:00:00 2001 From: ZennilGreenherald <144579645+ZennilGreenherald@users.noreply.github.com> Date: Sat, 15 Feb 2025 14:49:45 -0800 Subject: [PATCH 07/12] refining code --- minesweeperLVLs.py | 97 ++++++++++++++++++++++++---------------------- 1 file changed, 50 insertions(+), 47 deletions(-) diff --git a/minesweeperLVLs.py b/minesweeperLVLs.py index 0c5510a..3173eec 100644 --- a/minesweeperLVLs.py +++ b/minesweeperLVLs.py @@ -47,23 +47,23 @@ class Color: } ] -class Minesweeper: - # build board and define how many mines/level - def __init__(self): +class Board: + def __init__(self, rows, cols, mines): self.dict_board = {} self.mines_and_nums = {} self.count_flags = 0 - self.board_rows = 0 - self.board_cols = 0 - self.num_mines = 0 + self.board_rows = rows + self.board_cols = cols + self.countSpaces = self.board_rows * self.board_cols + self.num_mines = mines + self.make_board() def make_board(self): for r in range(self.board_rows): for c in range(self.board_cols): self.dict_board[(r, c)] = "O" - self.countSpaces = self.board_rows * self.board_cols self.place_mines() - + def place_mines(self): mines_to_place = ['*'] * self.num_mines + [' '] * ((self.board_rows * self.board_cols) - self.num_mines) random.shuffle(mines_to_place) @@ -76,15 +76,8 @@ def place_mines(self): self.mines_and_nums[coord] = "*" self.place_nums(r, c) - def model_neighbors(self, row, col): - for r in range(row - 1, row + 2): - for c in range(col - 1, col + 2): - if r >= 0 and c >= 0 and r < self.board_rows and c < self.board_cols and (r != row or c != col): - yield r, c - # method will use the coordinates of the mines that are placed def place_nums(self, row, col): - # finds coordinate of top left, top center, top right, left side, right side, bottom left, bottom center, bottom right surrounding the mine for space in self.model_neighbors(row, col): # if the coordinate is not in the dictionary yet, adds key and value if space not in self.mines_and_nums: @@ -106,6 +99,13 @@ def print_board(self): print(self.dict_board[(r,c)], end = " ") print() + def model_neighbors(self, row, col): + # finds neighboring spots in all 8 directions + for r in range(row - 1, row + 2): + for c in range(col - 1, col + 2): + if r >= 0 and c >= 0 and r < self.board_rows and c < self.board_cols and (r != row or c != col): + yield r, c + def model_toggle_flag(self, move_coord): if self.dict_board[move_coord] == "O": if self.count_flags < self.num_mines: @@ -161,6 +161,21 @@ def uncover_space(self, row, col): self.dict_board[space] = self.mines_and_nums[space] self.countSpaces -= 1 + def move_in_range(self, coord): + return coord in self.dict_board + + def has_moved(self): + return self.countSpaces != self.board_rows * self.board_cols + + def isGameWon(self): + # when all the blank spaces are uncovered - winner is pronounced! + return self.countSpaces == self.num_mines + + +class Minesweeper: + def __init__(self): + self.board = None + def get_level(self): while True: choice = input("Please choose a level (Beginner, Intermediate, Advanced, Custom, Quit): ").lower() @@ -172,21 +187,24 @@ def get_level(self): print("What kind of level is that?!?!?! >:O") def define_level(self): + # Get dimensions and number of mines with which to construct the board choice = self.get_level() if choice in levels[:3]: i = levels.index(choice) - self.board_rows = board_size_settings[i]['board_rows'] - self.board_cols = board_size_settings[i]['board_cols'] - self.num_mines = board_size_settings[i]['num_mines'] + rows = board_size_settings[i]['board_rows'] + cols = board_size_settings[i]['board_cols'] + mines = board_size_settings[i]['num_mines'] + self.board = Board(rows, cols, mines) # custom level else: while True: try: - self.board_rows = int(input("Please enter a number 1-80 for rows: ")) - self.board_cols = int(input("Please enter a number 1-80 for columns: ")) - self.num_mines = int(input("Please enter a number 1-99 for bombs: ")) - if 0 < self.board_rows <= 80 and 0 < self.board_cols <= 80 and 0 < self.num_mines <= 99 and self.num_mines < (self.board_rows * self.board_cols) / 2: - break + rows = int(input("Please enter a number 1-80 for rows: ")) + cols = int(input("Please enter a number 1-80 for columns: ")) + mines = int(input("Please enter a number 1-99 for bombs: ")) + if 0 < rows <= 80 and 0 < cols <= 80 and 0 < mines < min(100, (board_rows * board_cols) / 2): + self.board = Board(rows, cols, mines) + return else: print("Can't make a board like that! D:") except: @@ -207,10 +225,12 @@ def get_user_move(self): def make_move(self): while True: + self.board.print_board() + is_flagging, row, col = self.get_user_move() move_coord = row, col - if move_coord not in self.dict_board: + if not self.board.move_in_range(move_coord): print("That's not even a space on the board >_>") break @@ -218,15 +238,14 @@ def make_move(self): self.check_move(move_coord) break else: - is_first_move = self.countSpaces == self.board_rows * self.board_cols - if is_first_move: + if not self.board.has_moved(): print("You really want to place a flag on your first move?") else: self.toggle_flag(move_coord) break def toggle_flag(self, move_coord): - res = self.model_toggle_flag(move_coord) + res = self.board.model_toggle_flag(move_coord) if res == FlagResult.NO_FLAGS_LEFT: print('You already placed as many flags as there are bombs.') @@ -234,11 +253,8 @@ def toggle_flag(self, move_coord): elif res == FlagResult.SPOT_CLEAR: print("You want to waste flag on a space you already uncovered??? o_O") - else: - self.print_board() - def check_move(self, move_coord): - res = self.model_check_move(move_coord) + res = self.board.model_check_move(move_coord) if res == CheckResult.SPOT_FLAGGED: print("Uhmmm, you want to dig up a flag you put down??") @@ -246,28 +262,15 @@ def check_move(self, move_coord): elif res == CheckResult.SPOT_ALREADY_SHOWN: print("You already uncovered this space -_-") - elif res == CheckResult.OK: - pass - - elif res == CheckResult.EXPLODE: - print("Game Over!") - raise SystemExit() - - self.print_board() - - def user_win(self): - # when all the blank spaces are uncovered - winner is pronounced! - if self.countSpaces == self.num_mines: - print("Congrats you won! :D") + elif res == CheckResult.EXPLODE or (res == CheckResult.OK and self.board.isGameWon()): + self.board.print_board() + print("Game Over!" if res == CheckResult.EXPLODE else "Congrats you won! :D") raise SystemExit() def start_game(self): self.define_level() - self.make_board() - self.print_board() while True: self.make_move() - self.user_win() minesweeper = Minesweeper() minesweeper.start_game() From b2a714447a9584785116cd0a6347ec4f512001bc Mon Sep 17 00:00:00 2001 From: ZennilGreenherald <144579645+ZennilGreenherald@users.noreply.github.com> Date: Sat, 15 Feb 2025 16:13:04 -0800 Subject: [PATCH 08/12] Pushing globals down into static fields Pushing globals down into static fields --- minesweeperLVLs.py | 65 +++++++++++++++++++++++----------------------- 1 file changed, 33 insertions(+), 32 deletions(-) diff --git a/minesweeperLVLs.py b/minesweeperLVLs.py index 3173eec..e6dea6e 100644 --- a/minesweeperLVLs.py +++ b/minesweeperLVLs.py @@ -24,30 +24,9 @@ class Color: YELLOW = "\033[33m" END = "\033[0m" -red_x = f"{Color.RED}X{Color.END}" - -levels = ["beginner", "intermediate", "advanced", "custom"] - -# beginner = 9x9 w/ 10 mines -# intermediate = 16x16 w/ 40 mines -# advanced = 30x16 w/ 99 mines -board_size_settings = [ - { - 'board_rows': 9, - 'board_cols': 9, - 'num_mines': 10 - }, { - 'board_rows': 16, - 'board_cols': 16, - 'num_mines': 40 - }, { - 'board_rows': 16, - 'board_cols': 30, - 'num_mines': 99 - } -] - class Board: + red_x = f"{Color.RED}X{Color.END}" + def __init__(self, rows, cols, mines): self.dict_board = {} self.mines_and_nums = {} @@ -109,12 +88,12 @@ def model_neighbors(self, row, col): def model_toggle_flag(self, move_coord): if self.dict_board[move_coord] == "O": if self.count_flags < self.num_mines: - self.dict_board[move_coord] = red_x + self.dict_board[move_coord] = Board.red_x self.count_flags += 1 return FlagResult.OK else: return FlagResult.NO_FLAGS_LEFT - elif self.dict_board[move_coord] == red_x: + elif self.dict_board[move_coord] == Board.red_x: self.dict_board[move_coord] = "O" self.count_flags -= 1 return FlagResult.OK @@ -122,7 +101,7 @@ def model_toggle_flag(self, move_coord): return FlagResult.SPOT_CLEAR def model_check_move(self, move_coord): - if self.dict_board[move_coord] == red_x: + if self.dict_board[move_coord] == Board.red_x: return CheckResult.SPOT_FLAGGED elif self.dict_board[move_coord] != "O": @@ -173,6 +152,27 @@ def isGameWon(self): class Minesweeper: + # beginner = 9x9 w/ 10 mines + # intermediate = 16x16 w/ 40 mines + # advanced = 30x16 w/ 99 mines + board_size_settings = [ + { + 'board_rows': 9, + 'board_cols': 9, + 'num_mines': 10 + }, { + 'board_rows': 16, + 'board_cols': 16, + 'num_mines': 40 + }, { + 'board_rows': 16, + 'board_cols': 30, + 'num_mines': 99 + } + ] + levels = ["beginner", "intermediate", "advanced", "custom"] + + def __init__(self): self.board = None @@ -181,7 +181,7 @@ def get_level(self): choice = input("Please choose a level (Beginner, Intermediate, Advanced, Custom, Quit): ").lower() if choice == 'quit': raise SystemExit() - elif choice in levels: + elif choice in Minesweeper.levels: return choice else: print("What kind of level is that?!?!?! >:O") @@ -189,11 +189,12 @@ def get_level(self): def define_level(self): # Get dimensions and number of mines with which to construct the board choice = self.get_level() - if choice in levels[:3]: - i = levels.index(choice) - rows = board_size_settings[i]['board_rows'] - cols = board_size_settings[i]['board_cols'] - mines = board_size_settings[i]['num_mines'] + if choice in Minesweeper.levels[:3]: + i = Minesweeper.levels.index(choice) + settings = Minesweeper.board_size_settings + rows = settings[i]['board_rows'] + cols = settings[i]['board_cols'] + mines = settings[i]['num_mines'] self.board = Board(rows, cols, mines) # custom level else: From ff899305f78d1f010d6b55d4695d0cbb54c48252 Mon Sep 17 00:00:00 2001 From: ZennilGreenherald <144579645+ZennilGreenherald@users.noreply.github.com> Date: Sat, 15 Feb 2025 16:33:49 -0800 Subject: [PATCH 09/12] make_move recursive instead of loop --- minesweeperLVLs.py | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/minesweeperLVLs.py b/minesweeperLVLs.py index e6dea6e..2fddd78 100644 --- a/minesweeperLVLs.py +++ b/minesweeperLVLs.py @@ -225,25 +225,21 @@ def get_user_move(self): return self.get_user_move() def make_move(self): - while True: - self.board.print_board() - - is_flagging, row, col = self.get_user_move() - move_coord = row, col + self.board.print_board() - if not self.board.move_in_range(move_coord): - print("That's not even a space on the board >_>") - break + is_flagging, row, col = self.get_user_move() + move_coord = row, col - elif not is_flagging: - self.check_move(move_coord) - break + if not self.board.move_in_range(move_coord): + print("That's not even a space on the board >_>") + elif not is_flagging: + self.check_move(move_coord) + else: + if self.board.has_moved(): + self.toggle_flag(move_coord) else: - if not self.board.has_moved(): - print("You really want to place a flag on your first move?") - else: - self.toggle_flag(move_coord) - break + print("You really want to place a flag on your first move?") + self.make_move() def toggle_flag(self, move_coord): res = self.board.model_toggle_flag(move_coord) From bc56d869a94e9f1e24f10e1f1ae5821837a2132f Mon Sep 17 00:00:00 2001 From: ZennilGreenherald <144579645+ZennilGreenherald@users.noreply.github.com> Date: Sat, 15 Feb 2025 16:44:06 -0800 Subject: [PATCH 10/12] renaming stuff renaming stuff --- minesweeperLVLs.py | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/minesweeperLVLs.py b/minesweeperLVLs.py index 2fddd78..6ca93a6 100644 --- a/minesweeperLVLs.py +++ b/minesweeperLVLs.py @@ -53,17 +53,14 @@ def place_mines(self): coord = (r, c) if coord not in self.mines_and_nums or self.mines_and_nums[coord] != "*": self.mines_and_nums[coord] = "*" - self.place_nums(r, c) - - # method will use the coordinates of the mines that are placed - def place_nums(self, row, col): - for space in self.model_neighbors(row, col): - # if the coordinate is not in the dictionary yet, adds key and value - if space not in self.mines_and_nums: - self.mines_and_nums[space] = 1 - # if the coordinate is already a key, increments the value up by 1 - elif space in self.mines_and_nums and self.mines_and_nums[space] != "*": - self.mines_and_nums[space] += 1 + self.place_nums_around_mine(r, c) + + def place_nums_around_mine(self, row, col): + for neighbor_coord in self.neighbor_coords(row, col): + if neighbor_coord not in self.mines_and_nums: + self.mines_and_nums[neighbor_coord] = 1 + elif neighbor_coord in self.mines_and_nums and self.mines_and_nums[neighbor_coord] != "*": + self.mines_and_nums[neighbor_coord] += 1 def print_board(self): max_row_num_width = len(str(self.board_rows - 1)) @@ -78,14 +75,14 @@ def print_board(self): print(self.dict_board[(r,c)], end = " ") print() - def model_neighbors(self, row, col): + def neighbor_coords(self, row, col): # finds neighboring spots in all 8 directions for r in range(row - 1, row + 2): for c in range(col - 1, col + 2): if r >= 0 and c >= 0 and r < self.board_rows and c < self.board_cols and (r != row or c != col): yield r, c - def model_toggle_flag(self, move_coord): + def toggle_flag(self, move_coord): if self.dict_board[move_coord] == "O": if self.count_flags < self.num_mines: self.dict_board[move_coord] = Board.red_x @@ -100,7 +97,7 @@ def model_toggle_flag(self, move_coord): else: return FlagResult.SPOT_CLEAR - def model_check_move(self, move_coord): + def check_move(self, move_coord): if self.dict_board[move_coord] == Board.red_x: return CheckResult.SPOT_FLAGGED @@ -116,7 +113,7 @@ def model_check_move(self, move_coord): free_coord = ls[0] self.mines_and_nums[move_coord] = ' ' self.mines_and_nums[free_coord] = '*' - self.place_nums(free_coord[0], free_coord[1]) + self.place_nums_around_mine(free_coord[0], free_coord[1]) self.dict_board[move_coord] = self.mines_and_nums[move_coord] if move_coord in self.mines_and_nums else ' ' self.countSpaces -= 1 @@ -130,7 +127,7 @@ def model_check_move(self, move_coord): return CheckResult.OK def uncover_space(self, row, col): - for space in self.model_neighbors(row, col): + for space in self.neighbor_coords(row, col): if self.dict_board[space] == "O": if space not in self.mines_and_nums: self.dict_board[space] = " " @@ -242,7 +239,7 @@ def make_move(self): self.make_move() def toggle_flag(self, move_coord): - res = self.board.model_toggle_flag(move_coord) + res = self.board.toggle_flag(move_coord) if res == FlagResult.NO_FLAGS_LEFT: print('You already placed as many flags as there are bombs.') @@ -251,7 +248,7 @@ def toggle_flag(self, move_coord): print("You want to waste flag on a space you already uncovered??? o_O") def check_move(self, move_coord): - res = self.board.model_check_move(move_coord) + res = self.board.check_move(move_coord) if res == CheckResult.SPOT_FLAGGED: print("Uhmmm, you want to dig up a flag you put down??") From dc66c5a43cf24b3551261cd64de4aa45d7e34072 Mon Sep 17 00:00:00 2001 From: ZennilGreenherald <144579645+ZennilGreenherald@users.noreply.github.com> Date: Sat, 15 Feb 2025 17:09:17 -0800 Subject: [PATCH 11/12] Better board numbering and level select From 3863eeb3defaf4fb789315d620b050beecc3fee9 Mon Sep 17 00:00:00 2001 From: ZennilGreenherald <144579645+ZennilGreenherald@users.noreply.github.com> Date: Sat, 15 Feb 2025 17:11:50 -0800 Subject: [PATCH 12/12] Better board numbering and level select --- minesweeperLVLs.py | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/minesweeperLVLs.py b/minesweeperLVLs.py index 6ca93a6..450a4c4 100644 --- a/minesweeperLVLs.py +++ b/minesweeperLVLs.py @@ -64,16 +64,25 @@ def place_nums_around_mine(self, row, col): def print_board(self): max_row_num_width = len(str(self.board_rows - 1)) - print(' ' * (max_row_num_width + 3) + ' '.join(str(c // 10) if c >= 10 else ' ' for c in range(self.board_cols))) - print(' ' * (max_row_num_width + 3) + ' '.join(str(c % 10) for c in range(self.board_cols))) - print(' ' * (max_row_num_width + 1) + '-' * (self.board_cols * 2 + 1)) + horiz_rule = ' ' * (max_row_num_width + 1) + '-' * (self.board_cols * 2 + 3) + corner_spaces = ' ' * (max_row_num_width + 3) + if self.board_cols > 10: + horiz_nums = corner_spaces + ' '.join(str(c // 10) if c >= 10 else ' ' for c in range(self.board_cols)) + '\n' + else: + horiz_nums = '' + horiz_nums += corner_spaces + ' '.join(str(c % 10) for c in range(self.board_cols)) + print(horiz_nums) + print(horiz_rule) for r in range(self.board_rows): - row_prefix = f'{" " * max_row_num_width}{r} | '[-(max_row_num_width + 3):] - print(row_prefix, end = '') + row_num = f'{" " * max_row_num_width}{r}'[-max_row_num_width:] + print(f'{row_num} | ', end = '') for c in range(self.board_cols): print(self.dict_board[(r,c)], end = " ") - print() + print(f'| {row_num}') + + print(horiz_rule) + print(horiz_nums) def neighbor_coords(self, row, col): # finds neighboring spots in all 8 directions @@ -167,7 +176,7 @@ class Minesweeper: 'num_mines': 99 } ] - levels = ["beginner", "intermediate", "advanced", "custom"] + levels = ["b", "i", "a", "c"] def __init__(self): @@ -175,8 +184,9 @@ def __init__(self): def get_level(self): while True: - choice = input("Please choose a level (Beginner, Intermediate, Advanced, Custom, Quit): ").lower() - if choice == 'quit': + choice = input("Please choose a level: (B)eginner, (I)ntermediate, (A)dvanced, (C)ustom or (Q)uit: ").lower() + choice = choice[0] if choice else '' + if choice == 'q': raise SystemExit() elif choice in Minesweeper.levels: return choice