Helping Filling and Printing a 2D Array

I was assigned a project to create a magic square. If anybody is not familiar with that, it is where each row, column, and both diagnosis sum to the same number. I ask the user to select the size of the magic square and make sure the entered size is any odd number between 0 and 20. Sorry if there are obvious mistakes. I've had a lot of work to do lately and I haven't gotten much sleep. Any help or hints is greatly appreciated.

Here are the rules for generating the magic square:

Let k be an integer that has the values from 1 to n^2.
Place one (1) in the last column, middle row.
Next continue to fill the grid by placing k + 1 in the cell one column to the right and one row down from the cell where k was placed except when one of the following occurs:
1. if a move takes you below the bottom row in the jth column, then place k + 1 in the top row of the jth column;
2. if a move takes you outside to the right of the ith row, then place k + 1 in the 1st (left) column of the ith row;
3. or if a move takes you to a cell that is already occupied or outside the cell in the lower right corner, then k +1 should be placed immediately to the left of k.

Here is the code for the three functions I created.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
//Initializes all the array elements to zero
void zeros (int a[][19], int size)
{
	for (int k=0; k < (size*size); k++) 
	{
		for (int i=0; i<size; i++)
		{
			for (int j=0; j<size; j++)
			{
				a[i][j] = 0;
			}
		}
	}
}


//Fills the array based on the rules for generating the magic square
void FillArray (int a[][19], int size)
{
	int row, column;
	int i, j;

	for (int k=0; k < (size*size); k++) 
	{
		row = ((size+1)/2);
		column = size;
		a[row][column] = 1;

		for (i=0; i<size; i++)
		{
			for (j=0; j<size; j++)
			{
				if (a[i][j] == 0)
				{
					row = i+1;
					column = j+1;
					a[row][column] = k+1;
					if (column > size)
					{
						row = 0;
						column = size;
						a[row][column] = k+1;
					}
					else if (row > size)
					{
						row = i+1;
						column = 0;
						a[row][column] = k+1;
					}
					else if (a[i][j] != 0 || row+column > (size+size))
					{
						row = i-1;
						column = j-1;
						a[row][column] = k+1;
					}
				}
			}
		}
	}

}

//Prints the magic square 
void PrintArray (int a[][19], int size)	 fixed
{
	for (int k=0; k < (size*size); k++) 
	{
		for (int i=0; i<size; i++)
		{
			for (int j=0; j<size; j++)
			{
				cout << a[i][j] << "\t";
			}
		}
		cout << endl;
	}
}
Does anybody have idea?

I could pin point the question and ask what specifically in wrong in just the function called FillArray that fills the array based on the following rules:
Let k be an integer that has the values from 1 to n^2.
Place one (1) in the last column, middle row.
Next continue to fill the grid by placing k + 1 in the cell one column to the right and one row down from the cell where k was placed except when one of the following occurs:
1. if a move takes you below the bottom row in the jth column, then place k + 1 in the top row of the jth column;
2. if a move takes you outside to the right of the ith row, then place k + 1 in the 1st (left) column of the ith row;
3. or if a move takes you to a cell that is already occupied or outside the cell in the lower right corner, then k +1 should be placed immediately to the left of k.


Once again, here is the code.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
void FillArray (int a[][19], int size)
{
	int row, column;
	int i, j;

	for (int k=0; k < (size*size); k++) 
	{
		row = ((size+1)/2);
		column = size;
		a[row][column] = 1;

		for (i=0; i<size; i++)
		{
			for (j=0; j<size; j++)
			{
				if (a[i][j] == 0)
				{
					row = i+1;
					column = j+1;
					a[row][column] = k+1;
					if (column > size)
					{
						row = 0;
						column = size;
						a[row][column] = k+1;
					}
					else if (row > size)
					{
						row = i+1;
						column = 0;
						a[row][column] = k+1;
					}
					else if (a[i][j] != 0 || row+column > (size+size))
					{
						row = i-1;
						column = j-1;
						a[row][column] = k+1;
					}
				}
			}
		}
	}

}
Maybe asking questions like this will help get a response. The rule or step will be in grey and the corresponding piece of code will be in blue.

function definition and variables declared
1
2
3
4
void FillArray (int a[][19], int size)
{
	int row, column;
	int i, j;


Let k be an integer that has the values from 1 to n^2.
for (int k=0; k < (size*size); k++)

Place one (1) in the last column, middle row.

I think this will always make it so the number 1 will be initially placed in the middle row of the last column.
1
2
3
row = ((size+1)/2);
		column = size;
		a[row][column] = 1;


Next continue to fill the grid by placing k + 1 in the cell one column to the right and one row down from the cell where k was placed
1
2
3
4
5
6
7
8
9
for (i=0; i<size; i++)
		{
			for (j=0; j<size; j++)
			{
				if (a[i][j] == 0)
				{
					row = i+1;
					column = j+1;
					a[row][column] = k+1;


except when one of the following occurs:

1. if a move takes you below the bottom row in the jth column, then place k + 1 in the top row of the jth column;
1
2
3
4
5
6
if (column > size)
					{
						row = 0;
						column = size;
						a[row][column] = k+1;
					}



2. if a move takes you outside to the right of the ith row, then place k + 1 in the 1st (left) column of the ith row;
1
2
3
4
5
6
else if (row > size)
					{
						row = i+1;
						column = 0;
						a[row][column] = k+1;
					}



3. or if a move takes you to a cell that is already occupied or outside the cell in the lower right corner, then k +1 should be placed immediately to the left of k.
1
2
3
4
5
6
else if (a[i][j] != 0 || row+column > (size+size))
					{
						row = i-1;
						column = j-1;
						a[row][column] = k+1;
					}


Here is what the output should be for a 3x3 magic square
1
2
3
4   3   8
9   5   1
2   7   6


and is my output for a 3x3 magic square
1
2
3
4
5
6
7
8
9
0       0       0       0       9       9       0       9       0
0       0       0       0       9       9       0       9       0
0       0       0       0       9       9       0       9       0
0       0       0       0       9       9       0       9       0
0       0       0       0       9       9       0       9       0
0       0       0       0       9       9       0       9       0
0       0       0       0       9       9       0       9       0
0       0       0       0       9       9       0       9       0
0       0       0       0       9       9       0       9       0
Last edited on
closed account (D80DSL3A)
I'v been watching your thread but I was waiting until I got your program working myself before responding.

I think your approach is flawed as follows:
You loop through k = 0 to N*N-1 OK, but your effort to somehow assign values to the a[i][j] by iterating over i and j directly (as in the 2 for loops) and applying the rules along the way seems like the wrong way.

According to:
Let k be an integer that has the values from 1 to n^2.
Place one (1) in the last column, middle row.


We start with row = N/2; (not (N+1)/2, check it. N=7 expect midRow = 3 and 7/2 = 3)
and col = N-1
1st assignment then is to:a[N/2][N-1] = 1;
Of course that's actually a[row][col] = k; but row = N/2, col = N-1 and k = 1 right now.

From this point on you must let the rules be your guide in assigning values for row and col for the next assignment (of k+1).
There will be no for loops over i or j, just the for loop over k.

Here's what I have starting off:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
    unsigned N = 3;
    unsigned** pSq = new unsigned int*[N];
    for( unsigned i = 0; i < N; ++i )
        pSq[i] = new unsigned int[N]();

    unsigned row = N/2;// current row
    unsigned col = N - 1;// current col
    unsigned int k = 1;// value for: pSq[row][col] = k;

    while( k <= N*N )// one element will be assigned each iteration
    {
        // new k to be used
        pSq[row][col] = k;

        // find k, row, col for next loop
        ++k;
        if( k > N*N ) break;
        
        // apply rules to find next values for row and col
    }


The "usual" rule for the next value of row is row+1, and for col it is col+1

** exceptions **
rule #1: if move would be to below square
col += 1; row = 0; instead of row+=1, col+=1 (typ)

rule #2: if move would be to right of square
row+= 1; col = 0;

rule #3 i move would be to below and right of square (ie from [N-1][N-1])
col -= 1; row = row; (ie no change). This is a move to the left.

The key (I found) was that the rule about moving left if an element has already been assigned applies to ALL moves, so after figuring new row and col values based on the other rules, you must apply "move left if occupied" until an unassigned space is found.

I wrote a moveLeft() function. You give it the values for row, col which the rules would give, it keeps going left until it finds a space where a = 0 still.

The instructions seemed unclear regarding the move left:
if a move takes you to a cell that is already occupied..., then k +1 should be placed immediately to the left of k.

What if col = 0? Wrap to col=N-1? What about row? If col changes, does row decrease? If row=0, col=0 do we move to N-1, N-1? Turns out, yes to all.
This is what "move left" means.

I hope that is enough of a hint. Post back if you have problems or questions with this approach.

Using this algorithm I was able to get the following for N=3,5,7:

for N = 3

4  3  8
9  5  1
2  7  6

row sums = 15 15 15
col sums = 15 15 15
diag sums = 15 15

for N = 5

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

row sums = 65 65 65 65 65
col sums = 65 65 65 65 65
diag sums = 65 65

for N = 7

22 21 13 5  46 38 30
31 23 15 14 6  47 39
40 32 24 16 8  7  48
49 41 33 25 17 9  1
2  43 42 34 26 18 10
11 3  44 36 35 27 19
20 12 4  45 37 29 28

row sums = 175 175 175 175 175 175 175
col sums = 175 175 175 175 175 175 175
diag sums = 175 175
Last edited on
Thanks a lot for helping me out. I had a lab that went long today and I didn't see your post until about an hour ago.

This is the code I have so far, but it does not work at all. I think my biggest issue is I'm not sure how to define moveLeft and where to call it. Also, just to let you know, I can't use "break", "continue", or "goto".

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
//Fills the array based on the rules for generating the magic square
void FillArray (int a[][19], int n)
{
	int row, col;

	row = n/2;
	col = n-1;
	a[row][col] = 1;

	for (int k=0; k < n*n; k++)
	{
		a[row][col] = k;

		if (col > n)	//If move is to the right of the last column
		{
			row = row +1;
			col = 0;
			
			if (a[row][col] != 0)
			{
			moveLeft (a, row, col);
			}
			a[row][col] = k+1;
		}
		
		else if (row > n)	//If move is below the last row
		{
			row = 0;
			col = col +1;
			
			if (a[row][col] != 0)
			{
			moveLeft (a, row, col);
			}
			a[row][col] = k+1;
		}

		else if (a[row][col] != 0 || row+col > (n+n))	//If move is outside of lower right corner 
		{
			row = row;
			col = col - 1;
		
			if (a[row][col] != 0)
			{
			moveLeft (a, row, col);
			}
			a[row][col] = k+1;
		}
	}
}
				

//Moves left to fill magic square based on rules
void moveLeft (int a[][19], int row, int col)
{
	int i, j;
	i = row - 1;
	j = col;

	//a[i][j] = a[row][col]; //seems like this should go here but nothing prints when it is used
}


By the way, this is my main function.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
int main ()
{
	int array1 [19][19];
	int size;

	cout << "This program allows you to create a magic square using a 2 dimensional array.\n";
	cout << "You set the size of the 2D array by choosing an odd number between 1 and 20.\n\n";
	cout << "Enter the size you want the magic square to be: ";
	cin >> size;

	
	while (size < 1 && size > 20)
	{
		cout << "You must enter an odd number between 1 and 19\n"; 
		cin >> size;
	}

	while (size % 2 == 0)
	{
		cout << "You must enter an odd number between 1 and 19\n"; 
		cin >> size;
	}

	zeros (array1, size);

	FillArray (array1, size);

	PrintArray (array1, size);

	return 0;
}
Last edited on
Topic archived. No new replies allowed.