Coding puzzle not from curriculum: print nxn table of digits in clockwise spiral manner

Given n = 5, print out a table nxn with numbers in the spiralling clockwise manner.
e.g.

Screenshot_13

My broken code:

n = int(input())
 for row in range(1, n+1):
     for column in range(1,n+1):
           print( row)
           if( column == n): #here it should be printng the 'column'
               print(row, end = 'n')
           if( column == n*2):
               print(row, end = '\t')

This SO page has a lot of good examples on ways to approach this problem. I adapted my answer from there, user jfs’ answer in particular.

So first off. I like to start these exercises by directly duplicating what I expect my result to be so that I know what I’m working towards.
Let’s say n = 5:

print('1 2 3 4 5')        # 1 2 3 4 5
print('16 17 18 19 6')    # 16 17 18 19 6
print('15 24 25 20 7')    # 15 24 25 20 7
print('14 23 22 21 8')    # 14 23 22 21 8
print('13 12 11 10 9')    # 13 12 11 10 9

That’s a total of 5 print statements. In other words my goal is is going to be to construct 5 rows of string integers. This seems like a job for lists. Specifically a list of lists:

table = [[0] * n for _ in range(5)]
for row in table:
    print(table)

# [0, 0, 0, 0, 0]    X ------>
# [0, 0, 0, 0, 0]    Y
# [0, 0, 0, 0, 0]    |
# [0, 0, 0, 0, 0]    |
# [0, 0, 0, 0, 0]    v

So the way I see it, there are 2 ways to approach this. 1) Predict for each row what the sequence will be and add it to an empty list. This is probably the most efficient method (n steps) but requires a lot of predictive knowledge. 2) Run through a sequence of numbers of length n^2 (n^2 steps) and place them where we predict they’re supposed to go. Essentially, you can predict the number at each position, or the position of each number. I’d be interested in an answer using method 1 but method 2 seems easier for math mortals. Option 2 it is.

Try to think of the table as a cartesian coordinate system, with the origin (0,0) at the top left corner. Each position in the table has a unique x & y value. To create a spiral, we can take a number in sequence and assign it as the value for table[y][x] (y being the row, x being the column). To accomplish this we’re going to create x and y variables and update them as we crawl through the spiral. In order to update those values, we’ll create a dictionary with keys symbolizing directions up, down, left, and right with values pertaining to (x, y) incremental updates. One more dictionary will be used in order to switch directions when needed.

n = 5
seq = range(1, n**2 + 1)
table = [[0] * n for _ in range(n)]
movements = {'U': (0, -1), 'R': (1, 0), 'D': (0, 1), 'L': (-1, 0)}
turns = {'U': 'R', 'R': 'D', 'D': 'L', 'L': 'U'}
orientation = 'R'  # Starting orientation
dx, dy = movements[orientation]  # Unpack the movement tuple into variables
x, y = 0, 0  # Start at the top left corner
print((x, y))
for d in seq:
    table[y][x] = 1
    if not (0 <= x+dx < n and 0 <= y+dy < n and table[y+dy][x+dx] == 0):
    # If x or y are not between 0 - 4 or the potential new (x,y) position
    # has already been assigned a value: Turn clockwise
        orientation = turns[orientation]  # update direction
        dx, dy = movements[orientation] 
        x, y = x + dx, y + dy  # update x and y
        print('turned:' + orientation + '  mov: ' + str(movements[orientation]))
        print((x, y))
    else:
    # Don't change directions and continue moving in the current direction
        x, y = x + dx, y + dy  # update x and y
        print((x, y))

This bit of code should print out each (x, y) coordinate pair as it moves along the spiral and notify you when it changes direction. This way you can see how the loop is going to move through the table.

I’m pretty sure you can take it from here.

Here’s the function I cobbled together to accomplish this. It could probably be prettier and more efficient, but it works.

def spiral_maker(n):
    """ Prints a spiral matrix of size n x n of sequential integers """
    spiral = [[0] * n for _ in range(n)]
    movements = {'U': (0, -1), 'R': (1, 0), 'D': (0, 1), 'L': (-1, 0)}
    turns = {'U': 'R', 'R': 'D', 'D': 'L', 'L': 'U'}
    orientation = 'R'
    dx, dy = movements[orientation]
    x, y = 0, 0
    for d in range(1, n**2 + 1):
        spiral[y][x] = str(d)
        if not (0 <= x+dx < n and 0 <= y+dy < n and spiral[y+dy][x+dx] == 0):
            orientation = turns[orientation]
            dx, dy = movements[orientation]
            x, y = x + dx, y + dy
        else:
            x, y = x + dx, y + dy
    for row in spiral:
        print(' '.join(row))

thx u so much… i have another approach, let me check if i can code it up myself.