Skip to content

Instantly share code, notes, and snippets.

@tawn33y
Last active February 25, 2023 11:13
Show Gist options
  • Save tawn33y/9da371b78813f49ae1940d293e23763a to your computer and use it in GitHub Desktop.
Save tawn33y/9da371b78813f49ae1940d293e23763a to your computer and use it in GitHub Desktop.
3x3 Magic Square

3x3 Magic Square

Given a 3x3 grid, i.e.

x11 x12 x13
x21 x22 x23
x31 x32 x33

Place the numbers 1-9 numbers in the grid, one number per box, such that:

  • All numbers lie between 1 and 9 (both inclusive), i.e. x11, x12, ..., x33 ∈ {1,2,3,4,5,6,7,8,9}
  • No number is used twice, i.e. x11 ≠ x12 ≠ ... ≠ x33
  • The sum of each row is 15, i.e. x11 + x12 + x13 = 15, ..., x31 + x32 + x33 = 15
  • The sum of each column is 15, i.e. x11 + x21 + x31 = 15, ..., x13 + x23 + x33 = 15

Example

3 7 5
4 2 9
8 6 1
// To run the code, uncomment the following:
// console.log(generateGrid());
// console.log(test(50));
// --------------------------------------------------------------------------------
// helper functions
// --------------------------------------------------------------------------------
export const sum = (...arr) => arr.reduce((acc, curr) => {
acc += curr;
return acc;
}, 0);
export const generateRandomNum = (start, end, whitelistArr = []) => {
const rand = Math.floor(Math.random() * end) + start;
const _whitelistArr = Array.isArray(whitelistArr) ? whitelistArr : [];
return _whitelistArr.includes(rand)
? generateRandomNum(start, end, whitelistArr)
: rand;
};
export const hasDuplicates = (arr) => {
let temp = {};
return arr.reduce((acc, x) => {
if (temp[x]) {
acc = true;
}
temp[x] = 'anything :)';
return acc;
}, false);
};
export const isInRange = (arr, start, end) => arr.reduce((acc, x) => {
if (acc && (x < start || x > end)) {
acc = false;
}
return acc;
}, true);
// --------------------------------------------------------------------------------
// grid functions
// --------------------------------------------------------------------------------
export const generateRow1 = () => {
const x11 = generateRandomNum(1, 9);
const x12 = generateRandomNum(1, 9, [x11]);
const x13 = 15 - (x11 + x12);
const row1 = [x11, x12, x13];
if (hasDuplicates(row1) || !isInRange(row1, 1, 9) || sum(x11, x12) >= 15) {
return generateRow1();
} else {
return row1;
}
};
export const generateRow2 = (row1) => {
const x21 = generateRandomNum(1, 9, row1);
const x22 = generateRandomNum(1, 9, [...row1, x21]);
const x23 = 15 - (x21 + x22);
const row2 = [x21, x22, x23];
const [x11, x12, x13] = row1;
if (
hasDuplicates(row2) ||
!isInRange(row2, 1, 9) ||
sum(x21, x22) >= 15 ||
sum(x11, x21) >= 15 ||
sum(x12, x22) >= 15 ||
(15 - sum(x11, x21) === x13) ||
(15 - sum(x12, x22) === x13)
) {
return generateRow2(row1);
} else {
return row2;
}
};
export const generateRow3 = (row1, row2) => {
const [x11, x12, x13] = row1;
const [x21, x22, x23] = row2;
const x31 = 15 - sum(x11, x21);
const x32 = 15 - sum(x12, x22);
const x33 = 15 - sum(x13, x23); // const x33 = 15 - sum(x31, x32);
const row3 = [x31, x32, x33];
if (
hasDuplicates(row3) ||
hasDuplicates([...row1, ...row2, ...row3]) ||
!isInRange(row3, 1, 9) ||
sum(x31, x32) >= 15 ||
sum(x11, x21, x31) > 15 ||
sum(x12, x22, x32) > 15 ||
sum(x13, x23, x33) > 15 ||
sum(x31, x32, x33) > 15
) {
return false;
} else {
return row3;
}
};
export const generateGrid = () => {
const row1 = generateRow1();
const row2 = generateRow2(row1);
const row3 = generateRow3(row1, row2);
if (!row3) {
return generateGrid();
}
return [ row1, row2, row3 ];
};
// --------------------------------------------------------------------------------
// test functions
// --------------------------------------------------------------------------------
export const test = (count) => {
let testHasFailed = false;
for (let i = 0; i < count; i++) {
const [row1, row2, row3] = generateGrid();
const rowSum = [
sum(...row1),
sum(...row2),
sum(...row3)
];
const columnSum = [
sum(row1[0], row2[0], row3[0]),
sum(row1[1], row2[1], row3[1]),
sum(row1[2], row2[2], row3[2]),
];
const gridHasDuplicates = hasDuplicates([...row1, ...row2, ...row3]);
const gridContainsValuesNotEqualTo15 = [...rowSum, ...columnSum].reduce((acc, x) => {
if (x !== 15) {
acc = true;
}
return acc;
}, false);
const _testHasFailed = testHasFailed = gridHasDuplicates && gridContainsValuesNotEqualTo15;
console.log(`
Test ${i+1}: [${_testHasFailed ? 'FAIL' : 'PASS'}]
No Duplicates: [${gridHasDuplicates ? 'FAIL' : 'PASS'}]
Sum Equal To 15: [${gridContainsValuesNotEqualTo15 ? 'FAIL' : 'PASS'}]
--
| ${row1[0]} | ${row1[1]} | ${row1[2]} |
| ${row2[0]} | ${row2[1]} | ${row2[2]} |
| ${row3[0]} | ${row3[1]} | ${row3[2]} |
`);
}
console.log(`
OVERALL
${count} Tests: [${testHasFailed ? 'FAIL' : 'PASS'}]
`);
};

Guiding Rules

The code should implement the following rules:

a) Row 1

  • x11, x12, x13 ∈ {1,2,3,4,5,6,7,8,9}
  • x11 ≠ x12 ≠ x13
  • x11 + x12 + x13 = 15
  • x11 + x12 < 15

b) Row 2

  • x21, x22, x23 ∈ {1,2,3,4,5,6,7,8,9}
  • x21 ≠ x22 ≠ x23
  • x21 + x22 + x23 = 15
  • x21 + x22 < 15
  • x11 + x21 < 15
  • x12 + x22 < 15
  • 15 - (x11 + x21) ≠ x13
  • 15 - (x12 + x22) ≠ x13

c) Row 3

  • x31, x32, x33 ∈ {1,2,3,4,5,6,7,8,9}
  • x31 ≠ x32 ≠ x33
  • x31 + x32 + x33 = 15
  • x11 + x21 + x23 = 15
  • x12 + x22 + x32 = 15
  • x13 + x23 + x33 = 15
  • x31 + x32 < 15
  • x31, x32, x33 ∉ {x11, x12, ..., x33}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment