Last active
March 2, 2018 01:51
-
-
Save hanss314/13f08d8ee684c6be45d871656b35ceef 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
import curses | |
import time | |
from minesweeper import MineSweeper | |
def main(size=(10, 10), mines=10): | |
screen = curses.initscr() | |
height, width = screen.getmaxyx() | |
init_curses() | |
game = MineSweeper(*size, mines) | |
game_win = curses.newwin( | |
game.height + 2, 2 * game.width + 1, (height - game.height - 2) // 2, (width - 2 * game.width - 1) // 2 | |
) | |
game_win.nodelay(True) | |
x = y = 0 | |
start = end = None | |
while True: | |
draw_game(game, game_win, x, y) | |
if start is None: | |
screen.addstr((height - game.height - 4) // 2, (width - 5) // 2, "00.00") | |
elif end is None: | |
t = f"{time.time()-start:.2f}" | |
screen.addstr((height - game.height - 4) // 2, (width - len(t)) // 2, t) | |
else: | |
t = f"{end-start:.2f}" | |
screen.addstr((height - game.height - 4) // 2, (width - len(t)) // 2, t) | |
screen.refresh() | |
game_win.refresh() | |
pressed = game_win.getch() | |
if pressed == 113: | |
break | |
elif pressed == 107 and y < game.height - 1: | |
y += 1 | |
elif pressed == 105 and y > 0: | |
y -= 1 | |
elif pressed == 106 and x > 0: | |
x -= 1 | |
elif pressed == 108 and x < game.width - 1: | |
x += 1 | |
elif pressed == 32: | |
status = game.uncover(x, y) | |
if start == None: start = time.time() | |
if status != 0: end = time.time() | |
elif pressed == 102: | |
game.flag(x, y) | |
elif pressed == 114: | |
start = end = None | |
game = MineSweeper(*size, mines) | |
def init_curses(): | |
curses.start_color() | |
curses.use_default_colors() | |
curses.curs_set(0) | |
curses.init_color(1, 0, 0, 0) | |
curses.init_color(1, 999, 999, 999) | |
curses.init_pair(1, 0, 255) | |
def draw_game(game: MineSweeper, window, i, j): | |
window.border() | |
for x, row in enumerate(game.to_string()): | |
for y, tile in enumerate(row): | |
if x == i and y == j: | |
window.addstr(y + 1, 2 * x + 1, tile, curses.color_pair(1)) | |
else: | |
window.addstr(y + 1, 2 * x + 1, tile) | |
if __name__ == '__main__': | |
try: | |
main(size=(9, 9)) | |
finally: | |
curses.endwin() |
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
import random | |
class MineSweeper: | |
def __init__(self, width, height, mines): | |
self.width = width | |
self.height = height | |
self.mine_count = mines | |
self.mines_chosen = False | |
self.board = [ | |
[ | |
Tile(self, x, y) for y in range(self.height) | |
]for x in range(self.width) | |
] | |
def get_neighbors(self, x, y): | |
neighbors = [(x+dx, y+dy) for dx in range(-1, 2) for dy in range(-1, 2)] | |
neighbors.remove((x, y)) | |
neighbors = [n for n in neighbors if 0 <= n[0] < self.width and 0 <= n[1] < self.height] | |
return [self.board[x][y] for x, y in neighbors] | |
def choose_mines(self, i, j): | |
self.mines_chosen = True | |
squares = [(x, y) for x in range(self.width) for y in range(self.height)] | |
if (i, j) in squares: squares.remove((i, j)) | |
for x, y in random.sample(squares, self.mine_count): | |
self.board[x][y].mine = True | |
for x, row in enumerate(self.board): | |
for y, tile in enumerate(row): | |
tile.set_neighbors(self.get_neighbors(x, y)) | |
def flag(self, x, y): | |
self.board[x][y].flag() | |
def uncover(self, x, y): | |
if not self.mines_chosen: | |
self.choose_mines(x, y) | |
self.board[x][y].uncover() | |
if self.board[x][y].mine: | |
self.uncover_all() | |
return -1 | |
return self.checkwin() | |
def checkwin(self): | |
for row in self.board: | |
for tile in row: | |
if not tile.uncovered and not tile.mine: | |
return 0 | |
return 1 | |
def uncover_all(self): | |
for row in self.board: | |
for tile in row: | |
if not tile.uncovered: | |
tile.uncovered = True | |
def to_string(self): | |
return [ | |
[tile.to_char() for tile in row] | |
for row in self.board | |
] | |
class Tile: | |
def __init__(self, ms: MineSweeper, x, y, mine=False): | |
self.ms = ms | |
self.x, self.y = x, y | |
self.mine = mine | |
self.flagged = False | |
self.uncovered = False | |
self.neighbor_count = 0 | |
def flag(self): | |
if self.uncovered: return | |
self.flagged = not self.flagged | |
def uncover(self): | |
if self.flagged: | |
return | |
if not self.uncovered: | |
self.uncovered = True | |
if self.neighbor_count == 0 and not self.mine: | |
for neighbor in self.ms.get_neighbors(self.x, self.y): | |
neighbor.uncover() | |
else: | |
flagged = len([tile for tile in self.ms.get_neighbors(self.x, self.y) if tile.flagged]) | |
if flagged == self.neighbor_count: | |
for neighbor in self.ms.get_neighbors(self.x, self.y): | |
if not neighbor.uncovered: neighbor.uncover() | |
def set_neighbors(self, neighbors): | |
self.neighbor_count = 0 | |
for neighbor in neighbors: | |
if neighbor.mine: | |
self.neighbor_count += 1 | |
def to_char(self): | |
if self.uncovered: | |
return '*' if self.mine else str(self.neighbor_count) | |
else: | |
return 'F' if self.flagged else 'N' | |
if __name__ == '__main__': | |
minesweeper_board = MineSweeper(10, 10, 10) | |
# print(minesweeper_board.to_string()) | |
while True: | |
print('\n'.join(' '.join(x) for x in minesweeper_board.to_string())) | |
coords = input('> ') | |
flag = 'f' in coords | |
coords = list(map(int, coords.split(' ')[:2])) | |
if not flag: | |
state = minesweeper_board.uncover(*coords) | |
print(state) | |
if state != 0: break | |
else: | |
minesweeper_board.flag(*coords) | |
print('\n'.join(' '.join(x) for x in minesweeper_board.to_string())) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment