I wrote a code that is supposed to generate a spiral pattern of characters. It does generate a spiral, but for some reason, it skips the outermost column, the bottommost row, and the leftmost column (I'll leave an example output below). I can't figure out why this is happening on my own. I do check whether the cell two steps ahead is filled. Only if it is, we should make a turn, essentially creating the spiral.
def asterisk_spiral(size):
matrix = [[' ' for _ in range(size)] for _ in range(size)]
row, col = 0, 0
directions = [(0, 1), (1, 0), (0, -1), (-1, 0)]
direction = 0
for i in range(1, size * size // 2):
matrix[row][col] = '*'
next_row, next_col = row + directions[direction][0], col + directions[direction][1]
next_next_row, next_next_col = row + 2 * directions[direction][0], col + 2 * directions[direction][1]
if (
0 <= next_row < size
and 0 <= next_col < size
and 0 <= next_next_row < size
and 0 <= next_next_col < size
and matrix[next_row][next_col] == ' '
and matrix[next_next_row][next_next_col] != '*'
):
row, col = next_row, next_col
else:
# turn
direction = (direction + 1) % 4
row, col = row + directions[direction][0], col + directions[direction][1]
return matrix
def print_spiral(matrix):
for row in matrix:
print(' '.join(row))
size = 9
spiral_matrix = asterisk_spiral(size)
print_spiral(spiral_matrix)
Result:
[['*', '*', '*', '*', '*', '*', '*', '*', ' '],
[' ', ' ', ' ', ' ', ' ', ' ', ' ', '*', ' '],
[' ', '*', '*', '*', '*', '*', ' ', '*', ' '],
[' ', '*', ' ', ' ', ' ', '*', ' ', '*', ' '],
[' ', '*', ' ', '*', '*', '*', ' ', '*', ' '],
[' ', '*', ' ', '*', '*', '*', ' ', '*', ' '],
[' ', '*', ' ', ' ', ' ', ' ', ' ', '*', ' '],
[' ', '*', '*', '*', '*', '*', '*', '*', ' '],
[' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ']]
whereas expected matrix is:
[['*', '*', '*', '*', '*', '*', '*', '*', '*'],
[' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '*'],
['*', '*', '*', '*', '*', '*', '*', ' ', '*'],
['*', ' ', ' ', ' ', ' ', ' ', '*', ' ', '*'],
['*', ' ', '*', '*', '*', ' ', '*', ' ', '*'],
['*', ' ', '*', ' ', ' ', ' ', '*', ' ', '*'],
['*', ' ', '*', '*', '*', '*', '*', ' ', '*'],
['*', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '*'],
['*', '*', '*', '*', '*', '*', '*', '*', '*']]
When the if
condition 0 <= next_row < size
is true, but 0 <= next_next_row < size
is not true, your logic will trigger a turn, but that means that for the first few lines the turn is made before hitting the boundary of the square, i.e. one step too early.
Instead you should have this logic:
"When the next cell in the current direction exists, and it is not so that one step further there is an asterisk, then go on in the same direction".
That means the if
condition could look like this:
if (
0 <= next_row < size
and 0 <= next_col < size
and not (0 <= next_next_row < size
and 0 <= next_next_col < size
and matrix[next_next_row][next_next_col] == '*')
):
Once you have corrected this, you'll notice another issue: the loop doesn't make enough iterations. The for
statement should be corrected to this:
for i in range(size + size * size // 2):
Depending how you want the output to look for when size
is an even number, you may want to reduce that by one iteration. If so, change it to this:
for i in range(1 - size % 2, size + size * size // 2):
Choose whichever of the two suits your needs for the case where size
is even.