Tell me more ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

I would like to write a python or c++ function to print numbers like the following examples (with n as input parameter):

When n = 3, print:

1 2 3
8 0 4
7 6 5

When n = 4, print:

4  5  6  7
15 0  1  8
14 3  2  9
13 12 11 10

I have an answer in the following code block, but it is not quite elegant. Does anyone have a better solution?

def print_matrix(n):
  l = [i for i in range(0,n*n)]

  start = (n-1)/2
  end = n-1-start
  count = 0
  if start ==end:
    l [start+ n*end] = count
    start -= 1
    count +=1

  while start >=0:
        end = n - start
        for i in range(start, end-1):
                x= i
                y= start
                print y*n +x
                l[y*n +x] = count
                count +=1
        for i in range(start, end-1):
                x = end-1
                y = i
                print y*n +x
                l[y*n +x] = count
                count +=1
        for i in range(end-1,start,-1):
                x= i
                y= end-1
                print y*n +x
                l[y*n +x] = count
                count +=1
        for i in range(end-1, start,-1):
                x = start
                y = i
                print y*n +x
                l[y*n +x] = count
                count +=1
        start -=1


  print l
share|improve this question
1  
Have no idea why this has been moved here. Much more suited to stack overflow. There are also many more people on SO that can help maybe you should rephrase the question. – Loki Astari Oct 13 '12 at 14:37
3  
@LokiAstari, its not clear to me why you think this is off-topic here. People presenting working code and ask for more elegant solutions seems to be a large part of the questions here. – Winston Ewert Oct 13 '12 at 19:32

migrated from stackoverflow.com Oct 13 '12 at 13:39

5 Answers

up vote 5 down vote accepted

Using a 2D array to store the matrix, we can simplify the function greatly. This uses Python 2 syntax.

def print_matrix(n):
    mat = [[0]*n for _ in xrange(n)]

    k = 0 # value to write
    for level in reversed(xrange(n, 0, -2)):
        start = n/2 - level/2
        pr = pc = start # current row, column indices
        if level == 1: # special case: no perimeter crawl
            mat[pr][pc] = k
            k += 1
            continue
        # walk along each edge of the perimeter
        for dr, dc in [(0,1), (1,0), (0,-1), (-1,0)]:
            for i in xrange(level - 1):
                mat[pr][pc] = k
                k, pr, pc = k+1, pr+dr, pc+dc

    width = len(str(n*n-1))
    for i in mat:
        for j in i:
            print '{:<{width}}'.format(j, width=width),
        print

Samples:

>>> print_matrix(4)
4  5  6  7 
15 0  1  8 
14 3  2  9 
13 12 11 10
>>> print_matrix(3)
1 2 3
8 0 4
7 6 5
>>> print_matrix(2)
0 1
3 2
>>> print_matrix(1)
0
>>> print_matrix(9)
49 50 51 52 53 54 55 56 57
80 25 26 27 28 29 30 31 58
79 48 9  10 11 12 13 32 59
78 47 24 1  2  3  14 33 60
77 46 23 8  0  4  15 34 61
76 45 22 7  6  5  16 35 62
75 44 21 20 19 18 17 36 63
74 43 42 41 40 39 38 37 64
73 72 71 70 69 68 67 66 65
share|improve this answer

The code that you and other people posted could be simplified to the following:

def slot(n, x,y):
  ma = max(x,y)+1
  mi = min(x,y)
  o= min(n-ma,mi)
  l= max(n-2*(o+1),0)
  p= x+y - 2*o
  if x<y: p= 4*(l+1)-p
  return l*l+p

To use the code you could do:

from sys import stdout as out

n = 3
for y in xrange(n):
  for x in xrange(n):
    out.write(' %2d'%slot(n,x,y))
  print

As you can see, it doesn't need 2D arrays.
It just calculates the values pixel-per-pixel.
It is more robust: try to do any other program with n=1000000000 and it will fail.

The results are always as expected, see them at IdeOne.

share|improve this answer
nice.. :) however, I'd say that min and max have their own if in their implementation, so it's around 4-5 ifs in a whole. – Ron Klein Oct 15 '12 at 20:36
Yeah I know, but they're mathematic functions so their implementations don't count :) – jmendeth Oct 16 '12 at 6:34

The important element of a shorter program is using a direction-array to set the step directions in your matrix; whether the matrix is represented via a 1D vector or a 2D matrix is less important. In a vector, the same-column cell in the next row is n elements away from the current cell.

def print_matrix(n):
  ar = [0 for i in range(n*n)]
  m, bat = n, 0
  for shell in range((n+1)//2):
    at = bat
    m = m-2
    ar[at] = val = m*m      # Each shell starts with a square
    if m<0:
      ar[at] = 0
      break
    for delta in [1, n, -1, -n]:        # Do 4 sides of shell
      # Fill from corner to just before next corner
      for tic in range(m+1):
        ar[at] = val
        at += delta             # Step to next or prev row or col
        val += 1
    bat += n+1                  # Step to next-inner shell

  # Print matrix in n rows, n columns
  for i in range(n):
    for j in range(n):
      print "\t", ar[i*n+j],
    print

for n in range(1,7):
  print "n = ", n
  print_matrix(n)

This produces output like the following:

n =  1
    0
n =  2
    0   1
    3   2
n =  3
    1   2   3
    8   0   4
    7   6   5
...
n =  6
    16  17  18  19  20  21
    35  4   5   6   7   22
    34  15  0   1   8   23
    33  14  3   2   9   24
    32  13  12  11  10  25
    31  30  29  28  27  26
share|improve this answer

Just a direction, not a full solution, but anyway...

If limited by space, you could directly calculate each item in the matrix, given its indexes and N. So eventually you could have a function with the following signature:

def calc_mat_item(i, j, n)

The math behind this function is not that simple, but it's not that complex, too: You should calculate the shell's index, according to i, j, and n. Then you should calculate on which side of the shell are i and j ("North", "South", "East" or "West"), and calculate the "distance" (in steps) of the current item from the shell's start position.
All this is pretty much mod calculations.

Once this method is done, you could simply write a nested loop (N by N) with i and j, and print the function's value, without having to populate a matrix before that.

The calculations in the calc_mat_item should not take more than O(1) (in space and time), so eventually you could have a solution of Θ(N) in time, and O(1) in space.

Just an idea, though.

share|improve this answer
Yes, that's the idea I also had. Your direction has been converted into code! Checkout my answer. – jmendeth Oct 15 '12 at 19:18
As you can see, there's only one if, everything else is maths! – jmendeth Oct 15 '12 at 19:23

One possible answer, you could

1) initialize an array with all possible value ( [0, .., n2-1] )
2) randomly shuffle the value
3) print values in n x n lines

share|improve this answer
2  
but the numbers are not random, that's the whole thing. Take a look, it's spiral – nogard Oct 13 '12 at 19:26

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.