{"name":"sand.nu","source":"// sand.nu — Interaktiivinen Falling Sand -simulaatio\n\n& `libc` @ rand → i\n\n& `canvas` @ canvas_open i w i h → *i\n\n& `canvas` @ canvas_present → v\n\n& `canvas` @ canvas_sleep i ms → v\n\n& `canvas` @ canvas_should_close → i\n\n& `canvas` @ canvas_close → v\n\n// Hiirifunktiot (FFI C-kirjastosta tai WASM shimistä)\n& `canvas` @ canvas_mouse_x → i\n\n& `canvas` @ canvas_mouse_y → i\n\n& `canvas` @ canvas_mouse_btn → i\n\n: i W 320\n: i H 180\n: i FPS 60\n\n@ main → i {\n    : i total_px * W H\n\n    // Simulaatioverkko: 0 = tyhjä, 1 = hiekka\n    : *i grid # *i ( malloc * total_px 8 )\n\n    // Alustetaan verkko tyhjäksi\n    : ~ i i 0\n    ~ < i total_px {\n        = . grid i 0\n        = i + i 1\n    }\n\n    // Hiekan väri (Kullanvärinen keltainen, 0xFFEEDD88)\n    : i COL_SAND | 4278190080 | * 238 65536 | * 221 256 136\n    // Taustan väri (Musta, 0xFF000000)\n    : i COL_BG 4278190080\n\n    : *i fb ( canvas_open W H )\n    : i frame_ms / 1000 FPS\n\n    ~ == 0 ( canvas_should_close ) {\n\n        // 1. INPUT: Piirretään hiekkaa hiirellä\n        : i mx ( canvas_mouse_x )\n        : i my ( canvas_mouse_y )\n        : i mbtn ( canvas_mouse_btn )\n\n        ? == mbtn 1 {\n            // Tehdään pieni \"sivellin\" (5x5 neliö hiiren ympärille)\n            : ~ i dy - 0 2\n            ~ <= dy 2 {\n                : ~ i dx - 0 2\n                ~ <= dx 2 {\n                    : i px + mx dx\n                    : i py + my dy\n\n                    // Varmistetaan, että pysytään ruudulla\n                    ? & & & >= px 0 < px W >= py 0 < py H {\n                        // Lisätään hiekkaa satunnaisesti (spray-efekti)\n                        ? == % ( rand ) 3 0 {\n                            = . grid + * py W px 1\n                        } {}\n                    } {}\n                    = dx + dx 1\n                }\n                = dy + dy 1\n            }\n        } {}\n\n        // 2. FYSIIKKA: Päivitetään hiekanjyvät\n        // TÄRKEÄÄ: Hiekka pitää käydä läpi ALHAALTA YLÖS, jottei sama \n        // jyvä putoa koko ruudun mitalta yhden framen aikana!\n        : ~ i y - H 2\n        ~ >= y 0 {\n            : ~ i x 0\n            ~ < x W {\n                : i src_idx + * y W x\n\n                // Jos solussa on hiekkaa...\n                ? == . grid src_idx 1 {\n                    : i down_idx + * + y 1 W x\n\n                    // Vaihtoehto A: Suoraan alla on tyhjää\n                    ? == . grid down_idx 0 {\n                        = . grid down_idx 1\n                        = . grid src_idx 0\n                    } {\n                        // Vaihtoehto B: Alla on varattu, kokeillaan viistoon\n                        // Tarkistetaan, ollaanko reunalla ja onko tilaa\n                        : i can_l & > x 0 == . grid - down_idx 1 0\n                        : i can_r & < x - W 1 == . grid + down_idx 1 0\n\n                        ? & can_l can_r {\n                            // Molemmat vapaana: valitaan suunta satunnaisesti\n                            // ettei hiekka kasaudu luonnottomasti vain toiselle puolelle\n                            ? == % ( rand ) 2 0 {\n                                = . grid - down_idx 1 1\n                            } {\n                                = . grid + down_idx 1 1\n                            }\n                            = . grid src_idx 0\n                        } {\n                            // Vain toinen vapaana\n                            ? can_l {\n                                = . grid - down_idx 1 1\n                                = . grid src_idx 0\n                            } {\n                                ? can_r {\n                                    = . grid + down_idx 1 1\n                                    = . grid src_idx 0\n                                } {}\n                            }\n                        }\n                    }\n                } {}\n                = x + x 1\n            }\n            = y - y 1\n        }\n\n        // 3. PIIRTO: Siirretään grid framebufferiin\n        : ~ i idx 0\n        ~ < idx total_px {\n            = . fb idx ? == . grid idx 1 COL_SAND COL_BG\n            = idx + idx 1\n        }\n\n        ( canvas_present )\n        ( canvas_sleep frame_ms )\n    }\n\n    ( canvas_close )\n    ^ 0\n}\n","bytes":4247}