Klausj
Published © GPL3+

Magic Squares 4x4 all possible ones on TFT

While there are tons of Smartphone Apps for magic square this one is for Arduino UNO R3 and Arduino DUE.

BeginnerFull instructions provided1 hour88
Magic Squares 4x4 all possible ones on TFT

Things used in this project

Story

Read more

Code

Magic Squares 4x4 displayed on TFT

Arduino
All possible solutions are shown one by one
/*
  msq4.c ver 1.5 by K.Muroi 2004.04.30
  https://www.netstaff.co.jp/msq/msq4-src.gz

  UNO R3:
  init:  97 milliseconds
  searching:  8715 milliseconds
  printing: 6947 milliseconds
  using TFT display: 87 minutes (5 sec-delay)
  without delay: 14:12
*/

#include <TFT.h> // UNO R3 only
/*
  surprise:
  TFT exports a MACRO named "swap"
  don't declare it yourself!
*/
// pin definition for the Uno
#define cs   10
#define dc   9
#define rst  8
TFT tft = TFT(cs, dc, rst);

struct cell {
  int left;
  int top;
};

/* set textSize to 1 to increase the speed */
const byte textSize = 3;
const byte charW = 13 * textSize;
const byte charH = 13 * textSize;
const byte left = 3;
const byte top =  0;
const byte COLS = 4;
const byte MAX = COLS * COLS;
const byte SUM = (1 + MAX) * MAX / 2 / COLS;
int width, height;
cell disp[MAX];
char str[2 * MAX + 2];
int colour[MAX + 1];
byte oldValue[MAX + 1];
const byte SPEAKER = 7;

#define SQUARE

int8_t a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p;
int nSet[87][4];
long nBit[87], nChk0, nChk1, nChk2;
long T0;
int N = 0;

void setup() {
  long t = millis() + 5000; // for R4
  Serial.begin(115200);
  while (!Serial && millis() < t);
  Serial.println(F(__FILE__));
  Serial.println(F(__TIME__));
  // TFT:
  tft.begin();
  tft.setRotation(3);
  tft.fillScreen(tft.Color565(16, 0, 0));
  tft.setTextSize(textSize);
  height = tft.height();
  // calculate the positions of the 16 cells
  for (int i = 0; i < MAX; i++) {
    disp[i].left = left + 1 + (i & 3) * charW;
    disp[i].top  = top + 2 + (i / 4) * (charH - 5);
    oldValue[i] = -1;
  }
  for (int i = 1; i <= MAX; i++) {
    colour[i] = hue(i);
    str[i * 2] = i < 10 ? ' ' : '1';
    str[i * 2 + 1] = '0' + i % 10;
    // preset: black
    dispNumAtpos(0, i);
  }
  // end TFT
  // init the array:
  T0 = millis();
  for (byte n0 = 1; n0 <= MAX; n0++) {
    for (byte n1 = 1; n1 <= MAX; n1++) {
      for (byte n2 = 1; n2 <= MAX; n2++) {
        for (byte n3 = 1; n3 <= MAX; n3++) {
          if ((n0 + n1 + n2 + n3 == SUM) &&
              (n0 < n1) && (n1 < n2) && (n2 < n3))
          {
            N++; // so N goes up to 86
            nSet[N][0] = n0;
            nSet[N][1] = n1;
            nSet[N][2] = n2;
            nSet[N][3] = n3;
            nBit[N] = (1UL << n0 | 1UL << n1 | 1UL << n2 | 1UL << n3);
          }
        }
      }
    }
  }
}

void loop() {
  /*
    o  1 2 3 4
    1  a b c d
    2  e f g h
    3  i j k l
    4  m n o p
  */
  // now look for solutions:
  long pt = 0;
  long T1 = millis();
  N = 0;
  for (byte n0 = 1; n0 < 87; n0++) {
    long v0 = nBit[n0];
    a = nSet[n0][0]; // a <----------- upper left
    dispNumAtpos(a, 0);
    d = nSet[n0][1]; // d <-----
    p = nSet[n0][2]; // p <----
    m = nSet[n0][3]; // m <----
    for (byte a1 = 0; a1 < 3; a1++) {
      switch (a1) {
        case 0 :
          break;
        case 1 :
          swap(d, p); // d, p <-------
          break;
        case 2 :
          swap(m, p); // m, p <-------
          break;
      }
      dispNumAtpos(d, 3);  // other corners
      dispNumAtpos(m, 12);
      dispNumAtpos(p, 15);
      long as = 1L << a;
      long ds = 1L << d;
      long ps = 1L << p;
      long ms = 1L << m;
      for (byte n1 = 1; n1 < 87; n1++)
        for (byte n2 = 1; n2 < 87; n2++) {
          long v1 = nBit[n1];
          long v2 = nBit[n2];
          if ( ( (v0 & v1) == (as | ps) ) &&
               ( (v0 & v2) == (ds | ms) ) &&
               ( (v1 & v2) == 0 ) ) {
            nChk0 = v0 | v1 | v2;
            for (byte cn01 = 0; cn01 <= 3; cn01++) {
              int nSetN1CN01 = nSet[n1][cn01];
              if (nSetN1CN01 != a && nSetN1CN01 != p) {
                f = nSetN1CN01;   // f <-------------------
                for (byte cn11 = 0; cn11 <= 3; cn11++) {
                  int nSetN1CN11 = nSet[n1][cn11];
                  if (nSetN1CN11 != a &&
                      nSetN1CN11 != f &&
                      nSetN1CN11 != p) {
                    k = nSetN1CN11; // k <-----------------
                  }
                }
              }
            }
            byte cg, cj;
            for (byte cn02 = 0; cn02 <= 3; cn02++) {
              int nSetN2CN02 = nSet[n2][cn02];
              if (nSetN2CN02 != d &&
                  nSetN2CN02 != m) {
                cg = nSetN2CN02;
                for (byte cn21 = 0; cn21 <= 3; cn21++) {
                  int nSetN2CN21 = nSet[n2][cn21];
                  if (nSetN2CN21 != d &&
                      nSetN2CN21 != cg &&
                      nSetN2CN21 != m) {
                    cj = nSetN2CN21;
                  }
                }
              }
            }
            for (byte d0 = 0; d0 < 2; d0++) {
              if (d0 == 1) swap(f, k);
              dispNumAtpos(f, 5);
              dispNumAtpos(k, 10);
              g = cg;  // g <----------
              j = cj;  // j <----------
              for (byte d1 = 0; d1 < 2; d1++) {
                if (d1 == 1) swap(g, j);
                dispNumAtpos(g, 6);
                dispNumAtpos(j, 9);
                for (b = 1, c = SUM - a - b - d, n = SUM - b - f - j, o = SUM - m - n - p;
                     b <= MAX; b++, c--, n--, o++) {
                  // b, c, n, o <--------------------
                  if ((nChk0 & (1UL << b)) ||
                      (nChk0 & (1UL << c)) ||
                      (nChk0 & (1UL << n)) ||
                      (nChk0 & (1UL << o)) ||
                      c <= 0 ||
                      c > MAX ||
                      n <= 0 ||
                      n > MAX ||
                      o <= 0 ||
                      o > MAX ||
                      (c == b) ||
                      (n == b) ||
                      (o == b) ||
                      (n == c) ||
                      (o == c) ||
                      (n == o)) {
                    continue;
                  }
                  dispNumAtpos(b, 1);
                  dispNumAtpos(c, 2);
                  dispNumAtpos(n, 13);
                  dispNumAtpos(o, 14);
                  nChk1 = nChk0 | (1UL << b) | (1UL << c) | (1UL << n) | (1UL << o);
                  for (e = 1, i = SUM - a - e - m, h = SUM - e - f - g, l = SUM - d - h - p;
                       e <= MAX;
                       e++, i--, h--, l++) {
                    // e, i, h, l <-------------------
                    if ((nChk1 & (1UL << e)) ||
                        (nChk1 & (1UL << i)) ||
                        (nChk1 & (1UL << h)) ||
                        (nChk1 & (1UL << l)) ||
                        i <= 0 ||
                        i > MAX ||
                        h <= 0 ||
                        h > MAX ||
                        l <= 0 ||
                        l > MAX ||
                        (i == e) ||
                        (i == e) ||
                        (h == e) ||
                        (l == i) ||
                        (l == h) ||
                        (h == i)) {
                      continue;
                    }
                    dispNumAtpos(e, 4);
                    dispNumAtpos(i, 8);
                    dispNumAtpos(h, 7);
                    dispNumAtpos(l, 11);
                    long pt1 = millis();
                    N++;
                    Serial.print(N);
                    Serial.print(": ");
                    int t = millis() / 1000;
                    Serial.print(t / 60);
                    Serial.print(":");
                    Serial.println(t % 60);
                    print();
                    if (a + f + k + p == SUM) Serial.print(F(" diagonale-1"));
                    if (d + g + j + m == SUM) Serial.print(F(" diagonale-2"));
                    if (b + g + l + m == SUM) Serial.print(F(" panmagisch-1"));
                    if (c + h + i + n == SUM) Serial.print(F(" panmagisch-2"));
                    if (d + e + j + o == SUM) Serial.print(F(" panmagisch-3"));
                    if (a + h + k + n == SUM) Serial.print(F(" panmagisch-4"));
                    if (b + e + l + o == SUM) Serial.print(F(" panmagisch-5"));
                    if (c + f + i + p == SUM) Serial.print(F(" panmagisch-6"));
                    if ( (a + p == 17) && (f + k == 17) && (d + m == 17) && (j + g == 17) )
                      Serial.print(F(" symmetrisch"));
                    if ( (a + b + e + f == SUM) &&
                         (b + c + f + g == SUM) &&
                         (c + d + g + h == SUM) &&
                         (e + f + i + j == SUM) &&
                         (f + g + j + k == SUM) &&
                         (g + h + k + l == SUM) &&
                         (i + j + m + n == SUM) &&
                         (j + k + n + o == SUM) &&
                         (k + l + o + p == SUM) )
                      Serial.print(F(" super-magisch"));
                    Serial.println();
                    long pt2 = millis();
                    pt = pt + pt2 - pt1;
                    dispNumAtpos(0, 4); // left center
                    dispNumAtpos(0, 8);
                    dispNumAtpos(0, 7); // right center
                    dispNumAtpos(0, 11);
                  }
                  dispNumAtpos(0, 1); // top center b, c
                  dispNumAtpos(0, 2);
                  dispNumAtpos(0, 13); // bottom center n, o
                  dispNumAtpos(0, 14);
                }
                dispNumAtpos(0, 6); // center g, j
                dispNumAtpos(0, 9);
              }
              dispNumAtpos(0, 5); // center f, k
              dispNumAtpos(0, 10);
            }
          }
        }
      dispNumAtpos(0, 3); // corners, d, m, p
      dispNumAtpos(0, 12);
      dispNumAtpos(0, 15);
    }
    dispNumAtpos(0, 0); // a
  }
  long T2 = millis();
  Serial.print(F("init:\t"));
  Serial.print(T1 - T0);
  Serial.println(F(" milliseconds"));
  Serial.print(F("searching:\t"));
  Serial.print(T2 - T1 - pt);
  Serial.println(F(" milliseconds"));
  Serial.print(F("printing:\t"));
  Serial.print(pt);
  Serial.println(F(" milliseconds"));
}

void print() {
  tone(SPEAKER, 400, 250);
  print2(a);
  print2(b);
  print2(c);
  print2(d);
#ifdef SQUARE
  Serial.println();
#endif
  print2(e);
  print2(f);
  print2(g);
  print2(h);
#ifdef SQUARE
  Serial.println();
#endif
  print2(i);
  print2(j);
  print2(k);
  print2(l);
#ifdef SQUARE
  Serial.println();
#endif
  print2(m);
  print2(n);
  print2(o);
  print2(p);
  Serial.println();
  delay(5000);
  //noTone(SPEAKER);
}

void print2(byte x) {
  char ch[] = "   ";
  if (x > 9) ch[1] = '1';
  ch[2] = '0' + x % 10;
  Serial.print(ch);
}

// positions: 0 ... 15
// numbers:   1 ... 16
void dispNumAtpos(byte number, byte position) {
  if (number == oldValue[position]) return;
  // erase the number
  tft.fillRect(disp[position].left, disp[position].top - 1, textSize * 11, textSize * 8, ST7735_BLACK);
  oldValue[position] = number;
  if (number < 1) return;
  if (number > MAX) return;
  tft.setCursor(disp[position].left, disp[position].top);
  int farbe = colour[number];
  tft.setTextColor(farbe);
  number = number * 2;
  tft.print(str[number++]);
  tft.print(str[number]);
}

word hue(float z) {
  int M = 127;
  float h = z * M * 6 / 17;
  int g = max(-abs(h - 2 * M) + 3 * M - M, 0);
  int r = max(+abs(h - 3 * M) + 0 * M - M, 0);
  int b = max(-abs(h - 4 * M) + 3 * M - M, 0);
  return tft.Color565(b, g, r);
}

Improved version

Arduino
Modified to recursive algorithm
No preview (download only).

Improved version

Arduino
Support for Arduino DUE, added control buttons and speaker. Select letters rather than numbers
No preview (download only).

Credits

Klausj
89 projects • 8 followers
Thanks to K. Muroi, Japan.

Comments