I have a problem where I need create a function to solve the number of N's(ninjas) in a nested list of given coordinates x, y:
ninjas = [['N', ' ', ' ', ' ', ' '],
['N', 'N', 'N', 'N', ' '],
['N', ' ', 'N', ' ', ' '],
['N', 'N', 'N', ' ', ' '],
[' ', ' ', ' ', ' ', ' '],
[' ', ' ', ' ', ' ', ' ']]
So, if my coordinates are x=1 and y=2, the function should return 8 (the number of ninjas surrounding the coordinate). I've battled with this problem for 48 straight hours and I can't get my head around this. The solution should not contain any fancy numpy.imports. Only basic for-loops and...
How should I proceed with this problem? Any hints?
WAY over the PEP-8 79 characters per line limit, but here's my one-line solution:
def surrounding(ninjas, x, y):
return [ninjas[r][c] for r in range(y-1 if y > 0 else y, y + 2 if y < len(ninjas)-1 else y + 1) for c in range(x-1 if x > 0 else x, x + 2 if x < len(ninjas[0])-1 else x + 1)].count('N')
which works as expected:
surrounding(ninjas, 1, 2)
which gives 8.
surrounding(ninjas, 4, 5)
which gives 0.
If you want to break it down into something a little more readable, then here is a more sensible function to do the job:
def surrounding(ninjas, x, y):
neighbours = []
for r in range(y-1 if y > 0 else y, y+2 if y < len(ninjas)-1 else y+1):
for c in range(x-1 if x > 0 else x, x+2 if x < len(ninjas[0])-1 else x+1):
neighbours.append(ninjas[r][c])
return neighbours.count('N')
Note that both these solutions rely on the ninjas list being rectangular
How they work
Both functions work in the same way, just one is crammed into a list-comprehension and the other appends to a list of neighbours.
The steps for calculating the surrounding Ninjas is as follows:
list to store the cell values/rows in the 2d-list from 1 above if there are no walls above else from the entered position to 1 below if there are ...columns inside the current row from 1 to the left if there are no walls else from the entered... cell to the neighbours listneighbours list using .count('N')One more thing to note is that this problem could be approached in a slightly different way. Instead of adding every cell to a list and counting the Ninjas in that list, we could instead add 1 to a variable if that cell is a Ninja.
The code for that would look like:
def surrounding(ninjas, x, y):
noNinjas = 0
for r in range(y - 1 if y > 0 else y, y + 2 if y < len(ninjas) else y + 1):
for c in range(x - 1 if x > 0 else x, x + 2 if x < len(ninjas) else x + 1):
if ninjas[r][c] == 'N':
noNinjas += 1
return noNinjas
As you can get the (x, y) element by ninjas[y][x], you can simply check all 8 surrounding elements for an 'N':
Ns = 0 # Number of 'N's
if ninjas[y + 1][x] == 'N': # Below
Ns += 1
if ninjas[y][x + 1] == 'N': # To the right
Ns += 1
if ninjas[y - 1][x - 1] == 'N': # Above to the left
Ns += 1
...
This can of course be written more cleverly by utilizing loops rather than writing out all 8 cases by hand. Also, no bounds checking is performed, meaning that you probably should ensure that (x, y) is not on the boundary of your 2D data array.
As we need x -1, x and x + 1 (and similar for y) we can make the loops like so:
Ns = 0
for i in range(-1, 2):
for j in range(-1, 2):
if i == j == 0:
# This is just the (x, y) element itself. Skip it
continue
if ninjas[y + i][x + j] == 'N':
Ns += 1
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With