diff --git a/html/kgame/index.html b/html/kgame/index.html
index 453f40e..233c1d6 100644
--- a/html/kgame/index.html
+++ b/html/kgame/index.html
@@ -34,9 +34,17 @@
<li><code>G @ (50 * !50 + (49 - !50)) : 1</code> (Diagonal line from top-right - demonstrates - operator)</li>
<li><code>G @ (!2500) : ((!2500) / 50 + (!2500) % 50) % 2</code> (Checkerboard pattern - demonstrates / and % operators)</li>
- <li><strong>Special Operations:</strong></li>
- <li><code>G @ (where G=1) : 0</code> (Turn off currently 'on' cells - demonstrates where clause)</li>
- <li><code>G @ (!2500) : ((!2500) / 50 - 25) * ((!2500) / 50 - 25) + ((!2500) % 50 - 25) * ((!2500) % 50 - 25) < 625</code> (Circular pattern - demonstrates complex math)</li>
+ <li><strong>Unary Operators:</strong></li>
+ <li><code>G @ (!25) : ~(!25)</code> (First cell 1, rest 0 - demonstrates ~ not operator)</li>
+ <li><code>G @ (!25) : |(!25)</code> (Reverse sequence - demonstrates | reverse operator)</li>
+ <li><code>G @ (!25) : $(!25)</code> (Rotate sequence - demonstrates $ rotate operator)</li>
+ <li><code>G @ (!25) : #(!25)</code> (Reshape sequence - demonstrates # reshape operator)</li>
+
+ <li><strong>Operator Composition:</strong></li>
+ <li><code>G @ (!25) : ~((!25) / 5 + (!25) % 5) % 2</code> (Inverted checkerboard - demonstrates ~ with math)</li>
+ <li><code>G @ (!25) : |((!25) / 5 + (!25) % 5) % 2</code> (Flipped checkerboard - demonstrates | with math)</li>
+ <li><code>G @ (!25) : $((!25) / 5 + (!25) % 5) % 2</code> (Rotated checkerboard - demonstrates $ with math)</li>
+ <li><code>G @ (!25) : #((!25) % 2)</code> (Alternating columns reshaped - demonstrates # with math)</li>
</ul>
<canvas id="gridCanvas"></canvas>
diff --git a/html/kgame/script.js b/html/kgame/script.js
index a11d5f5..ed71eeb 100644
--- a/html/kgame/script.js
+++ b/html/kgame/script.js
@@ -74,7 +74,7 @@ document.addEventListener('DOMContentLoaded', () => {
code = code.replace(/\s+/g, ' ').trim();
// Define all operators and special characters
- const operators = ['+', '-', '*', '/', '%', '(', ')', '!', '@', ':', '=', '<', '>', "'"];
+ const operators = ['+', '-', '*', '/', '%', '(', ')', '!', '@', ':', '=', '<', '>', "'", '|', '$', '#', '~'];
// Add spaces around all operators
operators.forEach(op => {
@@ -102,10 +102,9 @@ document.addEventListener('DOMContentLoaded', () => {
function parseAtom() {
let token = tokens.shift();
if (!token) throw new Error("Unexpected end of expression");
- console.log('Parsing atom:', token, 'Remaining tokens:', tokens);
if (token === '(') {
- const value = parseAddSub(); // Start parsing inside parenthesis
+ const value = parseAddSub();
if (tokens.length === 0) {
throw new Error("Missing closing parenthesis");
}
@@ -119,49 +118,26 @@ document.addEventListener('DOMContentLoaded', () => {
if (typeof operand !== 'number' || !Number.isInteger(operand) || operand < 0) {
throw new Error("Operand for ! (iota) must be a non-negative integer");
}
- // Only generate indices that fit within our grid
const maxIndex = GRID_SIZE * GRID_SIZE;
- return Array.from({length: Math.min(operand, maxIndex)}, (_, i) => i);
- } else if (token === "'") { // Each adverb
- const operand = parseAtom();
- if (!Array.isArray(operand)) {
- throw new Error("Each adverb (') requires an array operand");
- }
- return operand.map(x => Array.isArray(x) ? x.map(y => y) : x);
- } else if (token === '/') { // Over adverb
- const operand = parseAtom();
- if (!Array.isArray(operand)) {
- throw new Error("Over adverb (/) requires an array operand");
- }
- return operand.reduce((a, b) => {
- if (Array.isArray(a) && Array.isArray(b)) {
- return a.map((x, i) => x + b[i]);
- }
- return a + b;
- });
- } else if (token === 'G') {
- // Return the grid as a flat array of [row,col] pairs
- const result = [];
- for (let row = 0; row < GRID_SIZE; row++) {
- for (let col = 0; col < GRID_SIZE; col++) {
- result.push([row, col]);
- }
- }
+ const result = Array.from({length: Math.min(operand, maxIndex)}, (_, i) => i);
+ console.log(`Iota generated array of length ${result.length}, first few values:`, result.slice(0, 5));
return result;
- } else if (token === 'where') {
- if (tokens.shift() !== 'G') throw new Error("Expected 'G' after 'where'");
- if (tokens.shift() !== '=') throw new Error("Expected '=' after 'where G'");
- if (tokens.shift() !== '1') throw new Error("Expected '1' after 'where G='");
- // Find all coordinates where G[row][col] === 1
- const indices = [];
- for(let row = 0; row < GRID_SIZE; row++) {
- for(let col = 0; col < GRID_SIZE; col++) {
- if (G[row][col] === 1) {
- indices.push(row * GRID_SIZE + col); // Convert to 1D index
- }
- }
+ } else if (token === '~') { // Not operator
+ const operand = parseAtom();
+ if (Array.isArray(operand)) {
+ const result = operand.map(x => {
+ const val = x === 0 ? 1 : 0;
+ console.log(`Not operation: ${x} -> ${val}`);
+ return val;
+ });
+ console.log(`Not operation on array, first few results:`, result.slice(0, 5));
+ console.log(`Input array first few values:`, operand.slice(0, 5));
+ return result;
+ } else {
+ const result = operand === 0 ? 1 : 0;
+ console.log(`Not operation (scalar): ${operand} -> ${result}`);
+ return result;
}
- return indices;
} else if (/^-?\d+$/.test(token)) {
return parseInt(token, 10);
} else {
@@ -169,6 +145,47 @@ document.addEventListener('DOMContentLoaded', () => {
}
}
+ function parseUnary() {
+ let token = tokens[0];
+ if (token === '|' || token === '$' || token === '#') {
+ tokens.shift();
+ const operand = parseUnary();
+ let result;
+ switch (token) {
+ case '|':
+ result = [...operand].reverse();
+ break;
+ case '$':
+ if (!Array.isArray(operand)) {
+ throw new Error("Rotate operator ($) requires an array operand");
+ }
+ const size = Math.sqrt(operand.length);
+ if (size * size !== operand.length) {
+ throw new Error("Rotate operator ($) requires a square array");
+ }
+ result = [];
+ for (let col = 0; col < size; col++) {
+ for (let row = size - 1; row >= 0; row--) {
+ result.push(operand[row * size + col]);
+ }
+ }
+ break;
+ case '#':
+ if (!Array.isArray(operand)) {
+ throw new Error("Reshape operator (#) requires an array operand");
+ }
+ result = [];
+ for (let i = 0; i < GRID_SIZE; i++) {
+ result.push(operand.slice(i * GRID_SIZE, (i + 1) * GRID_SIZE));
+ }
+ result = result.flat();
+ break;
+ }
+ return result;
+ }
+ return parseAtom();
+ }
+
function applyOperation(a, b, op) {
const isAList = Array.isArray(a);
const isBList = Array.isArray(b);
@@ -180,13 +197,12 @@ document.addEventListener('DOMContentLoaded', () => {
case '-': result = x - y; break;
case '*': result = x * y; break;
case '%': result = y === 0 ? 0 : x % y; break;
- case '/': result = y === 0 ? 0 : Math.floor(x / y); break; // Use integer division
+ case '/': result = y === 0 ? 0 : Math.floor(x / y); break;
case '<': result = x < y ? 1 : 0; break;
case '>': result = x > y ? 1 : 0; break;
case '=': result = x === y ? 1 : 0; break;
default: throw new Error(`Unknown operator: ${op}`);
}
- console.log(`Operation ${op}: ${x} ${op} ${y} = ${result}`);
return result;
};
@@ -198,29 +214,59 @@ document.addEventListener('DOMContentLoaded', () => {
// Handle array operations
const arrayOp = (arr, val) => {
if (Array.isArray(arr)) {
- return arr.map(x => arrayOp(x, val));
+ const result = arr.map(x => arrayOp(x, val));
+ if (op === '/' || op === '%') {
+ console.log(`Array operation ${op} with ${val}, first few results:`, result.slice(0, 5));
+ }
+ return result;
}
return scalarOp(arr, val);
};
if (isAList && !isBList) {
- return arrayOp(a, b);
+ const result = arrayOp(a, b);
+ if (op === '+') {
+ console.log(`Array + scalar operation, first few values:`, {
+ array: a.slice(0, 5),
+ scalar: b,
+ result: result.slice(0, 5)
+ });
+ }
+ return result;
} else if (!isAList && isBList) {
- return arrayOp(b, a);
+ const result = arrayOp(b, a);
+ if (op === '+') {
+ console.log(`Scalar + array operation, first few values:`, {
+ scalar: a,
+ array: b.slice(0, 5),
+ result: result.slice(0, 5)
+ });
+ }
+ return result;
} else {
// Both are arrays
if (a.length !== b.length) {
throw new Error(`List length mismatch for operator ${op}: ${a.length} vs ${b.length}`);
}
- return a.map((x, i) => arrayOp(x, b[i]));
+ const result = a.map((x, i) => {
+ const val = arrayOp(x, b[i]);
+ if (op === '+') {
+ console.log(`Adding values at index ${i}: ${x} + ${b[i]} = ${val}`);
+ }
+ return val;
+ });
+ if (op === '+') {
+ console.log(`Array addition, first few results:`, result.slice(0, 5));
+ }
+ return result;
}
}
function parseMulDivMod() {
- let left = parseAtom();
+ let left = parseUnary();
while (tokens.length > 0 && (tokens[0] === '*' || tokens[0] === '%' || tokens[0] === '/')) {
const op = tokens.shift();
- const right = parseAtom();
+ const right = parseUnary();
left = applyOperation(left, right, op);
}
return left;
@@ -246,7 +292,16 @@ document.addEventListener('DOMContentLoaded', () => {
return left;
}
- return parseComparison();
+ function parseNot() {
+ let left = parseComparison();
+ while (tokens.length > 0 && tokens[0] === '~') {
+ tokens.shift();
+ left = Array.isArray(left) ? left.map(x => x === 0 ? 1 : 0) : (left === 0 ? 1 : 0);
+ }
+ return left;
+ }
+
+ return parseNot();
}
// Main execution function
@@ -297,6 +352,9 @@ document.addEventListener('DOMContentLoaded', () => {
if (row >= 0 && row < GRID_SIZE && col >= 0 && col < GRID_SIZE) {
const valueToAssign = valuesArray[i % valuesArray.length];
+ if (count < 5) { // Only log first few assignments
+ console.log(`Assignment [${row},${col}]: ${valueToAssign} (from index ${idx})`);
+ }
G[row][col] = valueToAssign % 2;
return count + 1;
}
|