/* * File: SelfComplement.cpp * Author: S Harry White * Created: 2011-08-02 * Updated: 2013-01-18 */ /* * Makes non-associative self-complementary even order magic squares. * Double borders are repeatedly added to a center 4x4 or 6x6. */ #include "stdafx.h" #include #include #include #include #include #include #include int **xSquare = NULL, **bSquare = NULL, *tSideO = NULL, *tSideI = NULL, *bSideO = NULL, *bSideI = NULL, *rSideO = NULL, *rSideI = NULL; const int startSize = 25; int allocatedSize, biggestValue; //--------------------------------------------------------------------------- void freeSquare(int*** square, int size) { // ---------- if (*square != NULL) { for (int i = 0; i < size; i++) free((*square)[i]); free(*square); *square = NULL; } } // freeSquare void freeSquares() { // ----------- freeSquare(&xSquare, allocatedSize); freeSquare(&bSquare, allocatedSize); free(tSideO); free(tSideI); free(bSideO); free(bSideI); free(rSideO); free(rSideI); tSideO = NULL; tSideI = NULL; bSideO = NULL; bSideI = NULL; rSideO = NULL; rSideI = NULL; allocatedSize = 0; } // freeSquares bool allocateSquare(int*** square, int size) { // -------------- bool ok; *square = (int**) malloc(size * sizeof(int*)); ok = (*square != NULL); if (ok) { int numAllocated = size; for(int i = 0; i < size; i++) { int *p = (int*) malloc(size * sizeof(int)); (*square)[i] = p; if (p == NULL) { numAllocated = i; ok = false; break; } } if (!ok) freeSquare(square, numAllocated); } return ok; } // allocateSquare bool allocateSquares(int size) { // --------------- bool ok = true; if (size < startSize) size = startSize; if (size > allocatedSize) { freeSquares(); if (ok = allocateSquare(&xSquare, size)) { if (ok = allocateSquare(&bSquare, size)) { allocatedSize = size; tSideO = (int*) malloc(size * sizeof(int)); tSideI = (int*) malloc(size * sizeof(int)); bSideO = (int*) malloc(size * sizeof(int)); bSideI = (int*) malloc(size * sizeof(int)); rSideO = (int*) malloc(size * sizeof(int)); rSideI = (int*) malloc(size * sizeof(int)); ok = (tSideO != NULL) && (tSideI != NULL) && (bSideO != NULL) && (bSideI != NULL) && (rSideO != NULL) && (rSideI != NULL); if (!ok) freeSquares(); } else { freeSquare(&xSquare, size); allocatedSize = 0; } } } return ok; } //allocateSquares //--------------------------------------------------------------------------- bool isCorrect(int **x, int n) { // --------- int nn = n*n, nnp1 = nn+1; if (biggestValue != (nn / 2)) return false; int chkSum = n % 2 ? n * (nnp1 / 2) : n / 2 * nnp1; int sumX, sumY, sumXY = 0, sumYX = 0; for (int i = 0; i < n; i++) { sumX = 0; sumY = 0; for (int j = 0; j < n; j++) { sumX += x[i][j]; sumY += x[j][i]; } if ((sumX != chkSum) || (sumY != chkSum)) { return false; } sumXY += x[i][n - i - 1]; sumYX += x[i][i]; } return ((sumXY == chkSum) && (sumYX == chkSum)); } // isCorrect //--------------------------------------------------------------------------- bool isSelfComplement(int **x, int n) { // ---------------- int m = n - 1, mid = n/2, sum2 = n*n + 1; for (int r = 0; r < n; ++r) for (int c = 0; c < mid; ++c) if ((x[r][c] + x[r][m-c]) != sum2) return false; return true; } // isSelfComplement //--------------------------------------------------------------------------- void seed_rand() { srand((unsigned int)time(NULL)); } int random(int x) { // ------ return (int)((double)rand() / (RAND_MAX + 1) * x); } // random //-------------------------------------------------------------------------- typedef void (*t_Turn)(int, int, int); void no_Turn (int n, int i, int j) { xSquare[i][j] = bSquare[i][j]; }; void rotate_180(int n, int i, int j) { xSquare[n-i][n-j] = bSquare[i][j]; }; void rotate_Y (int n, int i, int j) { xSquare[i][n-j] = bSquare[i][j]; }; void rotate_X (int n, int i, int j) { xSquare[n-i][j] = bSquare[i][j]; }; static t_Turn turnCell[] = { no_Turn, rotate_180, rotate_Y, rotate_X }; void Turn(int o, int n) { // ---- const int numRotations = 4; int r, c, nmo = n-o, npo = n+o, k = random(numRotations); if (nmo < 7) { // turn all 4, 5, 6, 7 for (r = o; r <= n; r++) for (c = o; c <= n; c++) turnCell[k](npo, r, c); } else { // turn only 2 border rows and columns int p = o+1, m = n-1; for (r = o; r <= n; r += nmo) for (c = o; c <= n; ++c) turnCell[k](npo, r, c); for (c = o; c <= n; c += nmo) for (r = p; r < n; ++r) turnCell[k](npo, r, c); for (r = p; r <= m; r += (nmo-2)) for (c = p; c <= m; ++c) turnCell[k](npo, r, c); for (c = p; c <= m; c += (nmo-2)) for (r = p; r < m; ++r) turnCell[k](npo, r, c); } } // Turn //--------------------------------------------------------------------------- void makeActual(int n) { // ---------- int pPlus = n * n / 2, mPlus = pPlus + 1; for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) xSquare[i][j] += xSquare[i][j] > 0 ? pPlus : mPlus; } // makeActual //-------------------------------------------------------------------------------------- const int num4x4ss = 304; int code4x4ss[] = { 0x01ebd2c9,0x01ecd2b9,0x02d9c3ea,0x02dbc3e8,0x02dec39a,0x02dec3b8,0x03c7d2eb,0x03c7e1db, 0x03cbd2e7,0x03cbe1d7,0x03cde17b,0x03cde1b7,0x03ced27b,0x03ced2b7,0x04b9a5ec,0x04bda5e8, 0x04bea59c,0x04bea5d8,0x05a6e1dc,0x05a7b4ed,0x05a7e1bd,0x05ab96cd,0x05abe17d,0x05abe1d7, 0x05ac96bd,0x05adb4e7,0x05ade16c,0x05ade1b7,0x05aeb47d,0x05aeb4d7,0x0697b4de,0x0697d2be, 0x069b87ec,0x069bd27e,0x069bd2e7,0x069d87ea,0x069db47e,0x069db4e7,0x069e87bc,0x069e87da, 0x069eb4d7,0x069ed2b7,0xba5d1e63,0xb5ad3c61,0xb78d1e63,0x078dc36e,0xc5ab2d71,0xc69b1e72, 0xa3cd4b71,0xa69d1e74,0x93ce4b72,0x95ae2d74,0x087de16c,0x096b78ed,0x096bc3e8,0x096be17d, 0x096d78eb,0x096da5e8,0x096de17b,0x096e78bd,0x096e78db,0x096ea5d8,0x096ec3b8,0x72de5a93, 0x74be3c95,0x0a5b78de,0x0a5bd27e,0x0a5bd2c9,0x0a5cd2b9,0x0a5d78be,0x0a5d78eb,0x0a5dc36e, 0x0a5e78db,0x0a5ed27b,0x0b4d87ea,0x0b4e87da,0x0b4ec39a,0x75ac2db6,0x6a5d1eb8,0x596e2db8, 0x569e3cb7,0x0c3d78be,0x0c3db47e,0x0c3e78bd,0x0c3eb47d,0x75ab2dc6,0x0d2e87bc,0x0d2ea59c, 0x10fac3d8,0x10fdc3a8,0x12d6c3fa,0x12d6f0ca,0x12d7f0ab,0x12dac3f6,0x12daf07b,0x12daf0c6, 0x12dcf06a,0x12dcf0a6,0x12dfc36a,0x12dfc3a6,0x14b6a5fc,0x14b6f0ac,0x14ba87dc,0x14baf06c, 0x14baf0c6,0x14bca5f6,0x14bcf0a6,0x14bd87ac,0x14bfa56c,0x14bfa5c6,0x1697b4af,0x169ab47f, 0xdb4a0f63,0xd4ba3c60,0xd78a0f63,0xbd2c0f65,0xb2dc5a60,0xb78c0f65,0x82df5a63,0x84bf3c65, 0x178ac36f,0x178ac3f6,0x178ca56f,0x178ca5f6,0x178fa5c6,0x178fc3a6,0xc2da4b70,0xc69a0f74, 0x187a69fc,0x187af06c,0x187c69fa,0x187cf06a,0x187f69ac,0x187f69ca,0x196af07b,0xd7860fa3, 0xc6970fa4,0x7d2c0fa9,0x7b4c0fa9,0x60fd78a3,0x64bd3ca7,0x487f3ca9,0x1b4c69af,0x1b4c69fa, 0x1b4dc3a8,0x1b4f69ca,0x1b4fc36a,0xb7860fc5,0x7b4a0fc9,0x1d2f69ac,0x1d2fa56c,0x64ba3cd7, 0x21e5c3f9,0x21e5f0c9,0x21e9c3f5,0x21e9f0c5,0x21ecf059,0x21ecf095,0x21efc359,0x21efc395, 0x23c5f0e7,0x23cef057,0x24b596fc,0x24b5f0e7,0x24b9f0c5,0x24bcf095,0x24bef057,0x24bf965c, 0xbe1c0f56,0xb1ec6950,0xb78c0f56,0x9c3e0f58,0x9b4e0f58,0x81ef6953,0x84bf3c56,0x2789c3f5, 0x278c965f,0x278fc395,0x28795afc,0x287cf059,0x287f5a9c,0x7e1c0f9a,0x7b4c0f9a,0x487f3c9a, 0x2b4c5a9f,0x2b4e785f,0x2b4fc359,0x2c3e785f,0xb7850fc6,0x7b490fca,0x2e1f5a9c,0x2e1f965c, 0x30f4d2e8,0x30f4e1d8,0x30f5b4e9,0x30f8d2e4,0x30f8e1d4,0x30fde148,0x30fde184,0x30feb459, 0x30fed248,0x30fed284,0x31e4f0d7,0x31e6f0d5,0x31edf047,0x31edf065,0x32d4e1f6,0x32d596eb, 0x32de965b,0x32dfe146,0x34b6f0d5,0x34bdf065,0xaf0d1e47,0xa1ed8740,0xae1d0f48,0xa0fd7841, 0xa96d0f48,0xa69d1e47,0x9f0e2d47,0x90fe7842,0x95ae2d47,0x82df9641,0x8d2f1e49,0x8a5f1e49, 0x35a8e1d4,0x35ade184,0x35ae874d,0x35afe146,0x80fe6954,0x82de4b56,0x3698d2e4,0x369d874e, 0x369df047,0x369ed284,0x8e1d0f6a,0x8b4d0f6a,0x6f0d1e8b,0x6a5d1e8b,0x5f0e2d8b,0x596e2d8b, 0x396d784f,0x396de148,0x396e4b8d,0x3a5d4b8e,0x3a5ed248,0x3a5f694e,0x3b4d5a6f,0x3d2eb459, 0x3d2f694e,0xa9640fd8,0xa6941ed7,0x8b460fda,0x6a581edb,0x95a42de7,0x82d54be6,0x59682deb, 0x41e2c3f8,0x41e3a5f9,0x41e9f0a3,0x41eaf093,0x41efa539,0x41efc328,0x42d396fa,0x42d9f0a3, 0x42daf093,0x42df963a,0x9e1f3c27,0x91ef7823,0x95af3c27,0x81ef6935,0x82df5a36,0x45af872c, 0x7e1a0f9c,0x7d2a0f9c,0x4a5fc328,0x7e190fac,0x7d290fac,0x4d2fa539,0x4e1f872c,0x4e1f963a, 0x50f2b4e8,0x50f8e1b2,0x50fbe182,0x50feb428,0x51e6f0b3,0x51ebf063,0x52d6f0b3,0x52dbf063, 0x9f0e4b27,0x90fe7824,0x93ce4b27,0x53c8e1b2,0x53cbe182,0x53ce872b,0x8e1b0f6c,0x8d2b0f6c, 0x6f0b1e8d,0x6c3b1e8d,0x8e160fbc,0x8d260fbc,0x6f081ebd,0x6c381ebd,0x5c3eb428,0x93c24be7 }; //-------------------------------------------------------------------------------------- typedef signed char Sbyte; const int num6x6a = 50; Sbyte code6x6a[][18] = { {2,6,-3,-15,-8,-18,13,-5,9,-11,-4,10,12,-7,-14,-1,17,16}, {10,1,2,-18,16,4,-7,9,-13,-8,-17,-5,11,6,-3,12,-14,15}, {10,1,2,-18,16,-3,-7,9,-13,-8,-17,-5,11,6,4,12,-14,15}, {3,2,-10,-15,-18,4,6,13,17,-14,7,1,9,-11,5,12,8,-16}, {15,4,-7,-14,-1,11,-13,-8,12,-2,16,3,-5,6,-10,18,-17,-9}, {15,4,-10,-14,-1,11,-13,-8,12,-2,16,3,-5,6,-9,18,-17,-7}, {5,4,18,9,1,-3,6,-16,-17,7,15,-8,-12,10,-2,-14,-13,11}, {-14,-4,17,-3,7,-5,1,-16,-2,18,10,-13,9,15,-6,-11,-12,8}, {-7,-2,9,6,8,5,16,14,-18,1,-17,11,-3,-15,-10,-13,12,4}, {-7,-2,5,6,8,4,16,14,-18,1,-17,11,-3,-15,9,-13,12,-10}, {-2,-11,-4,1,9,17,10,-7,-3,13,5,18,-16,-8,-14,-6,12,-15}, {-8,9,-15,17,1,-4,3,14,-5,-13,7,16,11,-18,2,-10,-12,6}, {-8,9,-4,17,1,6,3,14,-5,-13,7,16,11,-18,2,-10,-12,-15}, {-14,16,-3,17,2,-12,4,-7,-5,9,-13,-10,-1,8,18,-15,-6,11}, {-14,16,18,17,2,11,4,-7,-5,9,-13,-10,-1,8,-12,-15,-6,-3}, {-9,-11,7,-5,14,-16,8,18,3,-2,-1,12,-6,-17,-15,13,-4,10}, {-12,17,-2,10,8,3,-14,-16,-6,9,-13,-4,18,5,15,-11,-1,-7}, {-11,1,13,14,6,10,4,-9,-15,16,8,-17,-18,2,-3,-5,-7,12}, {13,-17,-4,-15,1,-8,-10,-9,18,-3,7,11,-2,5,-6,16,14,-12}, {-5,-17,-13,8,-12,-2,16,18,15,-14,3,10,6,-1,-4,-11,9,-7}, {-7,-1,2,-15,14,-16,6,-3,-9,4,-10,-8,17,11,13,-5,-12,18}, {5,-2,-7,-3,4,-18,-15,-8,11,9,-6,17,14,12,13,-10,-1,-16}, {5,8,18,-4,-14,-13,15,-9,-1,-2,-11,-17,-12,10,7,-3,16,6}, {3,18,-13,16,2,-1,-17,-14,8,-12,7,10,5,-4,11,6,-9,-15}, {14,-16,8,-13,-2,18,-7,12,-15,-3,-6,-5,17,11,-10,-9,1,4}, {-7,17,10,5,-6,-13,-4,15,11,16,-8,-3,-12,-1,-14,2,-18,9}, {-7,17,9,5,-6,10,-4,15,11,16,-8,-3,-12,-1,-14,2,-18,-13}, {-10,-15,16,-4,14,6,18,-13,2,1,12,5,3,9,-17,-8,-7,-11}, {-1,-8,18,-6,5,-14,12,9,-13,-2,4,-17,-15,-3,10,11,-7,16}, {-1,-8,-7,-6,5,9,12,16,-13,-2,4,-17,-15,-3,10,11,-14,18}, {15,-17,-13,8,3,-2,11,-5,-14,-12,10,7,-18,1,16,-4,9,6}, {1,8,5,-18,13,7,9,-10,-17,11,-2,-6,-16,-12,-4,14,3,15}, {-11,-18,-15,16,1,-8,-4,12,9,-14,-2,-13,6,5,17,7,3,10}, {-11,-4,17,16,1,14,8,-10,9,-18,3,-13,-2,5,-12,7,6,-15}, {-11,-4,-12,16,1,17,8,-10,9,-18,3,-13,-2,5,14,7,6,-15}, {12,-16,-5,-18,1,-4,-11,2,15,6,13,17,9,8,-10,3,-7,-14}, {9,-12,6,-15,-16,14,18,13,5,2,11,1,-4,7,-8,-10,-3,-17}, {4,-5,-10,-1,17,2,15,-9,6,-16,-8,-3,-13,18,12,11,-14,-7}, {4,-5,-7,-1,17,2,15,-9,6,-16,-8,-3,-13,18,-10,11,-14,12}, {15,-10,-11,3,4,8,17,-13,-9,-16,2,5,-18,6,14,-1,12,-7}, {-18,2,9,3,-14,-1,7,11,5,17,-8,-10,4,-6,13,-12,15,-16}, {-18,2,-1,3,-14,13,7,11,5,17,-8,-10,4,-6,9,-12,15,-16}, {-18,2,-16,3,-14,13,7,11,5,17,-8,-10,4,-6,-1,-12,15,9}, {11,8,-12,-18,-5,-16,-1,-17,14,4,10,6,3,13,-7,2,-9,15}, {-5,3,13,15,-2,-18,11,-9,7,-17,14,16,-1,-12,-8,-4,6,-10}, {7,5,-16,-15,-18,6,2,-10,17,-3,-4,-8,9,13,12,1,14,-11}, {-3,-11,-8,-4,6,16,-12,17,-7,-9,-1,-15,14,-2,-5,13,-10,18}, {-3,-11,-5,-4,6,16,-12,17,-7,-9,-1,-15,14,-2,18,13,-10,-8}, {-2,18,-16,17,-12,13,-10,-9,15,-7,-14,-8,-3,6,1,4,11,-5}, {-2,18,13,17,-12,-5,-10,-9,15,-7,-14,-8,-3,6,-16,4,11,1} }; //-------------------------------------------------------------------------------------- void putCenter4x4(int **x, int **b, int o, int n) { // ------------ int code = code4x4ss[random(num4x4ss)]; const int Msum = 34; // 4 * (4 * 4 + 1) / 2; x[2][2] = (code & 0xf) + 1; code >>= 4; x[2][0] = (code & 0xf) + 1; code >>= 4; x[1][2] = (code & 0xf) + 1; code >>= 4; x[1][1] = (code & 0xf) + 1; code >>= 4; x[1][0] = (code & 0xf) + 1; code >>= 4; x[0][2] = (code & 0xf) + 1; code >>= 4; x[0][1] = (code & 0xf) + 1; code >>= 4; x[0][0] = (code & 0xf) + 1; x[0][3] = Msum - x[0][0] - x[0][1] - x[0][2]; x[1][3] = Msum - x[1][0] - x[1][1] - x[1][2]; x[3][0] = Msum - x[0][0] - x[1][0] - x[2][0]; x[3][2] = Msum - x[0][2] - x[1][2] - x[2][2]; x[3][3] = Msum - x[0][0] - x[1][1] - x[2][2]; x[3][1] = Msum - x[3][0] - x[3][2] - x[3][3]; x[2][1] = Msum - x[0][1] - x[1][1] - x[3][1]; x[2][3] = Msum - x[2][0] - x[2][1] - x[2][2]; for (int i = 0; i < 4; i++) for (int j = 0; j < 4; j++) b[i+o][j+o] = x[i][j] - (x[i][j] > 8 ? 8 : 9); // (4 * 4 + 1) / 2; (8.5) Turn(o, n); } // putCenter4x4 //--------------------------------------------------------------------------- void putCenter6x6(int **b, int o, int n) { // ------------ const Sbyte *code = code6x6a[random(num6x6a)]; int i = 0, upb = o+n, mid = upb/2; for (int r = o; r <= n; ++r) for (int c = o; c <= mid; ++c) { int v = code[i++]; b[r][c] = v; b[r][upb-c] = -v; } Turn(o, n); } // putCenter6x6 //--------------------------------------------------------------------------- void putBorder(int **b, int o, int n) { // --------- int m = n-1, p = o+1, upb = o+n, mid = upb/2, i = 0, v, length = (n-o-1)/2; // remaining choices in tSideO, etc. while (true) { i = random(length); if (tSideO[i] < 0) { v = tSideO[i]; tSideO[i] = tSideO[0]; b[o][p] = v; b[o][m] = -v; v = bSideO[i]; bSideO[i] = bSideO[0]; b[n][p] = v; b[n][m] = -v; break; } } for (int j = 0; j < length; ++j) { tSideO[j] = tSideO[j+1]; bSideO[j] = bSideO[j+1]; } --length; for (int c = p+1; c <= mid; ++c) { i = random(length); v = tSideO[i]; b[o][c] = v; b[o][upb-c] = -v; v = bSideO[i]; b[n][c] = v; b[n][upb-c] = -v; v = tSideI[i]; b[p][c] = v; b[p][upb-c] = -v; v = bSideI[i]; b[m][c] = v; b[m][upb-c] = -v; for (int j = i; j < length; ++j) { tSideO[j] = tSideO[j+1]; bSideO[j] = bSideO[j+1]; tSideI[j] = tSideI[j+1]; bSideI[j] = bSideI[j+1]; } --length; } length = n-o-1; // remaining choices in rSideO for (int r = p; r < n; ++r) { i = random(length); v = rSideO[i]; b[r][o] = v; b[r][n] = -v; for (int j = i; j < length; ++j) { rSideO[j] = rSideO[j+1]; } --length; } length = n-o-3; // remaining choices in rSideI for (int r = p+1; r < m; ++r) { i = random(length); v = rSideI[i]; b[r][p] = v; b[r][m] = -v; for (int j = i; j < length; ++j) { rSideI[j] = rSideI[j+1]; } --length; } Turn(o, n); } // putBorder //--------------------------------------------------------------------- int fieldWidth(int n) { // ---------- if (n == 1) return 1; int i = n*n, width = 1; while ((i = i / 10) != 0) ++width; return width; } // fieldWidth //--------------------------------------------------------------------------- typedef bool (*t_fprintFW)(FILE *fp, int i); bool fprintFW1(FILE *fp, int i) { return fprintf(fp, "%1d", i) > 0; } bool fprintFW2(FILE *fp, int i) { return fprintf(fp, "%2d", i) > 0; } bool fprintFW3(FILE *fp, int i) { return fprintf(fp, "%3d", i) > 0; } bool fprintFW4(FILE *fp, int i) { return fprintf(fp, "%4d", i) > 0; } bool fprintFW5(FILE *fp, int i) { return fprintf(fp, "%5d", i) > 0; } bool fprintFW6(FILE *fp, int i) { return fprintf(fp, "%6d", i) > 0; } bool fprintFW7(FILE *fp, int i) { return fprintf(fp, "%7d", i) > 0; } bool fprintFW8(FILE *fp, int i) { return fprintf(fp, "%8d", i) > 0; } bool fprintFW9(FILE *fp, int i) { return fprintf(fp, "%9d", i) > 0; } bool fprintFWa(FILE *fp, int i) { return fprintf(fp, "%10d", i) > 0; } static t_fprintFW fprintFW[] = { NULL, fprintFW1, fprintFW2, fprintFW3, fprintFW4, fprintFW5, fprintFW6, fprintFW7, fprintFW8, fprintFW9, fprintFWa }; const int maxFieldWidth = 10; //--------------------------------------------------------------------------- bool printSquare(FILE *wfp, int n) { // ----------- int fw0 = fieldWidth(n), fw = fw0+1; if (fw > maxFieldWidth) return false; for (int i = 0; i < n; i++) { if (!fprintFW[fw0](wfp, xSquare[i][0])) return false; for (int j = 1; j < n; j++) if (!fprintFW[fw](wfp, xSquare[i][j])) return false; if (fputc('\n', wfp) == EOF) return false; } return fputc('\n', wfp) != EOF; } // printSquare //--------------------------------------------------------------------------- void makeEven4(int **x, int **b, int size, FILE *wfp) { // --------- int v = 9; // 8.5; (4 * 4 + 1) / 2; // fill center 4x4 int o = (size - 4) / 2, n = o + 3; putCenter4x4(x, b, o, n); for (int i = 8; i <= size; i += 4) { int ct = 0, cb = 0, rr = 0; o = (size - i) / 2; n = o + i - 1; int p = o+1, m = n-1; int k = (i - 8) / 4; int *tO = tSideO, *bO = bSideO, *rO = rSideO, *tI = tSideI, *bI = bSideI, *rI = rSideI; tO[ct++] = -v++; bO[cb++] = v++; rO[rr++] = v++; rO[rr++] = -v++; tO[ct++] = v++; bO[cb++] = -v++; rO[rr++] = v++; rO[rr++] = -v++; tO[ct++] = -v++; bO[cb++] = v++; b[o][o] = -v; b[o][n] = v++; // NW, NE out b[m][p] = -v; b[m][m] = v++; // SW, SE in b[p][p] = v; b[p][m] = -v++; // NW, NE in b[n][o] = v; b[n][n] = -v++; // SW, SE out rO[rr++] = v++; rO[rr++] = -v++; int j = k; while (j--) { tO[ct++] = -v++; bO[cb++] = v++; rO[rr++] = v++; rO[rr++] = -v++; tO[ct++] = v++; bO[cb++] = -v++; rO[rr++] = -v++; rO[rr++] = v++; } ct = 0, cb = 0, rr = 0; tI[ct++] = -v++; bI[cb++] = v++; rI[rr++] = v++; rI[rr++] = -v++; tI[ct++] = v++; bI[cb++] = -v++; rI[rr++] = v++; rI[rr++] = -v++; j = k; while (j--) { tI[ct++] = v++; bI[cb++] = -v++; rI[rr++] = -v++; rI[rr++] = v++; tI[ct++] = -v++; bI[cb++] = v++; rI[rr++] = v++; rI[rr++] = -v++; } putBorder(b, o, n); } // for (i = 8; ... biggestValue = v - 1; } // makeEven4 //--------------------------------------------------------------------------- void makeEven6(int **b, int size, FILE *wfp) { // --------- int v = 19; // 18.5; (6 * 6 + 1) / 2; // fill center 6x6 int o = (size - 6) / 2, n = o + 5; putCenter6x6(b, o, n); for (int i = 10; i <= size; i += 4) { int ct = 0, cb = 0, rr = 0; o = (size - i) / 2; n = o + i - 1; int p = o+1, m = n-1; int k = (i - 10) / 4; int *tO = tSideO, *bO = bSideO, *rO = rSideO, *tI = tSideI, *bI = bSideI, *rI = rSideI; tO[ct++] = -v++; bO[cb++] = v++; rO[rr++] = v++; rO[rr++] = -v++; tO[ct++] = v++; bO[cb++] = -v++; rO[rr++] = -v++; rO[rr++] = v++; tO[ct++] = -v++; bO[cb++] = v++; rO[rr++] = v++; rO[rr++] = -v++; tO[ct++] = v++; bO[cb++] = -v++; b[o][o] = -v; b[o][n] = v++; // NW, NE out b[p][p] = v; b[p][m] = -v++; // NW, NE in rO[rr++] = v++; b[m][p] = -v; b[m][m] = v++; // SW, SE in b[n][o] = v; b[n][n] = -v++; // SW, SE out rO[rr++] = -v++; int j = k; while (j--) { tO[ct++] = -v++; bO[cb++] = v++; rO[rr++] = v++; rO[rr++] = -v++; tO[ct++] = v++; bO[cb++] = -v++; rO[rr++] = -v++; rO[rr++] = v++; } ct = 0, cb = 0, rr = 0; tI[ct++] = -v++; bI[cb++] = v++; rI[rr++] = v++; rI[rr++] = -v++; tI[ct++] = v++; bI[cb++] = -v++; rI[rr++] = -v++; rI[rr++] = v++; tI[ct++] = -v++; bI[cb++] = v++; rI[rr++] = -v++; rI[rr++] = v++; j = k; while (j--) { tI[ct++] = v++; bI[cb++] = -v++; rI[rr++] = -v++; rI[rr++] = v++; tI[ct++] = -v++; bI[cb++] = v++; rI[rr++] = v++; rI[rr++] = -v++; } putBorder(b, o, n); } // for (i = 10; ... biggestValue = v - 1; } // makeEven6 //--------------------------------------------------------------------------- const char *notMagic = "\a\nERROR: Square is NOT magic! Please report by email\n"; const char *notSelfComplement = "\a\nERROR: Square is NOT self-complementary! Please report by email\n"; bool makeEven(int n, FILE *wfp) // -------- { if (n%4 == 0) makeEven4(xSquare, bSquare, n, wfp); else makeEven6(bSquare, n, wfp); makeActual(n); if (isCorrect(xSquare, n)) { if (!isSelfComplement(xSquare, n)) printf(notSelfComplement); } else printf(notMagic); return printSquare(wfp, n); } // makeEven //-------------------------------------------------------------------------- void get_rest_of_line(int c) { // ---------------- if (c != '\n') do { c = getchar(); } while (c != '\n'); } bool getYorOrder(int *n) { // if user inputs size instead of 'y' or 'n', use it // ----------- bool result = false; int c; *n = 0; do { c = getchar(); } while ((c == ' ') || (c == '\t') || (c == '\n') ); if ( (c == 'Y') || (c == 'y') ) result = true; else if ( (c != 'N') && (c != 'n') ) if ( ('1' <= c) && (c <= '9') ) { int i = c - '0'; while ( ('0' <= (c = getchar())) && (c <= '9') ) i = i*10 + c - '0'; *n = i; result = true; } get_rest_of_line(c); return result; } // getYorOrder int getSize() { // ------- int n = 0; int unused = scanf_s("%d", &n); int c = getchar(); get_rest_of_line(c); return n; } //-------------------------------------------------------------------------- const int bufSize = 128; bool openDir() { // ------- char buf[bufSize], msg[bufSize]; const char *baseName = "SelfComplementSquares"; strcpy_s(buf, bufSize, baseName); int sub = 0; do { if (_mkdir(buf) == -1) { if (errno != EEXIST) { sprintf_s(msg, bufSize, "Can't make folder %s", buf); perror(msg); return false; } sprintf_s(buf, bufSize, "%s_%d", baseName, ++sub); } else break; } while (true); if (_chdir(buf) == -1) { sprintf_s(msg, bufSize, "Can't open folder %s", buf); perror(msg); return false; } printf("Output files are in folder %s\n\n", buf); return true; } // openDir //-------------------------------------------------------------------------- FILE *open_File(int n) { // --------- char buf[bufSize]; sprintf_s(buf, bufSize, "Order%d.txt", n); FILE *wfp = NULL; if (fopen_s(&wfp, buf, "a") != 0) { char msg[bufSize]; sprintf_s(msg, bufSize, "\a\nCan't open for write %s", buf); perror(msg); } return wfp; } // open_File //-------------------------------------------------------------------------- bool validOrder(int n) { // ---------- if (n <= 0) { printf("\aERROR: N must be a positive integer.\n"); return false; } else if (n%2) { printf("\aERROR: There are no non-associative self-complementary " "magic squares of odd order.\n"); return false; } else if (n == 2) { printf("\aERROR: There is no magic square of order 2.\n"); return false; } else return true; }// validOrder //-------------------------------------------------------------------------- using namespace System; using namespace System::Threading; int main() { // ---- bool another = true, inputSize = true, noWriteError = true; if (openDir()) { seed_rand(); int n = 0; do { if (inputSize) { printf("\nInput the order of the square: "); n = getSize(); } if (validOrder(n)) { if (allocateSquares(n)) { FILE *wfp = NULL; if ( (wfp = open_File(n)) != NULL) { noWriteError = makeEven(n, wfp); fclose(wfp); } } else printf("\a\nERROR: Storage allocation failed.\n"); } // if (validOrder if (noWriteError) { printf("\nMake another square? " "input y (yes) or n (no) or the order of the square: "); if (getYorOrder(&n)) inputSize = (n==0); else another = false; } else { perror("\a\nError writing file"); another = false; } } while (another); } freeSquares(); printf("\nPress a key to close the console."); while (!Console::KeyAvailable) Thread::Sleep(250); return 0; } // main