If constructing an object is entagled with different cases and conditions it's better to use factory. That's not the case here.
Instead of this.
def make_board(mines, size):
'''function that uses my created Board methods to create the playing board'''
board = Board(tuple([tuple([Cell(True,True,True) for i in range(size+1)]) for j in range(size+1)]))
open_pos = list(range(size-1)*(size-1))
for i in range(mines):
new_pos = random.choice(open_pos) #randomly select from open positions
open_pos.remove(new_pos) # take that new position out of the open one
(row_coord,col_coord) = (new_pos % 9, new_pos // 9) # mod and floor div
board.put_mine(row_coord,col_coord) #put the mine in the new random location
return board
You can do this. Notice also how I've transformed your code from imperative into declarative and used prefer composition over inheritance
by creating self.cells
.
def chunks(sequence, n):
iters = (iter(iterable),) * n
return zip(*iters)
class Board:
'''class that creates the playing board'''
def __init__(self, mines_count, height, width): #initializing
size = height * width
mines = chain(repeat(True, mines_count), repeat(False, size - mines_count))
mines = rnd.shuffle(mines)
cells = (Cell(is_mine) for is_mine in mines)
self.cells = chunks(cells, width)
self.playing = True
Use default values in initializer of Cell
class Cell(object):
"""a class to deal with individual cells"""
def __init__(self, can_see, flagged, is_mine): #initializing Cell class
self.can_see = not can_see
self.flagged = not flagged
self.is_mine = is_mine
class Cell(object):
'''a class to deal with individual cells'''
def __init__(self, is_mine, visible=False, flagged=False): #initializing Cell class
self.visible = visible
self.flagged = flagged
self.is_mine = is_mine
And is_solved
can be expressed much shortly and more readable
def is_solved(self):
for row in self:
for cell in row:
if not(cell.can_see or cell.flagged):
return False
return True
def is_solved(self):
return all(c.visible and c.flagged for c in chain.from_iterable(self.cells))
No need for parenthesis in sequence unpacking and in conditionals too.
for col_coord, cell in enumerate(row):
...
if cell.is_mine and not cell.flagged:
You're not finding neighbours they just are. Using iterools
def find_neighbors(self, row_coord,col_coord):
surr = ((-1,-1), (-1,0), (-1,1), (0,-1), (0,1), (1,-1), (1,0), (1,1))
y = ((row_coord + surr_row, col_coord + surr_col) for (surr_row,surr_col) in surr)
return y
def neighbors(self, row, col):
return (
self.cells[row + x][col + y]
for x, y in product((-1, 0, 1), repeat=2)
if (x, y) != (0, 0)
and 0 <= row + x <= self.width
and 0 <= col + y <= self.height
)
And now this
def count_surroundings(self,row_coord,col_coord):
count = 0
for (surr_row,surr_col) in self.find_neighbors(row_coord,col_coord):
if (self.is_in_range(surr_row,surr_col) and self[surr_row][surr_col].is_mine):
count += 1
return count
Becomes oneliners
def surrounding_mines_count(self,row_coord,col_coord):
return sum(cell.is_mine for cell in self.neighbors(row, col))
def mines_left(self):
return sum(c.is_mine and not c.flagged for c in chain.from_iterable(self.cells))