# Mu - hest-life.mu

https://github.com/akkartik/mu/blob/main/hest-life.mu

       1 # Conway's Game of Life in a Hestified way
       2 #   https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life
       3 #   https://ivanish.ca/hest-podcast
       4 #
       5 # To build:
       6 #   $ ./translate hest-life.mu
       7 # I run it on my 2.5GHz Linux laptop like this:
       8 #   $ qemu-system-i386 -enable-kvm code.img
       9 #
      10 # If things seem too fast or too slow on your computer, adjust the loop bounds
      11 # in the function `linger` at the bottom. Its value will depend on how you
      12 # accelerate Qemu. Mu will eventually get a clock to obviate the need for this
      13 # tuning.
      14 #
      15 # Keyboard shortcuts:
      16 #   space: pause/resume
      17 #   0: restart time
      18 #   l: start looping from 0 to curren time
      19 #   L: stop looping
      20 #   +: zoom in
      21 #   -: zoom out
      22
      23 fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) {
      24   var env-storage: environment
      25   var env/esi: (addr environment) <- address env-storage
      26   initialize-environment env
      27   var second-buffer: screen
      28   var second-screen/edi: (addr screen) <- address second-buffer
      29   initialize-screen second-screen, 0x80, 0x30, 1/include-pixels
      30   render second-screen, env
      31   copy-pixels second-screen, screen
      32   {
      33     edit keyboard, env
      34     var play?/eax: (addr boolean) <- get env, play?
      35     compare *play?, 0/false
      36     {
      37       break-if-=
      38       step env
      39       render second-screen, env
      40       copy-pixels second-screen, screen
      41     }
      42     linger env
      43     loop
      44   }
      45 }
      46
      47 type environment {
      48   data: (handle array handle array cell)
      49   zoom: int  # 0 = 1024 px per cell; 5 = 4px per cell; each step adjusts by a factor of 4
      50   tick: int
      51   play?: boolean
      52   loop: int  # if non-zero, return tick to 0 after this point
      53 }
      54
      55 type cell {
      56   curr: boolean
      57   next: boolean
      58 }
      59
      60 fn render screen: (addr screen), _self: (addr environment) {
      61   var self/esi: (addr environment) <- copy _self
      62   var zoom/eax: (addr int) <- get self, zoom
      63   compare *zoom, 0
      64   {
      65     break-if-!=
      66     clear-screen screen
      67     render0 screen, self
      68   }
      69   compare *zoom, 1
      70   {
      71     break-if-!=
      72     clear-screen screen
      73     render1 screen, self
      74   }
      75   compare *zoom, 4
      76   {
      77     break-if-!=
      78     render4 screen, self
      79   }
      80   # clock
      81   var tick-a/eax: (addr int) <- get self, tick
      82   set-cursor-position screen, 0x78/x, 0/y
      83   draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen screen, *tick-a, 7/fg 0/bg
      84 }
      85
      86 # Lots of hardcoded constants for now.
      87 # TODO: split this up into a primitive to render a single cell and its
      88 # incoming edges (but not the neighboring nodes they emanate from)
      89 fn render0 screen: (addr screen), _self: (addr environment) {
      90   var self/esi: (addr environment) <- copy _self
      91   # cell border
      92   draw-vertical-line   screen,  0xc0/x, 0/ymin, 0x300/ymax, 0x16/color=dark-grey
      93   draw-vertical-line   screen, 0x340/x, 0/ymin, 0x300/ymax, 0x16/color=dark-grey
      94   draw-horizontal-line screen,  0x40/y, 0/xmin, 0x400/xmax, 0x16/color=dark-grey
      95   draw-horizontal-line screen, 0x2c0/y, 0/xmin, 0x400/xmax, 0x16/color=dark-grey
      96   # neighboring inputs, corners
      97   var color/eax: int <- state-color self, 0x7f/cur-topleftx, 0x5f/cur-toplefty
      98   draw-rect screen,  0x90/xmin   0x10/ymin,    0xb0/xmax   0x30/ymax,  color
      99   color <- state-color self, 0x81/cur-toprightx, 0x5f/cur-toprighty
     100   draw-rect screen, 0x350/xmin   0x10/ymin,   0x370/xmax   0x30/ymax,  color
     101   color <- state-color self, 0x7f/cur-botleftx, 0x61/cur-botlefty
     102   draw-rect screen,  0x90/xmin  0x2d0/ymin,    0xb0/xmax  0x2f0/ymax,  color
     103   color <- state-color self, 0x81/cur-botrightx, 0x61/cur-botrighty
     104   draw-rect screen, 0x350/xmin  0x2d0/ymin,   0x370/xmax  0x2f0/ymax,  color
     105   # neighboring inputs, edges
     106   color <- state-color self, 0x80/cur-topx, 0x5f/cur-topy
     107   draw-rect screen, 0x1f0/xmin   0x10/ymin,   0x210/xmax   0x30/ymax,  color
     108   color <- state-color self, 0x7f/cur-leftx, 0x60/cur-lefty
     109   draw-rect screen,  0x90/xmin  0x170/ymin,    0xb0/xmax  0x190/ymax,  color
     110   color <- state-color self, 0x80/cur-botx, 0x61/cur-boty
     111   draw-rect screen, 0x1f0/xmin  0x2d0/ymin,   0x210/xmax  0x2f0/ymax,  color
     112   color <- state-color self, 0x81/cur-rightx, 0x60/cur-righty
     113   draw-rect screen, 0x350/xmin  0x170/ymin,   0x370/xmax  0x190/ymax,  color
     114   # sum node
     115   draw-rect screen, 0x170/xsmin 0x140/ysmin,  0x190/xsmax 0x160/ysmax, 0x40/color
     116   set-cursor-position screen, 0x2d/scol, 0x13/srow
     117   draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, "+", 0xf/color, 0/bg
     118   # conveyors from neighboring inputs to sum node
     119   draw-monotonic-bezier screen,  0xa0/x0  0x20/y0,  0x100/x1 0x150/ys,  0x180/xs 0x150/ys,  4/color
     120   draw-monotonic-bezier screen,  0xa0/x0 0x180/y0,   0xc0/x1 0x150/ys,  0x180/xs 0x150/ys,  4/color
     121   draw-monotonic-bezier screen,  0xa0/x0 0x2e0/y0,  0x100/x1 0x150/ys,  0x180/xs 0x150/ys,  4/color
     122   draw-monotonic-bezier screen, 0x200/x0  0x20/y0,  0x180/x1  0x90/y1,  0x180/xs 0x150/ys,  4/color
     123   draw-monotonic-bezier screen, 0x200/x0 0x2e0/y0,  0x180/x1 0x200/y1,  0x180/xs 0x150/ys,  4/color
     124   draw-monotonic-bezier screen, 0x360/x0  0x20/y0,  0x180/x1  0xc0/y1,  0x180/xs 0x150/ys,  4/color
     125   draw-monotonic-bezier screen, 0x360/x0 0x180/y0,  0x35c/x1 0x150/ys,  0x180/xs 0x150/ys,  4/color
     126   draw-monotonic-bezier screen, 0x360/x0 0x2e0/y0,  0x180/x1 0x200/y1,  0x180/xs 0x150/ys,  4/color
     127   # filter node
     128   draw-rect screen, 0x200/xfmin 0x1c0/yfmin, 0x220/xfmax 0x1e0/yfmax, 0x31/color
     129   set-cursor-position screen, 0x40/fcol, 0x1b/frow
     130   draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, "?", 0xf/color, 0/bg
     131   # conveyor from sum node to filter node
     132   draw-line screen 0x180/xs, 0x150/ys, 0x210/xf, 0x1d0/yf, 0xa2/color
     133   # cell outputs at corners
     134   var color/eax: int <- state-color self, 0x80/curx, 0x60/cury
     135   draw-rect screen,  0xd0/xmin  0x50/ymin,  0xf0/xmax  0x70/ymax, color
     136   draw-rect screen, 0x310/xmin  0x50/ymin, 0x330/xmax  0x70/ymax, color
     137   draw-rect screen,  0xd0/xmin 0x290/ymin,  0xf0/xmax 0x2b0/ymax, color
     138   draw-rect screen, 0x310/xmin 0x290/ymin, 0x330/xmax 0x2b0/ymax, color
     139   # cell outputs at edges
     140   draw-rect screen, 0x1f0/xmin  0x50/ymin, 0x210/xmax  0x70/ymax, color
     141   draw-rect screen,  0xd0/xmin 0x170/ymin,  0xf0/xmax 0x190/ymax, color
     142   draw-rect screen, 0x1f0/xmin 0x290/ymin, 0x210/xmax 0x2b0/ymax, color
     143   draw-rect screen, 0x310/xmin 0x170/ymin, 0x330/xmax 0x190/ymax, color
     144   # conveyors from filter to outputs
     145   draw-monotonic-bezier screen, 0x210/xf 0x1d0/yf,  0x1c0/x1  0x60/y1,  0xe0/x2   0x60/y2,  0x2a/color
     146   draw-monotonic-bezier screen, 0x210/xf 0x1d0/yf,   0xe0/x1 0x1c0/y1,  0xe0/x2  0x180/y2,  0x2a/color
     147   draw-monotonic-bezier screen, 0x210/xf 0x1d0/yf,  0x1c0/x1 0x2a0/y1,  0xe0/x2  0x2a0/y2,  0x2a/color
     148   draw-monotonic-bezier screen, 0x210/xf 0x1d0/yf,  0x210/x1  0x60/y1, 0x200/x2   0x60/y2,  0x2a/color
     149   draw-monotonic-bezier screen, 0x210/xf 0x1d0/yf,  0x210/x1 0x230/y1, 0x200/x2  0x2a0/y2,  0x2a/color
     150   draw-monotonic-bezier screen, 0x210/xf 0x1d0/yf,  0x320/x1 0x120/y1, 0x320/x2   0x60/y2,  0x2a/color
     151   draw-monotonic-bezier screen, 0x210/xf 0x1d0/yf,  0x320/x1 0x1c0/y1  0x320/x2  0x180/y2,  0x2a/color
     152   draw-monotonic-bezier screen, 0x210/xf 0x1d0/yf,  0x320/x1 0x230/y1, 0x320/x2  0x2a0/y2,  0x2a/color
     153   # time-variant portion: 16 repeating steps
     154   var tick-a/eax: (addr int) <- get self, tick
     155   var progress/eax: int <- copy *tick-a
     156   progress <- and 0xf
     157   # 7 time steps for getting inputs to sum
     158   {
     159     compare progress, 7
     160     break-if->=
     161     var u/xmm7: float <- convert progress
     162     var six/eax: int <- copy 6
     163     var six-f/xmm0: float <- convert six
     164     u <- divide six-f
     165     # points on conveyors from neighboring cells
     166     draw-bezier-point screen, u,  0xa0/x0  0x20/y0, 0x100/x1 0x150/ys, 0x180/xs 0x150/ys, 7/color, 4/radius
     167     draw-bezier-point screen, u,  0xa0/x0 0x180/y0,  0xc0/x1 0x150/ys, 0x180/xs 0x150/ys, 7/color, 4/radius
     168     draw-bezier-point screen, u,  0xa0/x0 0x2e0/y0, 0x100/x1 0x150/ys, 0x180/xs 0x150/ys, 7/color, 4/radius
     169     draw-bezier-point screen, u, 0x200/x0  0x20/y0, 0x180/x1  0x90/y1, 0x180/xs 0x150/ys, 7/color, 4/radius
     170     draw-bezier-point screen, u, 0x200/x0 0x2e0/y0, 0x180/x1 0x200/y1, 0x180/xs 0x150/ys, 7/color, 4/radius
     171     draw-bezier-point screen, u, 0x360/x0  0x20/y0, 0x180/x1  0xc0/y1, 0x180/xs 0x150/ys, 7/color, 4/radius
     172     draw-bezier-point screen, u, 0x360/x0 0x180/y0, 0x35c/x1 0x150/ys, 0x180/xs 0x150/ys, 7/color, 4/radius
     173     draw-bezier-point screen, u, 0x360/x0 0x2e0/y0, 0x180/x1 0x200/y1, 0x180/xs 0x150/ys, 7/color, 4/radius
     174     return
     175   }
     176   # two time steps for getting count to filter
     177   progress <- subtract 7
     178   {
     179     compare progress, 2
     180     break-if->=
     181     progress <- increment  # (0, 1) => (1, 2)
     182     var u/xmm7: float <- convert progress
     183     var three/eax: int <- copy 3
     184     var three-f/xmm0: float <- convert three
     185     u <- divide three-f
     186     draw-linear-point screen, u, 0x180/xs, 0x150/ys, 0x210/xf, 0x1d0/yf, 7/color, 4/radius
     187     set-cursor-position screen, 0x3a/scol, 0x18/srow
     188     var n/eax: int <- num-live-neighbors self, 0x80/curx, 0x60/cury
     189     draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen screen, n, 0xf/fg 0/bg
     190     return
     191   }
     192   # final 7 time steps for updating output
     193   progress <- subtract 2
     194   # points on conveyors to outputs
     195   var u/xmm7: float <- convert progress
     196   var six/eax: int <- copy 6
     197   var six-f/xmm0: float <- convert six
     198   u <- divide six-f
     199   draw-bezier-point screen, u, 0x210/xf 0x1d0/yf,  0x1c0/x1  0x60/y1,  0xe0/x2   0x60/y2, 7/color, 4/radius
     200   draw-bezier-point screen, u, 0x210/xf 0x1d0/yf,   0xe0/x1 0x1c0/y1,  0xe0/x2  0x180/y2, 7/color, 4/radius
     201   draw-bezier-point screen, u, 0x210/xf 0x1d0/yf,  0x1c0/x1 0x2a0/y1,  0xe0/x2  0x2a0/y2, 7/color, 4/radius
     202   draw-bezier-point screen, u, 0x210/xf 0x1d0/yf,  0x210/xf  0x60/y1, 0x200/x2   0x60/y2, 7/color, 4/radius
     203   draw-bezier-point screen, u, 0x210/xf 0x1d0/yf,  0x210/xf 0x230/y1, 0x200/x2  0x2a0/y2, 7/color, 4/radius
     204   draw-bezier-point screen, u, 0x210/xf 0x1d0/yf,  0x320/x1 0x120/y1, 0x320/x2   0x60/y2, 7/color, 4/radius
     205   draw-bezier-point screen, u, 0x210/xf 0x1d0/yf,  0x320/x1 0x1c0/y1, 0x320/x2  0x180/y2, 7/color, 4/radius
     206   draw-bezier-point screen, u, 0x210/xf 0x1d0/yf,  0x320/x1 0x230/y1, 0x320/x2  0x2a0/y2, 7/color, 4/radius
     207 }
     208
     209 fn render1 screen: (addr screen), _self: (addr environment) {
     210   var self/esi: (addr environment) <- copy _self
     211   # cell borders
     212   draw-vertical-line   screen,  0xe0/x, 0/ymin, 0x300/ymax, 0x16/color=dark-grey
     213   draw-vertical-line   screen, 0x200/x, 0/ymin, 0x300/ymax, 0x16/color=dark-grey
     214   draw-vertical-line   screen, 0x320/x, 0/ymin, 0x300/ymax, 0x16/color=dark-grey
     215   draw-horizontal-line screen,  0x60/y, 0/xmin, 0x400/xmax, 0x16/color=dark-grey
     216   draw-horizontal-line screen, 0x180/y, 0/xmin, 0x400/xmax, 0x16/color=dark-grey
     217   draw-horizontal-line screen, 0x2a0/y, 0/xmin, 0x400/xmax, 0x16/color=dark-grey
     218   # cell 0: outputs
     219   var color/eax: int <- state-color self, 0x80/curx, 0x60/cury
     220   draw-rect screen,  0xe8/xmin  0x68/ymin, 0x118/xmax   0x98/ymax, color
     221   draw-rect screen,  0xe8/xmin  0xd0/ymin, 0x118/xmax  0x100/ymax, color
     222   draw-rect screen,  0xe8/xmin 0x148/ymin, 0x118/xmax  0x178/ymax, color
     223   draw-rect screen, 0x158/xmin  0x68/ymin, 0x188/xmax   0x98/ymax, color
     224   draw-rect screen, 0x158/xmin 0x148/ymin, 0x188/xmax  0x178/ymax, color
     225   draw-rect screen, 0x1c8/xmin  0x68/ymin, 0x1f8/xmax   0x98/ymax, color
     226   draw-rect screen, 0x1c8/xmin  0xd0/ymin, 0x1f8/xmax  0x100/ymax, color
     227   draw-rect screen, 0x1c8/xmin 0x148/ymin, 0x1f8/xmax  0x178/ymax, color
     228   # cell 1: outputs
     229   var color/eax: int <- state-color self, 0x81/curx, 0x60/cury
     230   draw-rect screen, 0x208/xmin  0x68/ymin, 0x238/xmax   0x98/ymax, color
     231   draw-rect screen, 0x208/xmin  0xd0/ymin, 0x238/xmax  0x100/ymax, color
     232   draw-rect screen, 0x208/xmin 0x148/ymin, 0x238/xmax  0x178/ymax, color
     233   draw-rect screen, 0x278/xmin  0x68/ymin, 0x2a8/xmax   0x98/ymax, color
     234   draw-rect screen, 0x278/xmin 0x148/ymin, 0x2a8/xmax  0x178/ymax, color
     235   draw-rect screen, 0x2e8/xmin  0x68/ymin, 0x318/xmax   0x98/ymax, color
     236   draw-rect screen, 0x2e8/xmin  0xd0/ymin, 0x318/xmax  0x100/ymax, color
     237   draw-rect screen, 0x2e8/xmin 0x148/ymin, 0x318/xmax  0x178/ymax, color
     238   # cell 2: outputs
     239   var color/eax: int <- state-color self, 0x80/curx, 0x61/cury
     240   draw-rect screen,  0xe8/xmin 0x188/ymin, 0x118/xmax  0x1b8/ymax, color
     241   draw-rect screen,  0xe8/xmin 0x1f0/ymin, 0x118/xmax  0x220/ymax, color
     242   draw-rect screen,  0xe8/xmin 0x268/ymin, 0x118/xmax  0x298/ymax, color
     243   draw-rect screen, 0x158/xmin 0x188/ymin, 0x188/xmax  0x1b8/ymax, color
     244   draw-rect screen, 0x158/xmin 0x268/ymin, 0x188/xmax  0x298/ymax, color
     245   draw-rect screen, 0x1c8/xmin 0x188/ymin, 0x1f8/xmax  0x1b8/ymax, color
     246   draw-rect screen, 0x1c8/xmin 0x1f0/ymin, 0x1f8/xmax  0x220/ymax, color
     247   draw-rect screen, 0x1c8/xmin 0x268/ymin, 0x1f8/xmax  0x298/ymax, color
     248   # cell 3: outputs
     249   var color/eax: int <- state-color self, 0x81/curx, 0x61/cury
     250   draw-rect screen, 0x208/xmin 0x188/ymin, 0x238/xmax  0x1b8/ymax, color
     251   draw-rect screen, 0x208/xmin 0x1f0/ymin, 0x238/xmax  0x220/ymax, color
     252   draw-rect screen, 0x208/xmin 0x268/ymin, 0x238/xmax  0x298/ymax, color
     253   draw-rect screen, 0x278/xmin 0x188/ymin, 0x2a8/xmax  0x1b8/ymax, color
     254   draw-rect screen, 0x278/xmin 0x268/ymin, 0x2a8/xmax  0x298/ymax, color
     255   draw-rect screen, 0x2e8/xmin 0x188/ymin, 0x318/xmax  0x1b8/ymax, color
     256   draw-rect screen, 0x2e8/xmin 0x1f0/ymin, 0x318/xmax  0x220/ymax, color
     257   draw-rect screen, 0x2e8/xmin 0x268/ymin, 0x318/xmax  0x298/ymax, color
     258   # neighboring nodes
     259   var color/eax: int <- state-color self, 0x7f/curx, 0x5f/cury
     260   draw-rect screen,  0xa8/xmin  0x28/ymin,  0xd8/xmax   0x58/ymax, color
     261   var color/eax: int <- state-color self, 0x80/curx, 0x5f/cury
     262   draw-rect screen, 0x158/xmin  0x28/ymin, 0x188/xmax   0x58/ymax, color
     263   draw-rect screen, 0x1c8/xmin  0x28/ymin, 0x1f8/xmax   0x58/ymax, color
     264   var color/eax: int <- state-color self, 0x81/curx, 0x5f/cury
     265   draw-rect screen, 0x208/xmin  0x28/ymin, 0x238/xmax   0x58/ymax, color
     266   draw-rect screen, 0x278/xmin  0x28/ymin, 0x2a8/xmax   0x58/ymax, color
     267   var color/eax: int <- state-color self, 0x82/curx, 0x5f/cury
     268   draw-rect screen, 0x328/xmin  0x28/ymin, 0x358/xmax   0x58/ymax, color
     269   var color/eax: int <- state-color self, 0x7f/curx, 0x60/cury
     270   draw-rect screen,  0xa8/xmin  0xd0/ymin,  0xd8/xmax  0x100/ymax, color
     271   draw-rect screen,  0xa8/xmin 0x148/ymin,  0xd8/xmax  0x178/ymax, color
     272   var color/eax: int <- state-color self, 0x82/curx, 0x60/cury
     273   draw-rect screen, 0x328/xmin  0xd0/ymin, 0x358/xmax  0x100/ymax, color
     274   draw-rect screen, 0x328/xmin 0x148/ymin, 0x358/xmax  0x178/ymax, color
     275   var color/eax: int <- state-color self, 0x7f/curx, 0x61/cury
     276   draw-rect screen,  0xa8/xmin 0x188/ymin,  0xd8/xmax  0x1b8/ymax, color
     277   draw-rect screen,  0xa8/xmin 0x1f0/ymin,  0xd8/xmax  0x220/ymax, color
     278   var color/eax: int <- state-color self, 0x82/curx, 0x61/cury
     279   draw-rect screen, 0x328/xmin 0x188/ymin, 0x358/xmax  0x1b8/ymax, color
     280   draw-rect screen, 0x328/xmin 0x1f0/ymin, 0x358/xmax  0x220/ymax, color
     281   var color/eax: int <- state-color self, 0x7f/curx, 0x62/cury
     282   draw-rect screen,  0xa8/xmin 0x2a8/ymin,  0xd8/xmax  0x2d8/ymax, color
     283   var color/eax: int <- state-color self, 0x80/curx, 0x62/cury
     284   draw-rect screen, 0x158/xmin 0x2a8/ymin, 0x188/xmax  0x2d8/ymax, color
     285   draw-rect screen, 0x1c8/xmin 0x2a8/ymin, 0x1f8/xmax  0x2d8/ymax, color
     286   var color/eax: int <- state-color self, 0x81/curx, 0x62/cury
     287   draw-rect screen, 0x208/xmin 0x2a8/ymin, 0x238/xmax  0x2d8/ymax, color
     288   draw-rect screen, 0x278/xmin 0x2a8/ymin, 0x2a8/xmax  0x2d8/ymax, color
     289   var color/eax: int <- state-color self, 0x82/curx, 0x62/cury
     290   draw-rect screen, 0x328/xmin 0x2a8/ymin, 0x358/xmax  0x2d8/ymax, color
     291   # cell 0: sum and filter nodes
     292   draw-rect screen, 0x148/xsmin  0xc8/ysmin, 0x158/xsmax  0xd8/ysmax, 0x40/color
     293   draw-rect screen, 0x180/xfmin  0xf8/yfmin, 0x190/xfmax 0x108/yfmax, 0x31/color
     294   # cell 1: sum and filter nodes
     295   draw-rect screen, 0x268/xsmin  0xc8/ysmin, 0x278/xsmax  0xd8/ysmax, 0x40/color
     296   draw-rect screen, 0x2a0/xfmin  0xf8/yfmin, 0x2b0/xfmax 0x108/yfmax, 0x31/color
     297   # cell 2: sum and filter nodes
     298   draw-rect screen, 0x148/xsmin 0x1e8/ysmin, 0x158/xsmax 0x1f8/ysmax, 0x40/color
     299   draw-rect screen, 0x180/xfmin 0x218/yfmin, 0x190/xfmax 0x228/yfmax, 0x31/color
     300   # cell 3: sum and filter nodes
     301   draw-rect screen, 0x268/xsmin 0x1e8/ysmin, 0x278/xsmax 0x1f8/ysmax, 0x40/color
     302   draw-rect screen, 0x2a0/xfmin 0x218/yfmin, 0x2b0/xfmax 0x228/yfmax, 0x31/color
     303   # neighbor counts
     304   var n/eax: int <- num-live-neighbors self, 0x80/curx, 0x60/cury
     305   set-cursor-position screen, 0x2d, 0xe
     306   draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen screen, n, 0xf/fg 0/bg
     307   var n/eax: int <- num-live-neighbors self, 0x81/curx, 0x60/cury
     308   set-cursor-position screen, 0x52, 0xe
     309   draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen screen, n, 0xf/fg 0/bg
     310   var n/eax: int <- num-live-neighbors self, 0x80/curx, 0x61/cury
     311   set-cursor-position screen, 0x2d, 0x20
     312   draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen screen, n, 0xf/fg 0/bg
     313   var n/eax: int <- num-live-neighbors self, 0x81/curx, 0x61/cury
     314   set-cursor-position screen, 0x52, 0x20
     315   draw-int32-decimal-wrapping-right-then-down-from-cursor-over-full-screen screen, n, 0xf/fg 0/bg
     316   # cell 0: conveyors from neighboring inputs to sum node
     317   draw-monotonic-bezier screen,  0xc0/x0  0x40/y0,  0x100/x1  0xd0/ys, 0x150/xs  0xd0/ys,  4/color
     318   draw-monotonic-bezier screen,  0xc0/x0  0xe8/y0,   0xc0/x1  0xd0/ys, 0x150/xs  0xd0/ys,  4/color
     319   draw-monotonic-bezier screen,  0xc0/x0 0x1a0/y0,   0xe0/x1  0xd0/ys, 0x150/xs  0xd0/ys,  4/color
     320   draw-monotonic-bezier screen, 0x170/x0  0x40/y0,  0x150/x1  0x80/y1, 0x150/xs  0xd0/ys,  4/color
     321   draw-monotonic-bezier screen, 0x170/x0 0x1a0/y0,  0x150/x1 0x1a0/y1, 0x150/xs  0xd0/ys,  4/color
     322   draw-monotonic-bezier screen, 0x220/x0  0x40/y0,  0x150/x1  0x80/y1, 0x150/xs  0xd0/ys,  4/color
     323   draw-monotonic-bezier screen, 0x220/x0  0xe8/y0,  0x220/x1  0xd0/y1, 0x150/xs  0xd0/ys,  4/color
     324   draw-monotonic-bezier screen, 0x220/x0 0x1a0/y0,  0x180/x1 0x1a0/y1, 0x150/xs  0xd0/ys,  4/color
     325   # cell 0: conveyors from filter to outputs
     326   draw-monotonic-bezier screen, 0x188/xf 0x100/yf,  0x160/x1  0x8c/y1, 0x100/x2  0x80/y2,  0x2a/color
     327   draw-monotonic-bezier screen, 0x188/xf 0x100/yf,  0x100/x1 0x100/y1, 0x100/x2  0xe8/y2,  0x2a/color
     328   draw-monotonic-bezier screen, 0x188/xf 0x100/yf,  0x100/x1 0x100/y1, 0x100/x2 0x160/y2,  0x2a/color
     329   draw-monotonic-bezier screen, 0x188/xf 0x100/yf,  0x188/x1  0x80/y1, 0x170/x2  0x80/y2,  0x2a/color
     330   draw-monotonic-bezier screen, 0x188/xf 0x100/yf,  0x188/x1 0x160/y1, 0x170/x2 0x160/y2,  0x2a/color
     331   draw-monotonic-bezier screen, 0x188/xf 0x100/yf,  0x1e0/x1 0x100/y1, 0x1e0/x2  0x80/y2,  0x2a/color
     332   draw-monotonic-bezier screen, 0x188/xf 0x100/yf,  0x1e0/x1 0x100/y1  0x1e0/x2  0xe8/y2,  0x2a/color
     333   draw-monotonic-bezier screen, 0x188/xf 0x100/yf,  0x1e0/x1 0x100/y1, 0x1e0/x2 0x160/y2,  0x2a/color
     334   # cell 0: time-variant portion: 16 repeating steps
     335   $render1:cell0: {
     336     var tick-a/eax: (addr int) <- get self, tick
     337     var progress/eax: int <- copy *tick-a
     338     progress <- and 0xf
     339     # cell 0: 7 time steps for getting inputs to sum
     340     {
     341       compare progress, 7
     342       break-if->=
     343       var u/xmm7: float <- convert progress
     344       var six/eax: int <- copy 6
     345       var six-f/xmm0: float <- convert six
     346       u <- divide six-f
     347       # points on conveyors from neighboring cells
     348       draw-bezier-point screen, u,  0xc0/x0  0x40/y0, 0x100/x1  0xd0/ys, 0x150/xs  0xd0/ys, 7/color, 4/radius
     349       draw-bezier-point screen, u,  0xc0/x0  0xe8/y0,  0xc0/x1  0xd0/ys, 0x150/xs  0xd0/ys, 7/color, 4/radius
     350       draw-bezier-point screen, u,  0xc0/x0 0x1a0/y0,  0xe0/x1  0xd0/ys, 0x150/xs  0xd0/ys, 7/color, 4/radius
     351       draw-bezier-point screen, u, 0x170/x0  0x40/y0, 0x150/x1  0x80/y1, 0x150/xs  0xd0/ys, 7/color, 4/radius
     352       draw-bezier-point screen, u, 0x170/x0 0x1a0/y0, 0x150/x1 0x1a0/y1, 0x150/xs  0xd0/ys, 7/color, 4/radius
     353       draw-bezier-point screen, u, 0x220/x0  0x40/y0, 0x150/x1  0x80/y1, 0x150/xs  0xd0/ys, 7/color, 4/radius
     354       draw-bezier-point screen, u, 0x220/x0  0xe8/y0, 0x220/x1  0xd0/y1, 0x150/xs  0xd0/ys, 7/color, 4/radius
     355       draw-bezier-point screen, u, 0x220/x0 0x1a0/y0, 0x180/x1 0x1a0/y1, 0x150/xs  0xd0/ys, 7/color, 4/radius
     356       break $render1:cell0
     357     }
     358     # cell 0: two time steps for getting count to filter
     359     progress <- subtract 7
     360     {
     361       compare progress, 2
     362       break-if->=
     363       break $render1:cell0
     364     }
     365     # cell 0: final 7 time steps for updating output
     366     progress <- subtract 2
     367     # cell 0: points on conveyors to outputs
     368     var u/xmm7: float <- convert progress
     369     var six/eax: int <- copy 6
     370     var six-f/xmm0: float <- convert six
     371     u <- divide six-f
     372     draw-bezier-point screen, u, 0x188/xf 0x100/yf,  0x160/x1  0x8c/y1, 0x100/x2  0x80/y2, 7/color, 4/radius
     373     draw-bezier-point screen, u, 0x188/xf 0x100/yf,  0x100/x1 0x100/y1, 0x100/x2  0xe8/y2, 7/color, 4/radius
     374     draw-bezier-point screen, u, 0x188/xf 0x100/yf,  0x100/x1 0x100/y1, 0x100/x2 0x160/y2, 7/color, 4/radius
     375     draw-bezier-point screen, u, 0x188/xf 0x100/yf,  0x188/xf  0x80/y1, 0x170/x2  0x80/y2, 7/color, 4/radius
     376     draw-bezier-point screen, u, 0x188/xf 0x100/yf,  0x188/xf 0x160/y1, 0x170/x2 0x160/y2, 7/color, 4/radius
     377     draw-bezier-point screen, u, 0x188/xf 0x100/yf,  0x1e0/x1 0x100/y1, 0x1e0/x2  0x80/y2, 7/color, 4/radius
     378     draw-bezier-point screen, u, 0x188/xf 0x100/yf,  0x1e0/x1 0x100/y1, 0x1e0/x2  0xe8/y2, 7/color, 4/radius
     379     draw-bezier-point screen, u, 0x188/xf 0x100/yf,  0x1e0/x1 0x100/y1, 0x1e0/x2 0x160/y2, 7/color, 4/radius
     380   }
     381   # cell 1: conveyors from neighboring inputs to sum node
     382   draw-monotonic-bezier screen, 0x1e0/x0  0x40/y0,  0x220/x1  0xd0/ys, 0x270/xs  0xd0/ys,  4/color
     383   draw-monotonic-bezier screen, 0x1e0/x0  0xe8/y0,  0x1e0/x1  0xd0/ys, 0x270/xs  0xd0/ys,  4/color
     384   draw-monotonic-bezier screen, 0x1e0/x0 0x1a0/y0,  0x200/x1  0xd0/ys, 0x270/xs  0xd0/ys,  4/color
     385   draw-monotonic-bezier screen, 0x290/x0  0x40/y0,  0x270/x1  0x80/y1, 0x270/xs  0xd0/ys,  4/color
     386   draw-monotonic-bezier screen, 0x290/x0 0x1a0/y0,  0x270/x1 0x1a0/y1, 0x270/xs  0xd0/ys,  4/color
     387   draw-monotonic-bezier screen, 0x340/x0  0x40/y0,  0x270/x1  0x80/y1, 0x270/xs  0xd0/ys,  4/color
     388   draw-monotonic-bezier screen, 0x340/x0  0xe8/y0,  0x340/x1  0xd0/y1, 0x270/xs  0xd0/ys,  4/color
     389   draw-monotonic-bezier screen, 0x340/x0 0x1a0/y0,  0x2a0/x1 0x1a0/y1, 0x270/xs  0xd0/ys,  4/color
     390   # cell 1: conveyors from filter to outputs
     391   draw-monotonic-bezier screen, 0x2a8/xf 0x100/yf,  0x280/x1  0x8c/y1, 0x220/x2  0x80/y2,  0x2a/color
     392   draw-monotonic-bezier screen, 0x2a8/xf 0x100/yf,  0x220/x1 0x100/y1, 0x220/x2  0xe8/y2,  0x2a/color
     393   draw-monotonic-bezier screen, 0x2a8/xf 0x100/yf,  0x220/x1 0x100/y1, 0x220/x2 0x160/y2,  0x2a/color
     394   draw-monotonic-bezier screen, 0x2a8/xf 0x100/yf,  0x2a8/x1  0x80/y1, 0x290/x2  0x80/y2,  0x2a/color
     395   draw-monotonic-bezier screen, 0x2a8/xf 0x100/yf,  0x2a8/x1 0x160/y1, 0x290/x2 0x160/y2,  0x2a/color
     396   draw-monotonic-bezier screen, 0x2a8/xf 0x100/yf,  0x300/x1 0x100/y1, 0x300/x2  0x80/y2,  0x2a/color
     397   draw-monotonic-bezier screen, 0x2a8/xf 0x100/yf,  0x300/x1 0x100/y1  0x300/x2  0xe8/y2,  0x2a/color
     398   draw-monotonic-bezier screen, 0x2a8/xf 0x100/yf,  0x300/x1 0x100/y1, 0x300/x2 0x160/y2,  0x2a/color
     399   # cell 1: time-variant portion: 16 repeating steps
     400   $render1:cell1: {
     401     var tick-a/eax: (addr int) <- get self, tick
     402     var progress/eax: int <- copy *tick-a
     403     progress <- and 0xf
     404     # cell 1: 7 time steps for getting inputs to sum
     405     {
     406       compare progress, 7
     407       break-if->=
     408       var u/xmm7: float <- convert progress
     409       var six/eax: int <- copy 6
     410       var six-f/xmm0: float <- convert six
     411       u <- divide six-f
     412       # points on conveyors from neighboring cells
     413       draw-bezier-point screen, u, 0x1e0/x0  0x40/y0, 0x220/x1  0xd0/ys, 0x270/xs  0xd0/ys, 7/color, 4/radius
     414       draw-bezier-point screen, u, 0x1e0/x0  0xe8/y0, 0x1e0/x1  0xd0/ys, 0x270/xs  0xd0/ys, 7/color, 4/radius
     415       draw-bezier-point screen, u, 0x1e0/x0 0x1a0/y0, 0x200/x1  0xd0/ys, 0x270/xs  0xd0/ys, 7/color, 4/radius
     416       draw-bezier-point screen, u, 0x290/x0  0x40/y0, 0x270/x1  0x80/y1, 0x270/xs  0xd0/ys, 7/color, 4/radius
     417       draw-bezier-point screen, u, 0x290/x0 0x1a0/y0, 0x270/x1 0x1a0/y1, 0x270/xs  0xd0/ys, 7/color, 4/radius
     418       draw-bezier-point screen, u, 0x340/x0  0x40/y0, 0x270/x1  0x80/y1, 0x270/xs  0xd0/ys, 7/color, 4/radius
     419       draw-bezier-point screen, u, 0x340/x0  0xe8/y0, 0x340/x1  0xd0/y1, 0x270/xs  0xd0/ys, 7/color, 4/radius
     420       draw-bezier-point screen, u, 0x340/x0 0x1a0/y0, 0x2a0/x1 0x1a0/y1, 0x270/xs  0xd0/ys, 7/color, 4/radius
     421       break $render1:cell1
     422     }
     423     # cell 1: two time steps for getting count to filter
     424     progress <- subtract 7
     425     {
     426       compare progress, 2
     427       break-if->=
     428       break $render1:cell1
     429     }
     430     # cell 1: final 7 time steps for updating output
     431     progress <- subtract 2
     432     # cell 1: points on conveyors to outputs
     433     var u/xmm7: float <- convert progress
     434     var six/eax: int <- copy 6
     435     var six-f/xmm0: float <- convert six
     436     u <- divide six-f
     437     draw-bezier-point screen, u, 0x2a8/xf 0x100/yf,  0x280/x1  0x8c/y1, 0x220/x2  0x80/y2, 7/color, 4/radius
     438     draw-bezier-point screen, u, 0x2a8/xf 0x100/yf,  0x220/x1 0x100/y1, 0x220/x2  0xe8/y2, 7/color, 4/radius
     439     draw-bezier-point screen, u, 0x2a8/xf 0x100/yf,  0x220/x1 0x100/y1, 0x220/x2 0x160/y2, 7/color, 4/radius
     440     draw-bezier-point screen, u, 0x2a8/xf 0x100/yf,  0x2a8/xf  0x80/y1, 0x290/x2  0x80/y2, 7/color, 4/radius
     441     draw-bezier-point screen, u, 0x2a8/xf 0x100/yf,  0x2a8/xf 0x160/y1, 0x290/x2 0x160/y2, 7/color, 4/radius
     442     draw-bezier-point screen, u, 0x2a8/xf 0x100/yf,  0x300/x1 0x100/y1, 0x300/x2  0x80/y2, 7/color, 4/radius
     443     draw-bezier-point screen, u, 0x2a8/xf 0x100/yf,  0x300/x1 0x100/y1, 0x300/x2  0xe8/y2, 7/color, 4/radius
     444     draw-bezier-point screen, u, 0x2a8/xf 0x100/yf,  0x300/x1 0x100/y1, 0x300/x2 0x160/y2, 7/color, 4/radius
     445   }
     446   # cell 2: conveyors from neighboring inputs to sum node
     447   draw-monotonic-bezier screen,  0xc0/x0 0x160/y0,  0x100/x1 0x1f0/ys, 0x150/xs 0x1f0/ys,  4/color
     448   draw-monotonic-bezier screen,  0xc0/x0 0x208/y0,   0xc0/x1 0x1f0/ys, 0x150/xs 0x1f0/ys,  4/color
     449   draw-monotonic-bezier screen,  0xc0/x0 0x2c0/y0,   0xe0/x1 0x1f0/ys, 0x150/xs 0x1f0/ys,  4/color
     450   draw-monotonic-bezier screen, 0x170/x0 0x160/y0,  0x150/x1 0x1a0/y1, 0x150/xs 0x1f0/ys,  4/color
     451   draw-monotonic-bezier screen, 0x170/x0 0x2c0/y0,  0x150/x1 0x2c0/y1, 0x150/xs 0x1f0/ys,  4/color
     452   draw-monotonic-bezier screen, 0x220/x0 0x160/y0,  0x150/x1 0x1a0/y1, 0x150/xs 0x1f0/ys,  4/color
     453   draw-monotonic-bezier screen, 0x220/x0 0x208/y0,  0x220/x1 0x1f0/y1, 0x150/xs 0x1f0/ys,  4/color
     454   draw-monotonic-bezier screen, 0x220/x0 0x2c0/y0,  0x180/x1 0x2c0/y1, 0x150/xs 0x1f0/ys,  4/color
     455   # cell 2: conveyors from filter to outputs
     456   draw-monotonic-bezier screen, 0x188/xf 0x220/yf,  0x160/x1 0x1ac/y1, 0x100/x2 0x1a0/y2,  0x2a/color
     457   draw-monotonic-bezier screen, 0x188/xf 0x220/yf,  0x100/x1 0x220/y1, 0x100/x2 0x208/y2,  0x2a/color
     458   draw-monotonic-bezier screen, 0x188/xf 0x220/yf,  0x100/x1 0x220/y1, 0x100/x2 0x280/y2,  0x2a/color
     459   draw-monotonic-bezier screen, 0x188/xf 0x220/yf,  0x188/x1 0x1a0/y1, 0x170/x2 0x1a0/y2,  0x2a/color
     460   draw-monotonic-bezier screen, 0x188/xf 0x220/yf,  0x188/x1 0x280/y1, 0x170/x2 0x280/y2,  0x2a/color
     461   draw-monotonic-bezier screen, 0x188/xf 0x220/yf,  0x1e0/x1 0x220/y1, 0x1e0/x2 0x1a0/y2,  0x2a/color
     462   draw-monotonic-bezier screen, 0x188/xf 0x220/yf,  0x1e0/x1 0x220/y1  0x1e0/x2 0x208/y2,  0x2a/color
     463   draw-monotonic-bezier screen, 0x188/xf 0x220/yf,  0x1e0/x1 0x220/y1, 0x1e0/x2 0x280/y2,  0x2a/color
     464   # cell 2: time-variant portion: 16 repeating steps
     465   $render1:cell2: {
     466     var tick-a/eax: (addr int) <- get self, tick
     467     var progress/eax: int <- copy *tick-a
     468     progress <- and 0xf
     469     # cell 2: 7 time steps for getting inputs to sum
     470     {
     471       compare progress, 7
     472       break-if->=
     473       var u/xmm7: float <- convert progress
     474       var six/eax: int <- copy 6
     475       var six-f/xmm0: float <- convert six
     476       u <- divide six-f
     477       # points on conveyors from neighboring cells
     478       draw-bezier-point screen, u,  0xc0/x0 0x160/y0, 0x100/x1 0x1f0/ys, 0x150/xs 0x1f0/ys, 7/color, 4/radius
     479       draw-bezier-point screen, u,  0xc0/x0 0x208/y0,  0xc0/x1 0x1f0/ys, 0x150/xs 0x1f0/ys, 7/color, 4/radius
     480       draw-bezier-point screen, u,  0xc0/x0 0x2c0/y0,  0xe0/x1 0x1f0/ys, 0x150/xs 0x1f0/ys, 7/color, 4/radius
     481       draw-bezier-point screen, u, 0x170/x0 0x160/y0, 0x150/x1 0x1a0/y1, 0x150/xs 0x1f0/ys, 7/color, 4/radius
     482       draw-bezier-point screen, u, 0x170/x0 0x2c0/y0, 0x150/x1 0x2c0/y1, 0x150/xs 0x1f0/ys, 7/color, 4/radius
     483       draw-bezier-point screen, u, 0x220/x0 0x160/y0, 0x150/x1 0x1a0/y1, 0x150/xs 0x1f0/ys, 7/color, 4/radius
     484       draw-bezier-point screen, u, 0x220/x0 0x208/y0, 0x220/x1 0x1f0/y1, 0x150/xs 0x1f0/ys, 7/color, 4/radius
     485       draw-bezier-point screen, u, 0x220/x0 0x2c0/y0, 0x180/x1 0x2c0/y1, 0x150/xs 0x1f0/ys, 7/color, 4/radius
     486       break $render1:cell2
     487     }
     488     # cell 2: two time steps for getting count to filter
     489     progress <- subtract 7
     490     {
     491       compare progress, 2
     492       break-if->=
     493       break $render1:cell2
     494     }
     495     # cell 2: final 7 time steps for updating output
     496     progress <- subtract 2
     497     # cell 2: points on conveyors to outputs
     498     var u/xmm7: float <- convert progress
     499     var six/eax: int <- copy 6
     500     var six-f/xmm0: float <- convert six
     501     u <- divide six-f
     502     draw-bezier-point screen, u, 0x188/xf 0x220/yf,  0x160/x1 0x1ac/y1, 0x100/x2 0x1a0/y2, 7/color, 4/radius
     503     draw-bezier-point screen, u, 0x188/xf 0x220/yf,  0x100/x1 0x220/y1, 0x100/x2 0x208/y2, 7/color, 4/radius
     504     draw-bezier-point screen, u, 0x188/xf 0x220/yf,  0x100/x1 0x220/y1, 0x100/x2 0x280/y2, 7/color, 4/radius
     505     draw-bezier-point screen, u, 0x188/xf 0x220/yf,  0x188/xf 0x1a0/y1, 0x170/x2 0x1a0/y2, 7/color, 4/radius
     506     draw-bezier-point screen, u, 0x188/xf 0x220/yf,  0x188/xf 0x280/y1, 0x170/x2 0x280/y2, 7/color, 4/radius
     507     draw-bezier-point screen, u, 0x188/xf 0x220/yf,  0x1e0/x1 0x220/y1, 0x1e0/x2 0x1a0/y2, 7/color, 4/radius
     508     draw-bezier-point screen, u, 0x188/xf 0x220/yf,  0x1e0/x1 0x220/y1, 0x1e0/x2 0x208/y2, 7/color, 4/radius
     509     draw-bezier-point screen, u, 0x188/xf 0x220/yf,  0x1e0/x1 0x220/y1, 0x1e0/x2 0x280/y2, 7/color, 4/radius
     510   }
     511   # cell 3: conveyors from neighboring inputs to sum node
     512   draw-monotonic-bezier screen, 0x1e0/x0 0x160/y0,  0x220/x1 0x1f0/ys, 0x270/xs 0x1f0/ys,  4/color
     513   draw-monotonic-bezier screen, 0x1e0/x0 0x208/y0,  0x1e0/x1 0x1f0/ys, 0x270/xs 0x1f0/ys,  4/color
     514   draw-monotonic-bezier screen, 0x1e0/x0 0x2c0/y0,  0x200/x1 0x1f0/ys, 0x270/xs 0x1f0/ys,  4/color
     515   draw-monotonic-bezier screen, 0x290/x0 0x160/y0,  0x270/x1 0x1a0/y1, 0x270/xs 0x1f0/ys,  4/color
     516   draw-monotonic-bezier screen, 0x290/x0 0x2c0/y0,  0x270/x1 0x2c0/y1, 0x270/xs 0x1f0/ys,  4/color
     517   draw-monotonic-bezier screen, 0x340/x0 0x160/y0,  0x270/x1 0x1a0/y1, 0x270/xs 0x1f0/ys,  4/color
     518   draw-monotonic-bezier screen, 0x340/x0 0x208/y0,  0x340/x1 0x1f0/y1, 0x270/xs 0x1f0/ys,  4/color
     519   draw-monotonic-bezier screen, 0x340/x0 0x2c0/y0,  0x2a0/x1 0x2c0/y1, 0x270/xs 0x1f0/ys,  4/color
     520   # cell 3: conveyors from filter to outputs
     521   draw-monotonic-bezier screen, 0x2a8/xf 0x220/yf,  0x280/x1 0x1ac/y1, 0x220/x2 0x1a0/y2,  0x2a/color
     522   draw-monotonic-bezier screen, 0x2a8/xf 0x220/yf,  0x220/x1 0x220/y1, 0x220/x2 0x208/y2,  0x2a/color
     523   draw-monotonic-bezier screen, 0x2a8/xf 0x220/yf,  0x220/x1 0x220/y1, 0x220/x2 0x280/y2,  0x2a/color
     524   draw-monotonic-bezier screen, 0x2a8/xf 0x220/yf,  0x2a8/x1 0x1a0/y1, 0x290/x2 0x1a0/y2,  0x2a/color
     525   draw-monotonic-bezier screen, 0x2a8/xf 0x220/yf,  0x2a8/x1 0x280/y1, 0x290/x2 0x280/y2,  0x2a/color
     526   draw-monotonic-bezier screen, 0x2a8/xf 0x220/yf,  0x300/x1 0x220/y1, 0x300/x2 0x1a0/y2,  0x2a/color
     527   draw-monotonic-bezier screen, 0x2a8/xf 0x220/yf,  0x300/x1 0x220/y1  0x300/x2 0x208/y2,  0x2a/color
     528   draw-monotonic-bezier screen, 0x2a8/xf 0x220/yf,  0x300/x1 0x220/y1, 0x300/x2 0x280/y2,  0x2a/color
     529   # cell 3: time-variant portion: 16 repeating steps
     530   $render1:cell3: {
     531     var tick-a/eax: (addr int) <- get self, tick
     532     var progress/eax: int <- copy *tick-a
     533     progress <- and 0xf
     534     # cell 3: 7 time steps for getting inputs to sum
     535     {
     536       compare progress, 7
     537       break-if->=
     538       var u/xmm7: float <- convert progress
     539       var six/eax: int <- copy 6
     540       var six-f/xmm0: float <- convert six
     541       u <- divide six-f
     542       # points on conveyors from neighboring cells
     543       draw-bezier-point screen, u, 0x1e0/x0 0x160/y0, 0x220/x1 0x1f0/ys, 0x270/xs 0x1f0/ys, 7/color, 4/radius
     544       draw-bezier-point screen, u, 0x1e0/x0 0x208/y0, 0x1e0/x1 0x1f0/ys, 0x270/xs 0x1f0/ys, 7/color, 4/radius
     545       draw-bezier-point screen, u, 0x1e0/x0 0x2c0/y0, 0x200/x1 0x1f0/ys, 0x270/xs 0x1f0/ys, 7/color, 4/radius
     546       draw-bezier-point screen, u, 0x290/x0 0x160/y0, 0x270/x1 0x1a0/y1, 0x270/xs 0x1f0/ys, 7/color, 4/radius
     547       draw-bezier-point screen, u, 0x290/x0 0x2c0/y0, 0x270/x1 0x2c0/y1, 0x270/xs 0x1f0/ys, 7/color, 4/radius
     548       draw-bezier-point screen, u, 0x340/x0 0x160/y0, 0x270/x1 0x1a0/y1, 0x270/xs 0x1f0/ys, 7/color, 4/radius
     549       draw-bezier-point screen, u, 0x340/x0 0x208/y0, 0x340/x1 0x1f0/y1, 0x270/xs 0x1f0/ys, 7/color, 4/radius
     550       draw-bezier-point screen, u, 0x340/x0 0x2c0/y0, 0x2a0/x1 0x2c0/y1, 0x270/xs 0x1f0/ys, 7/color, 4/radius
     551       break $render1:cell3
     552     }
     553     # cell 3: two time steps for getting count to filter
     554     progress <- subtract 7
     555     {
     556       compare progress, 2
     557       break-if->=
     558       break $render1:cell3
     559     }
     560     # cell 3: final 7 time steps for updating output
     561     progress <- subtract 2
     562     # cell 3: points on conveyors to outputs
     563     var u/xmm7: float <- convert progress
     564     var six/eax: int <- copy 6
     565     var six-f/xmm0: float <- convert six
     566     u <- divide six-f
     567     draw-bezier-point screen, u, 0x2a8/xf 0x220/yf,  0x280/x1 0x1ac/y1, 0x220/x2 0x1a0/y2, 7/color, 4/radius
     568     draw-bezier-point screen, u, 0x2a8/xf 0x220/yf,  0x220/x1 0x220/y1, 0x220/x2 0x208/y2, 7/color, 4/radius
     569     draw-bezier-point screen, u, 0x2a8/xf 0x220/yf,  0x220/x1 0x220/y1, 0x220/x2 0x280/y2, 7/color, 4/radius
     570     draw-bezier-point screen, u, 0x2a8/xf 0x220/yf,  0x2a8/xf 0x1a0/y1, 0x290/x2 0x1a0/y2, 7/color, 4/radius
     571     draw-bezier-point screen, u, 0x2a8/xf 0x220/yf,  0x2a8/xf 0x280/y1, 0x290/x2 0x280/y2, 7/color, 4/radius
     572     draw-bezier-point screen, u, 0x2a8/xf 0x220/yf,  0x300/x1 0x220/y1, 0x300/x2 0x1a0/y2, 7/color, 4/radius
     573     draw-bezier-point screen, u, 0x2a8/xf 0x220/yf,  0x300/x1 0x220/y1, 0x300/x2 0x208/y2, 7/color, 4/radius
     574     draw-bezier-point screen, u, 0x2a8/xf 0x220/yf,  0x300/x1 0x220/y1, 0x300/x2 0x280/y2, 7/color, 4/radius
     575   }
     576 }
     577
     578 fn draw-bezier-point screen: (addr screen), u: float, x0: int, y0: int, x1: int, y1: int, x2: int, y2: int, color: int, radius: int {
     579   var _cy/eax: int <- bezier-point u, y0, y1, y2
     580   var cy/ecx: int <- copy _cy
     581   var cx/eax: int <- bezier-point u, x0, x1, x2
     582   draw-disc screen, cx, cy, radius, color, 0xf/border-color=white
     583 }
     584
     585 fn draw-linear-point screen: (addr screen), u: float, x0: int, y0: int, x1: int, y1: int, color: int, radius: int {
     586   var _cy/eax: int <- line-point u, y0, y1
     587   var cy/ecx: int <- copy _cy
     588   var cx/eax: int <- line-point u, x0, x1
     589   draw-disc screen, cx, cy, radius, color, 0xf/border-color=white
     590 }
     591
     592 fn edit keyboard: (addr keyboard), _self: (addr environment) {
     593   var self/esi: (addr environment) <- copy _self
     594   var key/eax: byte <- read-key keyboard
     595   # space: play/pause
     596   {
     597     compare key, 0x20/space
     598     break-if-!=
     599     var play?/eax: (addr boolean) <- get self, play?
     600     compare *play?, 0/false
     601     {
     602       break-if-=
     603       copy-to *play?, 0/false
     604       return
     605     }
     606     copy-to *play?, 1/true
     607     return
     608   }
     609   # 0: back to start
     610   {
     611     compare key, 0x30/0
     612     break-if-!=
     613     clear-environment self
     614     return
     615   }
     616   # l: loop from here to start
     617   {
     618     compare key, 0x6c/l
     619     break-if-!=
     620     var tick-a/eax: (addr int) <- get self, tick
     621     var tick/eax: int <- copy *tick-a
     622     var loop/ecx: (addr int) <- get self, loop
     623     copy-to *loop, tick
     624     return
     625   }
     626   # L: reset loop
     627   {
     628     compare key, 0x4c/L
     629     break-if-!=
     630     var loop/eax: (addr int) <- get self, loop
     631     copy-to *loop, 0
     632     return
     633   }
     634   # -: zoom out
     635   {
     636     compare key, 0x2d/-
     637     break-if-!=
     638     var zoom/eax: (addr int) <- get self, zoom
     639     compare *zoom, 1
     640     {
     641       break-if-!=
     642       copy-to *zoom, 4
     643     }
     644     compare *zoom, 0
     645     {
     646       break-if-!=
     647       copy-to *zoom, 1
     648     }
     649     # set tick to a multiple of zoom
     650     var tick-a/edx: (addr int) <- get self, tick
     651     clear-lowest-bits tick-a, *zoom
     652     return
     653   }
     654   # +: zoom in
     655   {
     656     compare key, 0x2b/+
     657     break-if-!=
     658     var zoom/eax: (addr int) <- get self, zoom
     659     compare *zoom, 1
     660     {
     661       break-if-!=
     662       copy-to *zoom, 0
     663     }
     664     compare *zoom, 4
     665     {
     666       break-if-!=
     667       copy-to *zoom, 1
     668     }
     669     # set tick to a multiple of zoom
     670     var tick-a/edx: (addr int) <- get self, tick
     671     clear-lowest-bits tick-a, *zoom
     672     return
     673   }
     674 }
     675
     676 fn step _self: (addr environment) {
     677   var self/esi: (addr environment) <- copy _self
     678   var tick-a/ecx: (addr int) <- get self, tick
     679   var zoom/edx: (addr int) <- get self, zoom
     680   compare *zoom, 0
     681   {
     682     break-if-!=
     683     increment *tick-a
     684   }
     685   compare *zoom, 1
     686   {
     687     break-if-!=
     688     # I wanted to speed up time, but that doesn't seem very usable.
     689 #?     add-to *tick-a, 2
     690     increment *tick-a
     691   }
     692   compare *zoom, 4
     693   {
     694     break-if-!=
     695     add-to *tick-a, 0x10
     696   }
     697   var tick/eax: int <- copy *tick-a
     698   tick <- and 0xf
     699   compare tick, 0
     700   {
     701     break-if-!=
     702     step4 self
     703   }
     704   var loop-a/eax: (addr int) <- get self, loop
     705   compare *loop-a, 0
     706   {
     707     break-if-=
     708     var loop/eax: int <- copy *loop-a
     709     compare *tick-a, loop
     710     break-if-<
     711     clear-environment self
     712   }
     713 }
     714
     715 fn initialize-environment _self: (addr environment) {
     716   var self/esi: (addr environment) <- copy _self
     717   var zoom/eax: (addr int) <- get self, zoom
     718   copy-to *zoom, 0
     719   var play?/eax: (addr boolean) <- get self, play?
     720   copy-to *play?, 1/true
     721   var data-ah/eax: (addr handle array handle array cell) <- get self, data
     722   populate data-ah, 0x100
     723   var data/eax: (addr array handle array cell) <- lookup *data-ah
     724   var y/ecx: int <- copy 0
     725   {
     726     compare y, 0xc0
     727     break-if->=
     728     var dest-ah/eax: (addr handle array cell) <- index data, y
     729     populate dest-ah, 0x100
     730     y <- increment
     731     loop
     732   }
     733   set self, 0x80, 0x5f, 1/alive
     734   set self, 0x81, 0x5f, 1/alive
     735   set self, 0x7f, 0x60, 1/alive
     736   set self, 0x80, 0x60, 1/alive
     737   set self, 0x80, 0x61, 1/alive
     738   flush self
     739 }
     740
     741 fn clear-environment _self: (addr environment) {
     742   var self/esi: (addr environment) <- copy _self
     743   var tick/eax: (addr int) <- get self, tick
     744   copy-to *tick, 0
     745   # don't touch zoom or play settings
     746   var data-ah/eax: (addr handle array handle array cell) <- get self, data
     747   var data/eax: (addr array handle array cell) <- lookup *data-ah
     748   var y/ecx: int <- copy 0
     749   {
     750     compare y, 0xc0
     751     break-if->=
     752     var row-ah/eax: (addr handle array cell) <- index data, y
     753     var row/eax: (addr array cell) <- lookup *row-ah
     754     var x/edx: int <- copy 0
     755     {
     756       compare x, 0x100
     757       break-if->=
     758       var dest/eax: (addr cell) <- index row, x
     759       clear-object dest
     760       x <- increment
     761       loop
     762     }
     763     y <- increment
     764     loop
     765   }
     766   set self, 0x80, 0x5f, 1/alive
     767   set self, 0x81, 0x5f, 1/alive
     768   set self, 0x7f, 0x60, 1/alive
     769   set self, 0x80, 0x60, 1/alive
     770   set self, 0x80, 0x61, 1/alive
     771   flush self
     772 }
     773
     774 fn set _self: (addr environment), _x: int, _y: int, _val: boolean {
     775   var self/esi: (addr environment) <- copy _self
     776   var data-ah/eax: (addr handle array handle array cell) <- get self, data
     777   var data/eax: (addr array handle array cell) <- lookup *data-ah
     778   var y/ecx: int <- copy _y
     779   var row-ah/eax: (addr handle array cell) <- index data, y
     780   var row/eax: (addr array cell) <- lookup *row-ah
     781   var x/ecx: int <- copy _x
     782   var cell/eax: (addr cell) <- index row, x
     783   var dest/eax: (addr boolean) <- get cell, next
     784   var val/ecx: boolean <- copy _val
     785   copy-to *dest, val
     786 }
     787
     788 fn state _self: (addr environment), _x: int, _y: int -> _/eax: boolean {
     789   var self/esi: (addr environment) <- copy _self
     790   var x/ecx: int <- copy _x
     791   var y/edx: int <- copy _y
     792   # clip at the edge
     793   compare x, 0
     794   {
     795     break-if->=
     796     return 0/false
     797   }
     798   compare y, 0
     799   {
     800     break-if->=
     801     return 0/false
     802   }
     803   compare x, 0x100/width
     804   {
     805     break-if-<
     806     return 0/false
     807   }
     808   compare y, 0xc0/height
     809   {
     810     break-if-<
     811     return 0/false
     812   }
     813   var data-ah/eax: (addr handle array handle array cell) <- get self, data
     814   var data/eax: (addr array handle array cell) <- lookup *data-ah
     815   var row-ah/eax: (addr handle array cell) <- index data, y
     816   var row/eax: (addr array cell) <- lookup *row-ah
     817   var cell/eax: (addr cell) <- index row, x
     818   var src/eax: (addr boolean) <- get cell, curr
     819   return *src
     820 }
     821
     822 fn state-color _self: (addr environment), x: int, y: int -> _/eax: int {
     823   var self/esi: (addr environment) <- copy _self
     824   var color/ecx: int <- copy 0x1a/dead
     825   {
     826     var state/eax: boolean <- state self, x, y
     827     compare state, 0/dead
     828     break-if-=
     829     color <- copy 0xf/alive
     830   }
     831   return color
     832 }
     833
     834 fn flush  _self: (addr environment) {
     835   var self/esi: (addr environment) <- copy _self
     836   var data-ah/eax: (addr handle array handle array cell) <- get self, data
     837   var _data/eax: (addr array handle array cell) <- lookup *data-ah
     838   var data/esi: (addr array handle array cell) <- copy _data
     839   var y/ecx: int <- copy 0
     840   {
     841     compare y, 0xc0/height
     842     break-if->=
     843     var row-ah/eax: (addr handle array cell) <- index data, y
     844     var _row/eax: (addr array cell) <- lookup *row-ah
     845     var row/ebx: (addr array cell) <- copy _row
     846     var x/edx: int <- copy 0
     847     {
     848       compare x, 0x100/width
     849       break-if->=
     850       var cell-a/eax: (addr cell) <- index row, x
     851       var curr-a/edi: (addr boolean) <- get cell-a, curr
     852       var next-a/esi: (addr boolean) <- get cell-a, next
     853       var val/eax: boolean <- copy *next-a
     854       copy-to *curr-a, val
     855       copy-to *next-a, 0/dead
     856       x <- increment
     857       loop
     858     }
     859     y <- increment
     860     loop
     861   }
     862 }
     863
     864 fn render4 screen: (addr screen), _self: (addr environment) {
     865   var self/esi: (addr environment) <- copy _self
     866   var y/ecx: int <- copy 0
     867   {
     868     compare y, 0xc0/height
     869     break-if->=
     870     var x/edx: int <- copy 0
     871     {
     872       compare x, 0x100/width
     873       break-if->=
     874       var state/eax: boolean <- state self, x, y
     875       compare state, 0/false
     876       {
     877         break-if-=
     878         render4-cell screen, x, y, 0xf/alive
     879       }
     880       compare state, 0/false
     881       {
     882         break-if-!=
     883         render4-cell screen, x, y, 0x1a/dead
     884       }
     885       x <- increment
     886       loop
     887     }
     888     y <- increment
     889     loop
     890   }
     891 }
     892
     893 fn render4-cell screen: (addr screen), x: int, y: int, color: int {
     894   var xmin/eax: int <- copy x
     895   xmin <- shift-left 2
     896   var xmax/ecx: int <- copy xmin
     897   xmax <- add 4
     898   var ymin/edx: int <- copy y
     899   ymin <- shift-left 2
     900   var ymax/ebx: int <- copy ymin
     901   ymax <- add 4
     902   draw-rect screen, xmin ymin, xmax ymax, color
     903 }
     904
     905 fn step4 _self: (addr environment) {
     906   var self/esi: (addr environment) <- copy _self
     907   var y/ecx: int <- copy 0
     908   {
     909     compare y, 0xc0/height
     910     break-if->=
     911     var x/edx: int <- copy 0
     912     {
     913       compare x, 0x100/width
     914       break-if->=
     915       var n/eax: int <- num-live-neighbors self, x, y
     916       # if neighbors < 2, die of loneliness
     917       {
     918         compare n, 2
     919         break-if->=
     920         set self, x, y, 0/dead
     921       }
     922       # if neighbors > 3, die of overcrowding
     923       {
     924         compare n, 3
     925         break-if-<=
     926         set self, x, y, 0/dead
     927       }
     928       # if neighbors = 2, preserve state
     929       {
     930         compare n, 2
     931         break-if-!=
     932         var old-state/eax: boolean <- state self, x, y
     933         set self, x, y, old-state
     934       }
     935       # if neighbors = 3, cell quickens to life
     936       {
     937         compare n, 3
     938         break-if-!=
     939         set self, x, y, 1/live
     940       }
     941       x <- increment
     942       loop
     943     }
     944     y <- increment
     945     loop
     946   }
     947   flush self
     948 }
     949
     950 fn num-live-neighbors _self: (addr environment), x: int, y: int -> _/eax: int {
     951   var self/esi: (addr environment) <- copy _self
     952   var result/edi: int <- copy 0
     953   # row above: zig
     954   decrement y
     955   decrement x
     956   var s/eax: boolean <- state self, x, y
     957   {
     958     compare s, 0/false
     959     break-if-=
     960     result <- increment
     961   }
     962   increment x
     963   s <- state self, x, y
     964   {
     965     compare s, 0/false
     966     break-if-=
     967     result <- increment
     968   }
     969   increment x
     970   s <- state self, x, y
     971   {
     972     compare s, 0/false
     973     break-if-=
     974     result <- increment
     975   }
     976   # curr row: zag
     977   increment y
     978   s <- state self, x, y
     979   {
     980     compare s, 0/false
     981     break-if-=
     982     result <- increment
     983   }
     984   subtract-from x, 2
     985   s <- state self, x, y
     986   {
     987     compare s, 0/false
     988     break-if-=
     989     result <- increment
     990   }
     991   # row below: zig
     992   increment y
     993   s <- state self, x, y
     994   {
     995     compare s, 0/false
     996     break-if-=
     997     result <- increment
     998   }
     999   increment x
    1000   s <- state self, x, y
    1001   {
    1002     compare s, 0/false
    1003     break-if-=
    1004     result <- increment
    1005   }
    1006   increment x
    1007   s <- state self, x, y
    1008   {
    1009     compare s, 0/false
    1010     break-if-=
    1011     result <- increment
    1012   }
    1013   return result
    1014 }
    1015
    1016 fn linger _self: (addr environment) {
    1017   var self/esi: (addr environment) <- copy _self
    1018   var i/ecx: int <- copy 0
    1019   {
    1020     compare i, 0x10000000  # Kartik's Linux with -enable-kvm
    1021 #?     compare i, 0x8000000  # Kartik's Mac with -accel tcg
    1022     break-if->=
    1023     i <- increment
    1024     loop
    1025   }
    1026 }