about summary refs log tree commit diff stats
path: root/html/kgame/script.js
diff options
context:
space:
mode:
Diffstat (limited to 'html/kgame/script.js')
-rw-r--r--html/kgame/script.js437
1 files changed, 437 insertions, 0 deletions
diff --git a/html/kgame/script.js b/html/kgame/script.js
new file mode 100644
index 0000000..ed71eeb
--- /dev/null
+++ b/html/kgame/script.js
@@ -0,0 +1,437 @@
+document.addEventListener('DOMContentLoaded', () => {
+    const GRID_SIZE = 50;
+    const CELL_SIZE = 10; // Adjust for desired visual size
+    const CANVAS_WIDTH = GRID_SIZE * CELL_SIZE;
+    const CANVAS_HEIGHT = GRID_SIZE * CELL_SIZE;
+
+    const canvas = document.getElementById('gridCanvas');
+    const ctx = canvas.getContext('2d');
+    const input = document.getElementById('kInput');
+    const runButton = document.getElementById('runButton');
+    const output = document.getElementById('output');
+
+    canvas.width = CANVAS_WIDTH;
+    canvas.height = CANVAS_HEIGHT;
+
+    // --- Grid State ---
+    let G = Array(GRID_SIZE).fill().map(() => Array(GRID_SIZE).fill(0)); // 2D matrix grid state
+
+    // --- Drawing ---
+    function drawGridLines() {
+        ctx.strokeStyle = '#eee'; // Light gray grid lines
+        ctx.lineWidth = 1;
+
+        for (let i = 0; i <= GRID_SIZE; i++) {
+            // Vertical lines
+            ctx.beginPath();
+            ctx.moveTo(i * CELL_SIZE + 0.5, 0);
+            ctx.lineTo(i * CELL_SIZE + 0.5, CANVAS_HEIGHT);
+            ctx.stroke();
+
+            // Horizontal lines
+            ctx.beginPath();
+            ctx.moveTo(0, i * CELL_SIZE + 0.5);
+            ctx.lineTo(CANVAS_WIDTH, i * CELL_SIZE + 0.5);
+            ctx.stroke();
+        }
+    }
+
+    function drawCells() {
+        ctx.fillStyle = '#333'; // Color for 'on' cells
+        for (let row = 0; row < GRID_SIZE; row++) {
+            for (let col = 0; col < GRID_SIZE; col++) {
+                if (G[row][col] === 1) {
+                    ctx.fillRect(col * CELL_SIZE, row * CELL_SIZE, CELL_SIZE, CELL_SIZE);
+                }
+            }
+        }
+    }
+
+    function redraw() {
+        // Clear canvas
+        ctx.fillStyle = '#fff'; // Background color
+        ctx.fillRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
+
+        drawGridLines();
+        drawCells();
+    }
+
+    // Helper functions for array operations
+    const range = (n) => Array.from({length: n}, (_, i) => i);
+    const reshape = (arr, rows, cols) => {
+        const result = [];
+        for (let i = 0; i < rows; i++) {
+            result.push(arr.slice(i * cols, (i + 1) * cols));
+        }
+        return result;
+    };
+    const ravel = (arr) => arr.flat();
+    const zip = (a, b) => a.map((x, i) => [x, b[i]]);
+
+    // --- K-like Interpreter ---
+    function tokenize(code) {
+        // First, normalize whitespace
+        code = code.replace(/\s+/g, ' ').trim();
+        
+        // Define all operators and special characters
+        const operators = ['+', '-', '*', '/', '%', '(', ')', '!', '@', ':', '=', '<', '>', "'", '|', '$', '#', '~'];
+        
+        // Add spaces around all operators
+        operators.forEach(op => {
+            // Use a regex that ensures we don't double-space
+            const regex = new RegExp(`\\${op}`, 'g');
+            code = code.replace(regex, ` ${op} `);
+        });
+        
+        // Normalize spaces again
+        code = code.replace(/\s+/g, ' ').trim();
+        
+        // Split into tokens
+        const tokens = code.split(' ');
+        
+        // Filter out empty tokens and log for debugging
+        const filteredTokens = tokens.filter(t => t.length > 0);
+        console.log('Tokenized:', filteredTokens);
+        
+        return filteredTokens;
+    }
+
+    function evaluateExpression(tokens) {
+        if (!tokens || tokens.length === 0) throw new Error("Empty expression");
+
+        function parseAtom() {
+            let token = tokens.shift();
+            if (!token) throw new Error("Unexpected end of expression");
+
+            if (token === '(') {
+                const value = parseAddSub();
+                if (tokens.length === 0) {
+                    throw new Error("Missing closing parenthesis");
+                }
+                const nextToken = tokens.shift();
+                if (nextToken !== ')') {
+                    throw new Error(`Expected closing parenthesis, got: ${nextToken}`);
+                }
+                return value;
+            } else if (token === '!') { // Iota (prefix)
+                const operand = parseAtom();
+                if (typeof operand !== 'number' || !Number.isInteger(operand) || operand < 0) {
+                    throw new Error("Operand for ! (iota) must be a non-negative integer");
+                }
+                const maxIndex = GRID_SIZE * GRID_SIZE;
+                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 === '~') { // 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;
+                }
+            } else if (/^-?\d+$/.test(token)) {
+                return parseInt(token, 10);
+            } else {
+                throw new Error(`Unrecognized token: ${token}`);
+            }
+        }
+
+        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);
+
+            const scalarOp = (x, y) => {
+                let result;
+                switch (op) {
+                    case '+': result = x + y; break;
+                    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;
+                    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}`);
+                }
+                return result;
+            };
+
+            // Handle scalar operations
+            if (!isAList && !isBList) {
+                return scalarOp(a, b);
+            }
+
+            // Handle array operations
+            const arrayOp = (arr, val) => {
+                if (Array.isArray(arr)) {
+                    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) {
+                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) {
+                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}`);
+                }
+                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 = parseUnary();
+            while (tokens.length > 0 && (tokens[0] === '*' || tokens[0] === '%' || tokens[0] === '/')) {
+                const op = tokens.shift();
+                const right = parseUnary();
+                left = applyOperation(left, right, op);
+            }
+            return left;
+        }
+
+        function parseAddSub() {
+            let left = parseMulDivMod();
+            while (tokens.length > 0 && (tokens[0] === '+' || tokens[0] === '-')) {
+                const op = tokens.shift();
+                const right = parseMulDivMod();
+                left = applyOperation(left, right, op);
+            }
+            return left;
+        }
+
+        function parseComparison() {
+            let left = parseAddSub();
+            while (tokens.length > 0 && (tokens[0] === '<' || tokens[0] === '>' || tokens[0] === '=')) {
+                const op = tokens.shift();
+                const right = parseAddSub();
+                left = applyOperation(left, right, op);
+            }
+            return left;
+        }
+
+        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
+    function executeK(code) {
+        code = code.trim();
+        if (!code) return;
+
+        try {
+            if (code === 'G : 0') {
+                G = Array(GRID_SIZE).fill().map(() => Array(GRID_SIZE).fill(0));
+                setOutput("Grid cleared.", "success");
+                return;
+            }
+            if (code === 'G : 1') {
+                G = Array(GRID_SIZE).fill().map(() => Array(GRID_SIZE).fill(1));
+                setOutput("Grid filled.", "success");
+                return;
+            }
+
+            const assignMatch = code.match(/^G\s*@\s*(.+?)\s*:\s*(.+)$/);
+            if (assignMatch) {
+                const indexExpr = assignMatch[1].trim();
+                const valueExpr = assignMatch[2].trim();
+                const steps = [];
+
+                // Parse and evaluate indices
+                steps.push(`1. Evaluating indices expression: ${indexExpr}`);
+                const indices = evaluateExpression(tokenize(indexExpr));
+                steps.push(`   → Generated ${indices.length} indices`);
+
+                // Parse and evaluate values
+                steps.push(`2. Evaluating values expression: ${valueExpr}`);
+                const values = evaluateExpression(tokenize(valueExpr));
+                steps.push(`   → Generated ${Array.isArray(values) ? values.length : 1} values`);
+
+                const indicesArray = Array.isArray(indices) ? indices : [indices];
+                const valuesArray = Array.isArray(values) ? values : [values];
+
+                if (indicesArray.length === 0) {
+                    setOutput("Warning: Assignment applied to empty index list.", "info", steps);
+                    return;
+                }
+
+                // Vectorized assignment
+                const assignments = indicesArray.reduce((count, idx, i) => {
+                    const row = Math.floor(idx / GRID_SIZE);
+                    const col = idx % GRID_SIZE;
+                    
+                    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;
+                    }
+                    return count;
+                }, 0);
+
+                steps.push(`3. Assignment complete:`);
+                steps.push(`   → Applied ${assignments} assignments to the grid`);
+                steps.push(`   → Each value was taken modulo 2 to ensure binary (0/1) values`);
+
+                setOutput(`OK. Performed ${assignments} assignments.`, "success", steps);
+            } else {
+                const result = evaluateExpression(tokenize(code));
+                setOutput(`Evaluated: ${JSON.stringify(result)}`, "info", [
+                    `1. Evaluated expression: ${code}`,
+                    `2. Result: ${JSON.stringify(result)}`
+                ]);
+            }
+        } catch (error) {
+            setOutput(`Error: ${error.message}`, "error", [
+                `1. Error occurred while executing: ${code}`,
+                `2. Error details: ${error.message}`
+            ]);
+            console.error("K execution error:", error);
+        }
+    }
+
+    // --- Output Helper ---
+    function setOutput(message, type = "info", steps = []) {
+        const outputDiv = document.getElementById('output');
+        
+        // Create a container for the message and steps
+        const container = document.createElement('div');
+        container.className = type;
+        
+        // Add the main message
+        const messageDiv = document.createElement('div');
+        messageDiv.textContent = message;
+        container.appendChild(messageDiv);
+        
+        // Add steps if provided
+        if (steps.length > 0) {
+            const stepsDiv = document.createElement('div');
+            stepsDiv.className = 'steps';
+            steps.forEach(step => {
+                const stepDiv = document.createElement('div');
+                stepDiv.className = 'step';
+                stepDiv.textContent = step;
+                stepsDiv.appendChild(stepDiv);
+            });
+            container.appendChild(stepsDiv);
+        }
+        
+        // Clear previous output and add new content
+        outputDiv.innerHTML = '';
+        outputDiv.appendChild(container);
+    }
+
+    // --- Event Listeners ---
+    function handleRun() {
+         const code = input.value;
+         executeK(code);
+         redraw();
+         // Optional: Clear input after running
+         // input.value = '';
+     }
+
+    input.addEventListener('keydown', (event) => {
+        if (event.key === 'Enter') {
+            handleRun();
+        }
+    });
+
+    runButton.addEventListener('click', handleRun);
+
+
+    // --- Initial Draw ---
+    setOutput("Grid initialized. Enter commands below.", "info");
+    redraw();
+});
\ No newline at end of file
:40:15 -0700 2220' href='/akkartik/mu/commit/031address.cc?h=main&id=a0d7a15594990974808cc613a4814d1f86471b5e'>a0d7a155 ^
5ba1c3b9 ^


a0fc38c9 ^


795f5244 ^
15c44292 ^
a0fc38c9 ^

ff9d5f43 ^
455fbac6 ^
a0fc38c9 ^




ff9d5f43 ^
4fb72d75 ^
15c44292 ^
ff9d5f43 ^

65c905fe ^

4fb72d75 ^

c6034af3 ^





a0fc38c9 ^
ae256ea1 ^
a0fc38c9 ^







7284d503 ^
88be3dbc ^
5e938dc1 ^
bc643692 ^


286ca5a4 ^
5e938dc1 ^
57699011 ^
5e938dc1 ^
8389d168 ^




7136ddd5 ^
8389d168 ^



286ca5a4 ^
b9011f34 ^
bc643692 ^


286ca5a4 ^
b9011f34 ^
57699011 ^
b9011f34 ^
900e6a0e ^

af7a5722 ^

900e6a0e ^
c6034af3 ^
5e938dc1 ^
88be3dbc ^
db5c9550 ^
5e938dc1 ^
bc643692 ^


fb5470bc ^
5e938dc1 ^
d7494165 ^
5e938dc1 ^
900e6a0e ^

29057ed9 ^

900e6a0e ^
c6034af3 ^
c51043ab ^
7002b921 ^



7136ddd5 ^
7002b921 ^


c4e143d6 ^
7002b921 ^





ae256ea1 ^
7002b921 ^

5f98a10c ^
7002b921 ^

d619db37 ^




795f5244 ^
d619db37 ^

c6034af3 ^

795f5244 ^
d619db37 ^

1fad5eef ^

d619db37 ^
1fad5eef ^




795f5244 ^
1fad5eef ^


795f5244 ^
1fad5eef ^


c6034af3 ^


c51043ab ^
1fad5eef ^
c51043ab ^
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237