Reputation: 3
Python 3.8.2 Mac Big Sur 11.2.1
This code is supposed to be a simple minesweeper game in the terminal but when i run it i only get a error message (shown below) i couldn't find any help to this problem when searching around so i thought to ask it myself instead
import random
import re
class Board:
def __init__(self, dim_size, num_bombs):
self.dim_size = dim_size
self.num_bombs = num_bombs
self.board = self.make_new_board()
self.assign_values_to_board
self.dug = set()
def make_new_board(self):
board = [[None for _ in range(self.dim_size)] for _ in range(self.dim_size)]
def assign_values_to_board(self):
for r in range(self.dim_size):
for c in range(self.dim_size):
if self.board[r][c] == '*':
continue
self.board[r][c] = self.get_num_neighboring_bombs(r, c)
def get_num_neighboring_bombs(self, row, col):
num_neighboring_bombs = 0
for r in range(max(0, row-1), min(self.dim_size-1, row+1)+1):
for c in range(max(0, col-1), min(self.dim_size - 1, col+1)+1):
if r == row and c == col:
continue
if self.board[r][c] == '*':
num_neighboring_bombs += 1
return num_neighboring_bombs
bombs_planted = 0
while bombs_planted < self.num_bombs:
loc = random.randint(0, self.dim_size**2 - 1)
row = loc // self.dim_size
col = loc % self.dim_size
if board [row][col] == '*':
# bomb already plated here
continue
board[row][col] = '*' # plant the bomb
bombs_planted += 1
return board
def dig(self, row, col):
self.dug.add((row, col))
if self.board[row][col] == '*':
return False
elif self.board[row][col] > 0:
return True
for r in range(max(0, row-1), min(self.dim_size-1, row+1)+1):
for c in range(max(0, col-1), min(self.dim_size - 1, col+1)+1):
if (r, c) in self.dug:
continue
self.dig(r, c)
return True
def __str__(self):
visible_board = [[None for _ in range(self.dim_size)] for _ in range(self.dim_size)]
for row in range(self.dim_size):
for col in range(self.dim_size):
if (row,col) in self.dug:
visible_board[row][col] = str(self.board[row][col])
else:
visible_board[row][col] = ' '
string_rep = ''
widths = []
for idx in range(self.dim_size):
columns = map(lambda x: x[idx], visible_board)
widths.append(
len(
max(columns, key = len)
)
)
indices = [i for i in range(self.dim_size)]
indices_row = ' '
cells = []
for idx, col in enumerate(indices):
format = '%-' + str(widths[idx]) + "s"
cells.append(format % (col))
indices_row += ' '.join(cells)
indices_row += ' \n'
for i in range(len(visible_board)):
row = visible_board[i]
string_rep += f'{i} |'
cells = []
for idx, col in enumerate(row):
format = '%-' + str(widths[idx]) + "s"
cells.append(format % (col))
string_rep += ' |'.join(cells)
string_rep += ' |\n'
str_len = int(len(string_rep) / self.dim_size)
string_rep = indices_row + '-'*str_len + '\n' + string_rep + '-'*str_len
return string_rep
def play(dim_size=10, num_bombs=10):
board = Board(dim_size, num_bombs)
safe = True
while len(board.dug) < board.dim_size ** 2 - num_bombs:
print(board)
user_input = re.split(',(\\s)*', input("Where would you like to dig? Input as row,col: "))
row, col = int(user_input[0]), int(user_input[-1])
if row < o or row >= board.dim_size or col < 0 or col >= dim_size:
print("Invalid location. Try again")
continue
safe = board.dig(row, col)
if not safe:
break
if safe:
print("Victory Royale!")
else:
print("You suck. Game Over")
board.dug = [(r,c) for r in range(board.dim_size) for c in range(board.dim_size)]
print(board)
if __name__ == '__main__':
play()
When i run this code it only returns
Traceback (most recent call last):
File "/Users/henry/Documents/projects/GamesPython/Minesweeper/game.py", line 134, in <module>
play()
File "/Users/henry/Documents/projects/GamesPython/Minesweeper/game.py", line 115, in play
print(board)
File "/Users/henry/Documents/projects/GamesPython/Minesweeper/game.py", line 82, in __str__
max(columns, key = len)
TypeError: object of type 'NoneType' has no len()
How can i fix this problem
Upvotes: 0
Views: 2253
Reputation: 2743
What seems to be happening here is that one of the variables you are passing to max()
is not defined (that is what NoneType
usually means -- something has no type (eg. it's a null
value), so you can't get the length of it). Maybe you have forgotten to return
something from one of your functions, or perhaps there is a scope error you aren't expecting. It's really hard to tell from your error stack because there are no line numbers in your code and you use max()
a bunch of times.
This is pretty complicated, but not that "large," and you have divided your logic nicely into functions. My suggestion would be start writing some unit tests, and probably I'd use doctest for something like this. That should help you narrow-down the problem.
Upvotes: 0
Reputation: 23089
The iterable columns
has at least one None
value in it. Here is a simple example that provides the same error given the same line of code:
columns = [ "a", None, "b" ]
max(columns, key = len)
Result:
max(columns, key = len)
TypeError: object of type 'NoneType' has no len()
As to why that None
value is in there, columns
is built from visible_board
. I haven't spent the time to understand your logic completely, but I will point out that the line of code that builds visible_board
is very suspicious:
visible_board = [[None for _ in range(self.dim_size)] for _ in range(self.dim_size)]
Sure looks to me like it's going to build a list with a lot of None
entries in it. That is verified when running your code in a debugger. At the point of the error, visible_board
looks like this:
[[' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '], [None, None, None, None, None, None, None, None, None, None], [None, None, None, None, None, None, None, None, None, None], [None, None, None, None, None, None, None, None, None, None], [None, None, None, None, None, None, None, None, None, None], [None, None, None, None, None, None, None, None, None, None], [None, None, None, None, None, None, None, None, None, None], [None, None, None, None, None, None, None, None, None, None], [None, None, None, None, None, None, None, None, None, None], [None, None, None, None, None, None, None, None, None, None]]
So it isn't surprising that you end up trying to cal the len
attribute on a None
value and get the error that you do.
Upvotes: 2