I had to change the sense of some of the commented if statements, but that seems to work to filter out the reflections to produce 880 solutions:
/*
Magische Quadrate 4x4, rekursiv
Serial only version
*/
struct cell {
int left;
int top;
};
int w, h;
const byte cols = 4;
const byte maxi = cols * cols;
const byte sum = (maxi + 1) * maxi / 2 / cols;
byte p[maxi];
int colour[maxi + 1];
// Reihenfolge, in der die Werte gesetzt werden:
const byte seq[] = {
0, 1, 2, 3,
4, 5, 6, 7,
8, 10, 12, 13,
9, 11, 14, 15
};
/* die Positionen:
_0 _1 _2 3 alle Postionen ohne "_"
_4 _5 _6 7 koennen berechnet werden!
_8 _9 10 11
12 13 14 15
*/
cell disp[maxi];
char str[2 * maxi + 2];
int count = 0;
const byte charW = 13;
const byte charH = 13;
const byte left = 39;
const byte top = 59;
const byte p0 = 2;
const byte p1 = 102;
byte solution[maxi + 1] = {0};
void setup() {
Serial.begin(115200);
Serial.println(F(__FILE__));
// calculate the positions of the 16 cells
for (int i = 0; i < maxi; i++) {
int j = seq[i];
disp[j].left = left + 1 + (i & 3) * charW;
disp[j].top = top + 2 + (i / 4) * charH;
}
// Generate the strings to display the numbers faster
str[0] = 0xDB;
str[1] = 0xDB;
for (int i = 1; i <= maxi; i++) {
// colour[i] = hue(i);
str[i * 2] = i < 10 ? ' ' : '1';
str[i * 2 + 1] = '0' + i % 10;
dispNumAtpos(0, i);
}
// start the recursion:
place(0, 0xFFFF);
// finished and ready.
Serial.print(F("Complete ["));
Serial.print(millis() / 1000);
Serial.println(F(" sec]"));
}
void loop() {}
void place(byte pos, int avail) {
byte i;
switch (pos) {
case 0: case 1: case 2: case 4: case 5: case 6: case 8:
for (i = 1; i <= maxi; i++) Try(pos, i, avail); break;
case 3: i = rem3(0, 1, 2); if (p[0] < i)
Try(pos, i, avail); break;
// Row 1, mirrored on the vertical axis
case 7: i = rem3(4, 5, 6); Try(pos, i, avail); break; // Zeile 2
case 9: i = rem3(0, 4, 8); if ((p[0] < i) && (p[3] > i))
//if(p[3] > i)
Try(pos, i, avail); break; // Spalte 1
case 10: i = rem3(9, 6, 3); Try(pos, i, avail); break; // /-diagonal
case 11: i = rem3(1, 5, 10); Try(pos, i, avail); break; // Spalte 2
case 12: i = rem3(5, 6, 10); Try(pos, i, avail); break; // mittlerer Block
case 13: i = rem3(8, 10, 12); Try(pos, i, avail); break; // Zeile 3
case 14: i = rem3(2, 6, 12); Try(pos, i, avail); break; // Spalte 3
case 15: i = rem3(3, 7, 13); if (p[0] < i)
Try(pos, i, avail); break;
// Column 4, mirrored on the main diagonal
case 16: if (rem3(0, 5, 12) == p[15]) {
// signal the current solution
Serial.print(F("Solution #"));
Serial.print(++count);
Serial.print(F(" ["));
Serial.print(millis() / 1000);
Serial.println(F(" sec]:"));
for (size_t pr = 0; pr < maxi; pr++) {
Serial.print(str[solution[seq[pr]] * 2]);
Serial.print(str[solution[seq[pr]] * 2 + 1]);
Serial.print(' ');
if (((pr + 1) % cols) == 0) {
Serial.println();
}
}
Serial.println();
}
}
}
void Try(byte pos, byte value, int avail) {
if ((value < 1) || (value > maxi)) return; // ungueltige Zahl
int mask = 1 << (value - 1);
if (avail & mask) {
p[pos] = value;
dispNumAtpos(value, pos);
place(pos + 1, avail & ~mask);
dispNumAtpos(0, pos); // loesche Zelle
p[pos] = 0;
}
}
byte rem3(byte a, byte b, byte c) { // gib den Rest zurueck
return sum - p[a] - p[b] - p[c];
}
void dispNumAtpos(byte number, byte position) {
solution[position] = number;
}
On an Uno R3:
...
Solution #879 [115 sec]:
7 16 1 10
4 13 12 5
14 3 6 11
9 2 15 8
Solution #880 [115 sec]:
7 16 1 10
12 5 4 13
6 11 14 3
9 2 15 8
Complete [150 sec]:
It feels a bit wrong to filter out the exhaustive search and then plan to reflect/rotate the 880 that pass.