I used the following algorithm:
- Place initial number at middle of top row (e.g. k). False: you start in the second column and the first row (always, independent of the variable
size
---which should be odd, but you don't say this) This is important to make the two diagonals to add up to the same value of the rows/columns
- Move up one row and right one column and place k+1. False: you move down one row and right one column. You need to decrement the row (to move up) and increment the column (to move right).
- If move takes you above top row or left column, go to bottom row(or left column). You try to implement this in a very complex way. When you get to the bottom (
col == size
, after incrementing) you have to move to the top (col = 0
, or col -= size
, as you have incremented it you need to move up size
rows, not size + 1
)
- If move takes you to prefilled square or you move out of right corner square, place k+1 immediately below k. This is one row increment.
Well this is the known formula for a magic square (one that fills a square matrix with the numbers 1
to size*size
in a way that all rows add to the same number, all columns the same and the two grand diagonals too.)
The thing (after solving all the things you don't do well) should go in a way similar to this:
/* ms.c -- magic square.
* Author: Luis Colorado.
* Date: Fri 03 Sep 2021 02:08:34 PM EEST
* Copyright: (C) 2021 Luis Colorado. All rights reserved.
* License: BSD.
*/
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#define MAX 1023
#define DFLT 11
int square[MAX][MAX];
int sum_main_diag,
sum_anti_diag,
sum_cols[MAX],
sum_rows[MAX];
char DOUBLE_LINE[] = "========================";
char SINGLE_LINE[] = "------------------------";
int main(int argc, char **argv)
{
int opt; /* option */
int size = DFLT;
while ((opt = getopt(argc, argv, "n:")) >= 0) {
switch (opt) {
case 'n': size = atoi(optarg);
if (size < 1 /* size must be >= 1 */
|| size > MAX /* and <= MAX */
/* || !(size & 1) */) /* ...and odd, commented (see below) */
{
fprintf(stderr,
"N defaulting to %d, as provided "
"value (%s) was invalid\n",
DFLT, optarg);
size = DFLT;
}
break;
} /* switch */
}
int row = 0, /* top row */
col = size/2, /* middle cell */
total = size * size, /* total number of cells */
i; /* number to put in the cell */
for (i = 1; i <= total; i++) {
square[row][col] = i; /* fill the square */
if (row == col) { /* add to anti_diag */
sum_anti_diag += i;
}
if (row + col + 1 == size) { /* add to main diag */
sum_main_diag += i;
}
sum_cols[col] += i; /* add to col */
sum_rows[row] += i; /* add to row */
int nxtrow = row, /* next row to go */
nxtcol = col; /* next col to go */
nxtrow--;
if (nxtrow < 0) { /* top row */
nxtrow = size - 1; /* rules 2 & 3 */
}
nxtcol++;
if (nxtcol >= size) { /* right column */
nxtcol = 0; /* rules 2 & 3 */
}
if (square[nxtrow][nxtcol]) { /* rule four */
/* next cell is the located below the initial */
nxtrow = row + 1;
if (nxtrow >= size) { /* check boundary, not needed */
nxtrow = 0;
}
nxtcol = col;
}
col = nxtcol; /* ... update */
row = nxtrow;
}
/* print them all */
int digs = snprintf(NULL, 0, "%d", total);
int digs_sums = snprintf(NULL, 0, "%d", total*(total+1)/2/size);
for (row = 0; row < size; row++) {
printf("%*s +", digs_sums, "");
for (col = 0; col < size; col++)
printf("%.*s+", digs_sums, SINGLE_LINE);
printf("\n%*d |", digs_sums, row);
for (col = 0; col < size; col++) {
printf("%*d|", digs_sums, square[row][col]);
int val = square[row][col];
}
printf(" ==> %*d\n", digs, sum_rows[row]);
}
printf("%*s +", digs_sums, "");
for (col = 0; col < size; col++)
printf("%.*s+", digs_sums, DOUBLE_LINE);
printf("\n%*d/|", digs, sum_anti_diag);
for (col = 0; col < size; col++)
printf("%*d|", digs, sum_cols[col]);
printf("\\ %d\n", sum_main_diag);
return 0; /* OK exit code */
}
that will print something like:
$ ms -n 3
+--+--+--+
0 | 8| 1| 6| ==> 15
+--+--+--+
1 | 3| 5| 7| ==> 15
+--+--+--+
2 | 4| 9| 2| ==> 15
+==+==+==+
15/|15|15|15|\ 15
$ ms -n 5
+--+--+--+--+--+
0 |17|24| 1| 8|15| ==> 65
+--+--+--+--+--+
1 |23| 5| 7|14|16| ==> 65
+--+--+--+--+--+
2 | 4| 6|13|20|22| ==> 65
+--+--+--+--+--+
3 |10|12|19|21| 3| ==> 65
+--+--+--+--+--+
4 |11|18|25| 2| 9| ==> 65
+==+==+==+==+==+
65/|65|65|65|65|65|\ 65
$ ms -n 6 # I've commented the odd test to see that the magic square is invalid.
+---+---+---+---+---+---+
0 | 19| 27| 35| 1| 9| 17| ==> 108
+---+---+---+---+---+---+
1 | 26| 34| 6| 8| 16| 24| ==> 114
+---+---+---+---+---+---+
2 | 33| 5| 7| 15| 23| 25| ==> 108
+---+---+---+---+---+---+
3 | 4| 12| 14| 22| 30| 32| ==> 114
+---+---+---+---+---+---+
4 | 11| 13| 21| 29| 31| 3| ==> 108
+---+---+---+---+---+---+
5 | 18| 20| 28| 36| 2| 10| ==> 114
+===+===+===+===+===+===+
123/|111|111|111|111|111|111|\ 93
$ ms
+---+---+---+---+---+---+---+---+---+---+---+
0 | 68| 81| 94|107|120| 1| 14| 27| 40| 53| 66| ==> 671
+---+---+---+---+---+---+---+---+---+---+---+
1 | 80| 93|106|119| 11| 13| 26| 39| 52| 65| 67| ==> 671
+---+---+---+---+---+---+---+---+---+---+---+
2 | 92|105|118| 10| 12| 25| 38| 51| 64| 77| 79| ==> 671
+---+---+---+---+---+---+---+---+---+---+---+
3 |104|117| 9| 22| 24| 37| 50| 63| 76| 78| 91| ==> 671
+---+---+---+---+---+---+---+---+---+---+---+
4 |116| 8| 21| 23| 36| 49| 62| 75| 88| 90|103| ==> 671
+---+---+---+---+---+---+---+---+---+---+---+
5 | 7| 20| 33| 35| 48| 61| 74| 87| 89|102|115| ==> 671
+---+---+---+---+---+---+---+---+---+---+---+
6 | 19| 32| 34| 47| 60| 73| 86| 99|101|114| 6| ==> 671
+---+---+---+---+---+---+---+---+---+---+---+
7 | 31| 44| 46| 59| 72| 85| 98|100|113| 5| 18| ==> 671
+---+---+---+---+---+---+---+---+---+---+---+
8 | 43| 45| 58| 71| 84| 97|110|112| 4| 17| 30| ==> 671
+---+---+---+---+---+---+---+---+---+---+---+
9 | 55| 57| 70| 83| 96|109|111| 3| 16| 29| 42| ==> 671
+---+---+---+---+---+---+---+---+---+---+---+
10 | 56| 69| 82| 95|108|121| 2| 15| 28| 41| 54| ==> 671
+===+===+===+===+===+===+===+===+===+===+===+
671/|671|671|671|671|671|671|671|671|671|671|671|\ 671
$ _
(parameter -n
allows any odd number between 1 and 1023, and defaults ---e.g. option is not used--- to 11)