Atom Square
About
A magic square is a grid of numbers arranged such that the sum of the numbers in each row, column, and diagonal is the same.
As a magician, you can use a magic square for mentalism or as a mathematical magic trick. Ask a spectator to choose any number between 22 and 117, and then reveal the sum of the numbers in any row, column, or diagonal that contains that number.
This mini-app helps you create a magic square based on a chosen number. Simply enter the number provided by the spectator, and copy the resulting numbers displayed on the PeekSmith 3 screen.
// the number
let num = '';
// the array will contain the numbers of the 4x4 square
let square = newUint8Array(16);
function main() {
ps.connect();
}
function formatNumber(n) {
if (n < 10) return `\xA0${n}`;
return `${n}`;
}
function buildSquare(n) {
// we can calculate a magic square for numbers
// between 22 and 117 when we would like to end with
// max. two digit positive numbers
if (n < 22 || n > 117) {
ps.print(`${n}\nINVALID`);
return;
}
let correction = (n - 22) / 6 | 0;
if (n > 25) correction += rand(2);
square[0] = 7 + correction;
square[1] = 12 + correction;
square[2] = 1 + correction;
square[3] = n - 20 - correction * 3;
square[4] = 2 + correction;
square[5] = n - 21 - correction * 3;
square[6] = 8 + correction;
square[7] = 11 + correction;
square[8] = n - 18 - correction * 3;
square[9] = 3 + correction;
square[10] = 10 + correction;
square[11] = 5 + correction;
square[12] = 9 + correction;
square[13] = 6 + correction;
square[14] = n - 19 - correction * 3;
square[15] = 4 + correction;
let vFlipped = rand(0, 2);
let rotated = rand(0, 2);
let startRow = vFlipped === 1 ? 3 : 0;
let endRow = vFlipped === 1 ? -1 : 4;
let step = vFlipped === 1 ? -1 : 1;
let result = '';
for (let row = startRow; row !== endRow; row += step) {
for (let col = 0; col < 4; col++) {
if (rotated === 0) {
result += formatNumber(square[row * 4 + col]);
} else { // col <==> row
result += formatNumber(square[col * 4 + row]);
}
result += col < 3 ? ' ' : '\n';
}
}
ps.print(result);
}
let layout = [
'1', '2', '3',
'4', '5', '6',
'7', '8', '9',
's', '0', '<'
];
function calc() {
if (num === '') return;
clearTimeout(timer);
buildSquare(parseInt(num));
num = '';
}
let timer;
function onButtonClick(buttonId) {
let key = layout[buttonId];
switch (key) {
case 's':
calc();
return;
case '<':
num = strSub(num, 0, -1);
break;
default:
if (strLen(num) < 3) num += key;
break;
}
clearTimeout(timer);
const processAfter = config.get('keyboard.submit.after');
if (processAfter > 0) timer = setTimeout(() => {
calc();
}, processAfter);
printNumberEntered();
}
function printNumberEntered() {
let rest = '';
for (let i = strLen(num); i < 3; i++) {
rest += '_';
}
let text = `${num}${rest}\n`;
ps.print(text);
}
function onEvent(e) {
if (e.source === 'ps:ble' && e.type === 'connected') {
ps.print('Atom\nSquare');
setTimeout(printNumberEntered, 2000);
return;
}
if (e.source === 'atom:button') {
const buttonId = parseInt(e.value);
if (e.type === 'click') {
onButtonClick(buttonId);
}
if (strSub(e.type, 0, 5) === 'click' && strLen(e.type) === 6) {
const clickCount = parseInt(strCharAt(e.type, 5));
for (let i = 0; i < clickCount; i++) {
onButtonClick(buttonId);
}
}
}
}