Question: given an integer number n, print the numbers from 1 up to n2 like this:
n = 4
result is:
01 02 03 04
12 13 14 05
11 16 1
Here's a different approach. It relies on spotting that the movements you make cycle between: right, down, left, up, right, .... Further, the number of times you move goes: 3 right, 3 down, 3 left, 2 up, 2 right, 1 down, 1 left. So without further ado, I will code this up in Python.
First, I will use some itertools and some numpy:
from itertools import chain, cycle, imap, izip, repeat
from numpy import array
The directions cycle between: right, down, left, up, right, ...:
directions = cycle(array(v) for v in ((0,1),(1,0),(0,-1),(-1,0)))
(I'm using numpy's arrays here so I can easily add directions together. Tuples don't add nicely.)
Next, the number of times I move counts down from n-1 to 1, repeating each number twice, and the first number three times:
countdown = chain((n-1,), *imap(repeat, range(n-1,0,-1), repeat(2)))
So now my sequence of directions can be created by repeating each successive direction by the paired number in countdown:
dirseq = chain(*imap(repeat, directions, countdown))
To get my sequence of indices, I can just sum this sequence, but (AFAIK) Python does not provide such a method, so let's quickly throw one together:
def sumseq(seq, start=0):
v = start
yield v
for s in seq:
v += s
yield v
Now to generate the original array, I can do the following:
a = array(((0,)*n,)*n) # n-by-n array of zeroes
for i, v in enumerate(sumseq(dirseq, array((0,0)))):
a[v[0], v[1]] = i+1
print a
Which, for n = 4, gives:
[[ 1 2 3 4]
[12 13 14 5]
[11 16 15 6]
[10 9 8 7]]
and, for n = 5, gives:
[[ 1 2 3 4 5]
[16 17 18 19 6]
[15 24 25 20 7]
[14 23 22 21 8]
[13 12 11 10 9]]
This approach can be generalised to rectangular grids; I leave this as an exercise for the reader ;)
Though your example is in python and this is in Java, I think you should be able to follow the logic:
public class SquareTest {
public static void main(String[] args) {
SquareTest squareTest = new SquareTest(4);
System.out.println(squareTest);
}
private int squareSize;
private int[][] numberSquare;
private int currentX;
private int currentY;
private Direction currentDirection;
private enum Direction {
LEFT_TO_RIGHT, RIGHT_TO_LEFT, TOP_TO_BOTTOM, BOTTOM_TO_TOP;
};
public SquareTest(int squareSize) {
this.squareSize = squareSize;
numberSquare = new int[squareSize][squareSize];
currentY = 0;
currentX = 0;
currentDirection = Direction.LEFT_TO_RIGHT;
constructSquare();
}
private void constructSquare() {
for (int i = 0; i < squareSize * squareSize; i = i + 1) {
numberSquare[currentY][currentX] = i + 1;
if (Direction.LEFT_TO_RIGHT.equals(currentDirection)) {
travelLeftToRight();
} else if (Direction.RIGHT_TO_LEFT.equals(currentDirection)) {
travelRightToLeft();
} else if (Direction.TOP_TO_BOTTOM.equals(currentDirection)) {
travelTopToBottom();
} else {
travelBottomToTop();
}
}
}
private void travelLeftToRight() {
if (currentX + 1 == squareSize || numberSquare[currentY][currentX + 1] != 0) {
currentY = currentY + 1;
currentDirection = Direction.TOP_TO_BOTTOM;
} else {
currentX = currentX + 1;
}
}
private void travelRightToLeft() {
if (currentX - 1 < 0 || numberSquare[currentY][currentX - 1] != 0) {
currentY = currentY - 1;
currentDirection = Direction.BOTTOM_TO_TOP;
} else {
currentX = currentX - 1;
}
}
private void travelTopToBottom() {
if (currentY + 1 == squareSize || numberSquare[currentY + 1][currentX] != 0) {
currentX = currentX - 1;
currentDirection = Direction.RIGHT_TO_LEFT;
} else {
currentY = currentY + 1;
}
}
private void travelBottomToTop() {
if (currentY - 1 < 0 || numberSquare[currentY - 1][currentX] != 0) {
currentX = currentX + 1;
currentDirection = Direction.LEFT_TO_RIGHT;
} else {
currentY = currentY - 1;
}
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
for (int i = 0; i < squareSize; i = i + 1) {
for (int j = 0; j < squareSize; j = j + 1) {
builder.append(numberSquare[i][j]);
builder.append(" ");
}
builder.append("\n");
}
return builder.toString();
}
}
Another way to do it, this time in C#:
int number = 9;
var position = new { x = -1, y = 0 };
var directions = new [] {
new { x = 1, y = 0 },
new { x = 0, y = 1 },
new { x = -1, y = 0 },
new { x = 0, y = -1 }
};
var sequence = (
from n in Enumerable.Range(1, number)
from o in Enumerable.Repeat(n, n != number ? 2 : 1)
select o
).Reverse().ToList();
var result = new int[number,number];
for (int i = 0, current = 1; i < sequence.Count; i++)
{
var direction = directions[i % directions.Length];
for (int j = 0; j < sequence[i]; j++, current++)
{
position = new {
x = position.x + direction.x,
y = position.y + direction.y
};
result[position.y, position.x] = current;
}
}
I have solved your problem using C++. I don't know if it will be helpful for you. But posting it. If it works for you it will be a pleasure.
Here is the Code:
#include<iostream>
#include<string.h>
using namespace std;
bool valid(int n,int r,int c)
{
if(r>=1 && r<=n && c>=1 && c<=n)
return true;
return false;
}
int main()
{
pair<int,int>d1,d2,d3,d4,temp;
d1 = make_pair(0,1);
d2 = make_pair(1,0);
d3 = make_pair(0,-1);
d4 = make_pair(-1,0);
/**********************direction******************************/
int n, i, j, counter=1, newR = 1, newC = 0, direction = 4;
bool changeDir=true;
/**************************variables*************************/
cin>>n;
int arr[n+1][n+1];
int visited[n+1][n+1];
/*************************arrays********************************/
memset(visited,0,sizeof(visited));
memset(arr,0,sizeof(arr));
/***************initializing the array**************************/
while(counter<=n*n)
{
if(direction==1 && changeDir)
{
temp = make_pair(d2.first,d2.second);
direction=2;
changeDir=false;
}
else if(direction==2&& changeDir)
{
temp = make_pair(d3.first,d3.second);
direction=3;
changeDir=false;
}
else if(direction==3&& changeDir)
{
temp = make_pair(d4.first,d4.second);
direction=4;
changeDir=false;
}
else if(direction==4&& changeDir)
{
temp = make_pair(d1.first,d1.second);
direction=1;
changeDir=false;
}
while(counter<=(n*n) && !changeDir)
{
newR =newR+temp.first;
newC=newC+temp.second;
if(valid(n,newR,newC) && !visited[newR][newC])
{
arr[newR][newC]=counter;
visited[newR][newC]=1;
counter++;
}
else
{
newR-=temp.first;
newC-=temp.second;
changeDir=true;
break;
}
}
}
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
{
if(arr[i][j]<10)
cout<<0;
cout<<arr[i][j]<<" ";
}
cout<<endl;
}
return 0;
}
Here is the output where N=5:
01 02 03 04 05
16 17 18 19 06
15 24 25 20 07
14 23 22 21 08
13 12 11 10 09
Thank you.
I found a way. Now I've to improve it a bit, especially I've to find a cleaner way to build "fdisp". n = 5
dim = n
pos = (0, -1)
fdisp = []
squares = n % 2 == 0 and n / 2 or n / 2 + 1
for _ in range(squares):
pos = (pos[0], pos[1] + 1)
fdisp.append(pos)
fdisp += [(pos[0],pos[1]+i) for i in range(1, dim)]
pos = fdisp[-1]
fdisp += [(pos[0]+i,pos[1]) for i in range(1, dim)]
pos = fdisp[-1]
fdisp += [(pos[0],pos[1]-i) for i in range(1, dim)]
pos = fdisp[-1]
fdisp += [(pos[0]-i,pos[1]) for i in range(1, dim - 1)]
pos = fdisp[-1]
dim = dim - 2
matrix = [[0] * n for i in range(n)]
for val,i in enumerate(fdisp):
matrix[i[0]][i[1]] = val + 1
def show_matrix(matrix, n):
for i,l in enumerate(matrix):
for j in range(n):
print "%d\t" % matrix[i][j],
print
show_matrix(matrix, n)