Created
September 9, 2016 18:05
-
-
Save MasonM/6e81d65a624209be15e8707d71d22968 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
import random | |
import collections | |
import re | |
class MinesweeperGrid: | |
def __init__(self, size, num_bombs): | |
self.size = size | |
self.num_bombs = num_bombs | |
self.num_opened = 0 | |
self.__init_grid() | |
self.__place_bombs() | |
def __init_grid(self): | |
self.grid = [] | |
for row in range(self.size): | |
self.grid.append([]) | |
for col in range(self.size): | |
self.grid[row].append(MinesweeperGridCell(row, col)) | |
def __place_bombs(self): | |
bombs = [] | |
while True: | |
index = random.randint(0, self.size ** 2 - 1) | |
row = index // self.size | |
col = index % self.size | |
cell = self.grid[row][col] | |
if cell in bombs: | |
continue | |
cell.has_bomb = True | |
for neighbor in self.__get_neighbors(cell).values(): | |
neighbor.num_surrounding_bombs += 1 | |
bombs.append(cell) | |
if len(bombs) == self.num_bombs: | |
break | |
def has_won(self): | |
return self.num_opened == (self.size ** 2 - self.num_bombs) | |
def open(self, row, col): | |
cell = self.grid[row][col] | |
cell.opened = True | |
if cell.has_bomb: | |
return True | |
queue = collections.deque([cell]) | |
while queue: | |
cell = queue.popleft() | |
cell.opened = True | |
self.num_opened += 1 | |
if cell.num_surrounding_bombs != 0: | |
continue | |
for direction, neighbor in self.__get_neighbors(cell).items(): | |
if not neighbor.has_bomb and \ | |
not neighbor.opened and \ | |
direction in ['above', 'below', 'left', 'right']: | |
neighbor.opened = True | |
queue.append(neighbor) | |
return False | |
def __get_neighbors(self, cell): | |
neighbors = {} | |
row, col = cell.row, cell.col | |
if row > 0: | |
neighbors['above'] = self.grid[row - 1][col] | |
if col > 0: | |
neighbors['above_left'] = self.grid[row - 1][col - 1] | |
if col < self.size - 1: | |
neighbors['above_right'] = self.grid[row - 1][col + 1] | |
if row < self.size - 1: | |
neighbors['below'] = self.grid[row + 1][col] | |
if col > 0: | |
neighbors['below_left'] = self.grid[row + 1][col - 1] | |
if col < self.size - 1: | |
neighbors['below_right'] = self.grid[row + 1][col + 1] | |
if col > 0: | |
neighbors['left'] = self.grid[row][col - 1] | |
if col < self.size - 1: | |
neighbors['right'] = self.grid[row][col + 1] | |
return neighbors | |
def render(self, show_all=False): | |
out = " " + "".join(map(str, range(1, self.size + 1))) + "\n" | |
for row_num, row in enumerate(self.grid): | |
out += "{} [{}]\n".format(row_num + 1, "".join(cell.render(show_all) for cell in row)) | |
return out | |
class MinesweeperGridCell: | |
def __init__(self, row, col): | |
self.row = row | |
self.col = col | |
self.opened = False | |
self.has_bomb = False | |
self.num_surrounding_bombs = 0 | |
def render(self, show_all=False): | |
if self.opened: | |
if self.has_bomb: | |
return '!' | |
if self.num_surrounding_bombs == 0: | |
return 'O' | |
return str(self.num_surrounding_bombs) | |
if show_all: | |
return 'X' if self.has_bomb else '_' | |
return '?' | |
class Minesweeper: | |
def __init__(self, size, num_bombs, debug=False): | |
self.debug = debug | |
self.grid = MinesweeperGrid(size, num_bombs) | |
def get_input(self): | |
user_input = input("Your move in row,col format:") | |
match = re.match("(\d+), *(\d+)", user_input) | |
if not match: | |
print("Invalid input") | |
return self.get_input() | |
row, col = match.groups() | |
if not row.isdigit() or not col.isdigit(): | |
print("Invalid input") | |
return self.get_input() | |
return (int(row) - 1, int(col) - 1) | |
def play(self): | |
while True: | |
print(self.grid.render(self.debug)) | |
row, col = self.get_input() | |
if self.grid.open(row, col): | |
print("You hit a bomb!") | |
break | |
if self.grid.has_won(): | |
print("You win!") | |
break | |
print(self.grid.render(True)) | |
debug = False | |
a = Minesweeper(4, 7, debug) | |
a.play() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment