Skip to content

Instantly share code, notes, and snippets.

@bobmurder
Created November 1, 2012 01:16
Show Gist options
  • Save bobmurder/3991003 to your computer and use it in GitHub Desktop.
Save bobmurder/3991003 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python
from collections import defaultdict
from itertools import chain, repeat
from random import choice
##################
# Map Generation #
##################
#==============
# Lookup Tables
#==============
def operations_table():
return dict(zip(
range(1, 10),
[(-1, -1), (0, -1), (1, -1),
(-1, 0), (0, 0), (1, 0),
(-1, 1), (0, 1), (1, 1)]
))
def edge_table():
return (tuple([4] + range(6, 10)), tuple(range(1, 5) + [6]),
(2, 3, 6, 8, 9), (1, 2, 4, 7, 8))
def corner_operations(height, width):
height, width = map(lambda x: x - 1, [height, width])
return {(0, 0): [operations_table[n] for n in (6, 8, 9)],
(width, 0): [operations_table[n] for n in (4, 7, 8)],
(0, height): [operations_table[n] for n in (2, 3, 6)],
(width, height): [operations_table[n] for n in (1, 2, 4)]}
def edge_operations(height, width):
top, bottom, left, right = edge_table()
max_x, max_y = map(lambda x: x - 1, [height, width])
edge_cells = {}
for cell in [(n, 0) for n in range(1, width)]:
edge_cells[cell] = [operations_table[n] for n in top]
for cell in [(n, max_y) for n in range(1, width)]:
edge_cells[cell] = [operations_table[n] for n in bottom]
for cell in [(0, n) for n in range(1, height)]:
edge_cells[cell] = [operations_table[n] for n in left]
for cell in [(max_x, n) for n in range(1, height)]:
edge_cells[cell] = [operations_table[n] for n in right]
return edge_cells
#================
# Cell Operations
#================
def check_space(grid, cell):
x, y = cell
if grid[x][y] == empty_cell:
return True
return False
def protect_cells(cell, operations):
pass
def flag_cell(mine_cell, operation):
x, y = mine_cell
add_x, add_y = operation
return (x + add_x, y + add_y)
def increment(grid, mine_cell, flag_cells, operations):
for operation in operations:
cell = tuple(flag_cell(mine_cell, operation))
if check_space(grid, cell):
flag_cells[cell] += 1
#================
# Grid Operations
#================
def blank_grid(height, width):
return [[empty_cell for n in range(width)] for n in range(height)]
def place_mines(grid, mines, choice):
height, width = len(grid), len(grid[0])
mine_cells = []
while mines:
x, y = choice(range(height)), choice(range(width))
if grid[x][y] == empty_cell:
grid[x][y] = bomb_symbol
mine_cells.append((x, y))
mines -= 1
return grid, mine_cells
def place_flags(grid, mine_cells):
corner_cells = corner_operations(height, width)
edge_cells = edge_operations(height, width)
flag_cells = defaultdict(int)
for mine_cell in mine_cells:
if mine_cell in corner_cells:
operations = corner_cells[mine_cell]
elif mine_cell in edge_cells:
operations = edge_cells[mine_cell]
else:
operations = operations_table.values()
increment(grid, mine_cell, flag_cells, operations)
for k, v in flag_cells.iteritems():
x, y = k
grid[x][y] = str(v)
return grid
#=============
# Map Creation
#=============
def create_map(height, width, mines):
initial_grid = blank_grid(height, width)
grid, mine_cells = place_mines(initial_grid, mines)
return place_flags(grid, mine_cells), mine_cells
################
# Game Display #
################
# prompt message
def prompt_message(mark_list):
if mark_list:
return "(R)eveal, (M)ark, (U)nmark, (Q)uit"
return "(R)eveal, (M)ark, (Q)uit"
# status bar
def status_bar(mines):
return 'Mines: %s' % mines
# create a grid matching the height and width of the game map
def initial_display(height, width):
from string import uppercase
head = 0
header = [uppercase[i] for i in range(width)]
header.insert(head, ' ')
header.append(' ')
header = '|'.join(header)
grid = [['#' for i in range(width)] for j in range(height)]
for idx, row in enumerate(grid):
i = idx + 1
if len(str(i)) == 1:
row.insert(head, ' %s' % i)
else:
row.insert(head, '%s' % i)
row.append(' ')
return grid, header
def update_display(current_display, cell):
pass
#########
# Tests #
#########
def won(mine_list, mark_list, current_display):
''' Returns True if both conditions are true '''
cells = chain(*current_display)
# true if they match, false otherwise
matching = sorted(mine_list) == sorted(mark_list)
# true if '#' isn't a character in the current display
uncovered = all([cell != '#' for cell in cells])
return matching and uncovered
minesweeper_rules = """
global variables:
mine/marker counter
marks list
bombs list
User Starts Game
-prompt for initial choice
Initial Choice
-The flag and bomb positions aren't generated yet.
-User selects an initial cell to check
-Create the flag and bomb grid, while making sure that
the cell the user chose and all adjacent cells are not bombs.
-Do this by setting the cells affected by the user's cell to
a unique symbol during bomb placement, then changing them back
to the default symbol afterwards before flag placement
Subsequent Choices
Reveal:
while alive:
prompt for choice
if it is a bomb: game over
if it is an empty space:
reveal the empty space
add the coordinates to the memo dict
for each adjacent space:
if it is a number:
reveal the number
add the coordinates to the memo dict
continue to the next space
if it is an empty space:
if it is not in the memo dict:
recurse
else:
continue
if it is a number:
reveal the number
add the coordinates to the memo dict
Mark:
mark the space
add the coords to the marks list
decrement the counter
Unmark:
unmark the space
remove the coords from the marks list
increment the counter
Quit:
quit da game
Convert [letter][number] coords to (x, y) tuples
-example: A1 = (0, 0), C5 = (3, 5)
-function: lambda x: tuple(alpha_table[x[0]], int(x[1:])
-regex validation: '^[A-Za-z]{1}\d{1,2}$'
Tests
#done
Winning:
if bomb coords == mark coords and # not in display grid:
you win
else:
you are alive
"""
###############
# Main Script #
###############
if __name__ == '__main__':
# imports used during execution as a script
from pprint import pprint
import sys
# testing
DEBUG = False
INFO = True
# global variables
empty_cell = ' '
bomb_symbol = 'X'
operations_table = operations_table()
height, width = 15, 15
mines = 20
marked_cells = []
revealed_cells = {}
mines_left = mines
# initial map
grid, mine_cells = create_map(height, width, mines)
initial_status = status_bar(mines)
display, header = initial_display(height, width)
if DEBUG:
pprint(grid)
print
pprint(display)
if INFO:
for row in grid:
print ''.join(row)
print
print
print status_bar(mines)
print
print header
for row in display:
print '|'.join(row)
print prompt_message(marked_cells)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment