Magic Squares
Print 100 magic squares.
A magic square is a square where each row, column, and diagonal must sum to the same value. In addition, each value in the matrix must be unique.
Additionally, each matrix must be distinct, and not be linear mapable to any other matrix. That means there must not exist a slope and offset so matrix1 * slope + offset == matrix2
.
Seperate each matrix by a double line break, and the values in each matrix by a space or tab. Separate rows with a single line break.
Matrix sizes must be between 3x3 and 6x6. You can mix and match if you want.
Judge
(async function*(context: Context): Challenge { function printMatrix<T>(matrix: T[][]): string { return matrix.map( row => row.map( cell => ''+cell ).join(" ") ).join("\n") } function isMagicSquare(matrix: number[][]): undefined | TestCase { const length = matrix.length; let sum: number | undefined; for(const i of range(length)) { let newSum = range(length).map( j=>matrix[i][j] ).reduce((a,b)=>a+b); if (sum === undefined) { sum = newSum; } if (!Number.isFinite(sum)) { return new TestCase( "Finite sum", "Fail", { "Text": `Sum must be finite:\n${printMatrix(matrix)}` } ) } if (Number.isNaN(sum)) { return new TestCase( "NaN sum", "Fail", { "Text": `Sum must not be NaN:\n${printMatrix(matrix)}` } ) } if (sum !== newSum) { return new TestCase( "Matrix Rows", "Fail", { "Text": `Matrix rows do not sum to the same value:\n`+ `${printMatrix(matrix)}\n\n`+ `Expected ${sum} Got ${newSum} ` } ) } } for(const i of range(length)) { let newSum = range(length).map( j=>matrix[j][i] ).reduce((a,b)=>a+b); if (sum !== newSum) { return new TestCase( "Matrix Columns", "Fail", { "Text": `Matrix columns do not sum to the same value:\n`+ `${printMatrix(matrix)}\n`+ `Expected ${sum} Got ${newSum} ` } ) } } for (const i of [0,1]) { let newSum = range(length).map( j=>matrix[j][i ? j : length - 1 - j] ).reduce((a,b)=>a+b); if (sum !== newSum) { return new TestCase( "Matrix Diagonal", "Fail", { "Text": `Matrix diagonals do not sum to the same value:\n`+ `${printMatrix(matrix)}\n`+ `Expected ${sum} Got ${newSum} ` } ) } } } // Single Test yield (await context.run(undefined)).assert( (e): TestCase => { const matrixes: string[][][] = e.trimEnd().split(/\n\n+/g).map( z => z.trimEnd().split("\n").map( e => e.split(/[ |\t]+/g) ) ); for (const matrix of matrixes) { if (matrix.length != matrix[0].length || !matrix.every(row=>row.every(cell=>!Number.isNaN(+cell)) )) { return new TestCase("Matrix Size", "Fail", {"Text": `Matrix is not square or does not contain numbers: \n${printMatrix(matrix)}\n\nLength=${matrix.length}\nRow=${matrix[0].length}`}); } if (matrix.length < 3 || matrix.length > 6) { return new TestCase("Matrix Size", "Fail", {"Text": `Matrix size must be between 3 and 6, got ${matrix.length}: \n${printMatrix(matrix)}`}); } } const mats: number[][][] = matrixes.map( i=>i.map(j=>j.map(k=>+k)) ); for (const matrix of mats) { let square; if (square = isMagicSquare(matrix)) { return square; } } for (const matrix of mats) { if (new Set(matrix.flatMap(i=>i)).size != matrix.length * matrix.length) { return new TestCase( "Matrix Unique Values", "Fail", { "Text": `Matrix must have all unique numbers\n${printMatrix(matrix)}` } ) } } for (const matrix1 of mats) { for (const matrix2 of mats) { if (matrix1 === matrix2) { continue; } if (matrix1.length != matrix2.length) { continue; } const slope = (matrix1[1][0] - matrix1[0][0]) / (matrix2[1][0] - matrix2[0][0]); const offset = matrix1[0][0] - matrix2[0][0] * slope; const matrix2mapped = matrix2.map( row => row.map( value => value * slope + offset ) ); if ( range(matrix1.length).every( i=>range(matrix1.length).every( j=>matrix1[i][j] == matrix2mapped[i][j] ) ) ) { return new TestCase( "Matrix must not be a linear mapping", "Fail", { "Text": `Two matrixes are integer ratios of eachother.\n${printMatrix(matrix1)}\n\n${printMatrix(matrix2)}\n\nSlope: ${slope}\nOffset:${offset}` } ) } } } if (matrixes.length != 100) { return new TestCase( "Matrix Count", "Fail", { "Text": `Expected 100 squares, got ${matrixes.length}` } ) } return new TestCase( "Ok", "Pass", { "Text": "All sqares are valid!" } ) } ) // Finally, the challenge is passed if no test cases failed return context.noFailures(); })
Example Code
console.log(`10 3 13 8 5 16 2 11 4 9 7 14 15 6 12 1 10 3 13 22 19 16 2 11 4 9 21 14 15 20 12 1 10 3 13 36 33 16 2 11 4 9 35 14 15 34 12 1 10 3 13 50 47 16 2 11 4 9 49 14 15 48 12 1 10 3 13 64 61 16 2 11 4 9 63 14 15 62 12 1 10 3 13 78 75 16 2 11 4 9 77 14 15 76 12 1 10 3 13 92 89 16 2 11 4 9 91 14 15 90 12 1 10 3 13 106 103 16 2 11 4 9 105 14 15 104 12 1 10 3 13 120 117 16 2 11 4 9 119 14 15 118 12 1 10 3 13 134 131 16 2 11 4 9 133 14 15 132 12 1 10 3 13 148 145 16 2 11 4 9 147 14 15 146 12 1 10 3 13 162 159 16 2 11 4 9 161 14 15 160 12 1 10 3 13 176 173 16 2 11 4 9 175 14 15 174 12 1 10 3 13 190 187 16 2 11 4 9 189 14 15 188 12 1 10 3 13 204 201 16 2 11 4 9 203 14 15 202 12 1 10 3 13 218 215 16 2 11 4 9 217 14 15 216 12 1 10 3 13 232 229 16 2 11 4 9 231 14 15 230 12 1 10 3 13 246 243 16 2 11 4 9 245 14 15 244 12 1 10 3 13 260 257 16 2 11 4 9 259 14 15 258 12 1 10 3 13 274 271 16 2 11 4 9 273 14 15 272 12 1 10 3 13 288 285 16 2 11 4 9 287 14 15 286 12 1 10 3 13 302 299 16 2 11 4 9 301 14 15 300 12 1 10 3 13 316 313 16 2 11 4 9 315 14 15 314 12 1 10 3 13 330 327 16 2 11 4 9 329 14 15 328 12 1 10 3 13 344 341 16 2 11 4 9 343 14 15 342 12 1 10 3 13 358 355 16 2 11 4 9 357 14 15 356 12 1 10 3 13 372 369 16 2 11 4 9 371 14 15 370 12 1 10 3 13 386 383 16 2 11 4 9 385 14 15 384 12 1 10 3 13 400 397 16 2 11 4 9 399 14 15 398 12 1 10 3 13 414 411 16 2 11 4 9 413 14 15 412 12 1 10 3 13 428 425 16 2 11 4 9 427 14 15 426 12 1 10 3 13 442 439 16 2 11 4 9 441 14 15 440 12 1 10 3 13 456 453 16 2 11 4 9 455 14 15 454 12 1 10 3 13 470 467 16 2 11 4 9 469 14 15 468 12 1 10 3 13 484 481 16 2 11 4 9 483 14 15 482 12 1 10 3 13 498 495 16 2 11 4 9 497 14 15 496 12 1 10 3 13 512 509 16 2 11 4 9 511 14 15 510 12 1 10 3 13 526 523 16 2 11 4 9 525 14 15 524 12 1 10 3 13 540 537 16 2 11 4 9 539 14 15 538 12 1 10 3 13 554 551 16 2 11 4 9 553 14 15 552 12 1 10 3 13 568 565 16 2 11 4 9 567 14 15 566 12 1 10 3 13 582 579 16 2 11 4 9 581 14 15 580 12 1 10 3 13 596 593 16 2 11 4 9 595 14 15 594 12 1 10 3 13 610 607 16 2 11 4 9 609 14 15 608 12 1 10 3 13 624 621 16 2 11 4 9 623 14 15 622 12 1 10 3 13 638 635 16 2 11 4 9 637 14 15 636 12 1 10 3 13 652 649 16 2 11 4 9 651 14 15 650 12 1 10 3 13 666 663 16 2 11 4 9 665 14 15 664 12 1 10 3 13 680 677 16 2 11 4 9 679 14 15 678 12 1 10 3 13 694 691 16 2 11 4 9 693 14 15 692 12 1 10 3 13 708 705 16 2 11 4 9 707 14 15 706 12 1 10 3 13 722 719 16 2 11 4 9 721 14 15 720 12 1 10 3 13 736 733 16 2 11 4 9 735 14 15 734 12 1 10 3 13 750 747 16 2 11 4 9 749 14 15 748 12 1 10 3 13 764 761 16 2 11 4 9 763 14 15 762 12 1 10 3 13 778 775 16 2 11 4 9 777 14 15 776 12 1 10 3 13 792 789 16 2 11 4 9 791 14 15 790 12 1 10 3 13 806 803 16 2 11 4 9 805 14 15 804 12 1 10 3 13 820 817 16 2 11 4 9 819 14 15 818 12 1 10 3 13 834 831 16 2 11 4 9 833 14 15 832 12 1 10 3 13 848 845 16 2 11 4 9 847 14 15 846 12 1 10 3 13 862 859 16 2 11 4 9 861 14 15 860 12 1 10 3 13 876 873 16 2 11 4 9 875 14 15 874 12 1 10 3 13 890 887 16 2 11 4 9 889 14 15 888 12 1 10 3 13 904 901 16 2 11 4 9 903 14 15 902 12 1 10 3 13 918 915 16 2 11 4 9 917 14 15 916 12 1 10 3 13 932 929 16 2 11 4 9 931 14 15 930 12 1 10 3 13 946 943 16 2 11 4 9 945 14 15 944 12 1 10 3 13 960 957 16 2 11 4 9 959 14 15 958 12 1 10 3 13 974 971 16 2 11 4 9 973 14 15 972 12 1 10 3 13 988 985 16 2 11 4 9 987 14 15 986 12 1 10 3 13 1002 999 16 2 11 4 9 1001 14 15 1000 12 1 10 3 13 1016 1013 16 2 11 4 9 1015 14 15 1014 12 1 10 3 13 1030 1027 16 2 11 4 9 1029 14 15 1028 12 1 10 3 13 1044 1041 16 2 11 4 9 1043 14 15 1042 12 1 10 3 13 1058 1055 16 2 11 4 9 1057 14 15 1056 12 1 10 3 13 1072 1069 16 2 11 4 9 1071 14 15 1070 12 1 10 3 13 1086 1083 16 2 11 4 9 1085 14 15 1084 12 1 10 3 13 1100 1097 16 2 11 4 9 1099 14 15 1098 12 1 10 3 13 1114 1111 16 2 11 4 9 1113 14 15 1112 12 1 10 3 13 1128 1125 16 2 11 4 9 1127 14 15 1126 12 1 10 3 13 1142 1139 16 2 11 4 9 1141 14 15 1140 12 1 10 3 13 1156 1153 16 2 11 4 9 1155 14 15 1154 12 1 10 3 13 1170 1167 16 2 11 4 9 1169 14 15 1168 12 1 10 3 13 1184 1181 16 2 11 4 9 1183 14 15 1182 12 1 10 3 13 1198 1195 16 2 11 4 9 1197 14 15 1196 12 1 10 3 13 1212 1209 16 2 11 4 9 1211 14 15 1210 12 1 10 3 13 1226 1223 16 2 11 4 9 1225 14 15 1224 12 1 10 3 13 1240 1237 16 2 11 4 9 1239 14 15 1238 12 1 10 3 13 1254 1251 16 2 11 4 9 1253 14 15 1252 12 1 10 3 13 1268 1265 16 2 11 4 9 1267 14 15 1266 12 1 10 3 13 1282 1279 16 2 11 4 9 1281 14 15 1280 12 1 10 3 13 1296 1293 16 2 11 4 9 1295 14 15 1294 12 1 10 3 13 1310 1307 16 2 11 4 9 1309 14 15 1308 12 1 10 3 13 1324 1321 16 2 11 4 9 1323 14 15 1322 12 1 10 3 13 1338 1335 16 2 11 4 9 1337 14 15 1336 12 1 10 3 13 1352 1349 16 2 11 4 9 1351 14 15 1350 12 1 10 3 13 1366 1363 16 2 11 4 9 1365 14 15 1364 12 1 10 3 13 1380 1377 16 2 11 4 9 1379 14 15 1378 12 1 4 3 8 9 5 1 2 7 6`)