import { dropdown , type , DropDownOption } from "@thi.ng/hdom-components/dropdown" ; import { start } from "@thi.ng/hdom/start" ; import { bits } from "@thi.ng/transducers-binary/bits" ; import { comp } from "@thi.ng/transducers/comp" ; import { buildKernel2d , convolve2d } from "@thi.ng/transducers/convolve" ; import { map } from "@thi.ng/transducers/map" ; import { mapIndexed } from "@thi.ng/transducers/map-indexed" ; import { partition } from "@thi.ng/transducers/partition" ; import { push } from "@thi.ng/transducers/push" ; import { range2d } from "@thi.ng/transducers/range2d" ; import { repeatedly } from "@thi.ng/transducers/repeatedly" ; import { step } from "@thi.ng/transducers/step" ; import { str } from "@thi.ng/transducers/str" ; import { transduce } from "@thi.ng/transducers/transduce" ; const W = 128 ; const H = 48 ; const presets = [ [ "" , "custom" ] , [ "000100000001100000" , "conway" ] , [ "000100000001110000" , "maze #1" ] , [ "000111111000001111" , "maze #2" ] , [ "000001111111111110" , "dots" ] , [ "000101111000001111" , "growth" ] , [ "000001111000011111" , "organic" ] , [ "000010011000011111" , "angular" ] , ] ; let grid ; let rules ; const kernel = buildKernel2d ( [ 1 , 1 , 1 , 1 , 0 , 1 , 1 , 1 , 1 ] , 3 , 3 ) ; const setHash = ( ) => ( location . hash = rules . join ( "" ) ) ; const parseRules = step ( comp ( map ( ( x ) => parseInt ( x . replace ( "-" , "" ) , 2 ) ) , bits ( 18 ) ) ) ; const applyRules = ( raw ) => { if ( raw . length >= 18 ) { rules = < number [ ] > parseRules ( raw ) ; randomizeGrid ( ) ; setHash ( ) ; } } ; const randomSeq = ( num , prob = 0.5 ) => [ ... repeatedly ( ( ) => ( Math . random ( ) < prob ? 1 : 0 ) , num ) , ] ; const randomizeGrid = ( prob = 0.5 ) => ( grid = randomSeq ( W * H , prob ) ) ; const randomizeRules = ( ) => { rules = randomSeq ( 18 ) ; randomizeGrid ( ) ; setHash ( ) ; } ; export const convolve = ( src , rules , width , height , rstride = 9 , wrap = true ) => transduce < number [ ] , number , number [ ] > ( comp ( convolve2d ( { src , width , height , kernel , wrap } ) , mapIndexed ( ( i , x ) => rules [ x + src [ i ] * rstride ] ) ) , push ( ) , range2d ( width , height ) ) ; const format = ( src , width , fill = "\u2588" , empty = " " ) => transduce ( comp ( map ( ( x ) => ( x ? fill : empty ) ) , partition ( width ) , map ( ( x ) => x . join ( "" ) ) ) , str ( "\n" ) , src ) ; const setRule = ( i , j , s , rstride = 9 ) => { rules [ i * rstride + j ] = s ? 1 : 0 ; setHash ( ) ; } ; const checkbox = ( x , onchange ) => [ "input" , { type : "checkbox" , checked : ! ! x , onchange } , ] ; const ruleBoxes = ( prefix , i , rstride = 9 ) => [ "div" , [ "label" , prefix ] , ... rules . slice ( i * rstride , ( i + 1 ) * rstride ) . map ( ( rule , j ) => checkbox ( rule , ( e ) => setRule ( i , j , ( < HTMLInputElement > e . target ) . checked ) ) ) , ] ; const isPreset = ( id ) => presets . findIndex ( ( x ) => x [ 0 ] === id ) !== - 1 ; applyRules ( location . hash . length > 18 ? location . hash . substr ( 1 ) : < string > presets [ 1 ] [ 0 ] ) ; start ( ( ) => { const id = location . hash . substr ( 1 ) ; return [ "div" , ruleBoxes ( "birth" , 0 ) , ruleBoxes ( "survive" , 1 ) , [ "div" , [ "button" , { onclick : ( ) => randomizeRules ( ) } , "randomize rules" ] , [ "button" , { onclick : ( ) => randomizeGrid ( ) } , "reset grid" ] , [ dropdown , { onchange : ( e ) => applyRules ( ( < HTMLSelectElement > e . target ) . value ) , } , presets , isPreset ( id ) ? id : "" , ] , ] , [ "pre" , format ( ( grid = convolve ( grid , rules , W , H ) ) , W ) ] , ] ; } ) ;