Open Source Adventures: Episode 25: Imba 2 Game of Life
Tomasz Wegrzanowski
Posted on March 25, 2022
I want to port a few more Imba 1 apps to Imba 2.
This one is very simple, just another Game of Life program. It's fairly straightforward, but we'll need to adapt it a bit, as Imba 1 version used components inheriting from svg:g
and Imba 2 can't do this, as web components don't support that yet.
Here's the original source code, and here you can see the app in action.
Imba 1 app.imba
let def countNeighbours(cells, x, y)
let count = 0
for i, cell of cells
if !cell:state
continue
let dx = Math.abs(cell:x - x)
let dy = Math.abs(cell:y - y)
if Math.max(dx, dy) == 1
count += 1
return count
let def runStep(cells)
let nextCells = []
for i, cell of cells
let n = countNeighbours(cells, cell:x, cell:y)
let nextState = (n == 3 || (cell:state && n == 2))
nextCells.push({x: cell:x, y: cell:y, state: nextState})
return nextCells
tag CellTag < svg:g
def onclick
data:state = !data:state
trigger("pause")
def render
let visualStartX = 20 * data:x + 1
let visualStartY = 20 * data:y + 1
<self>
<svg:rect .alive=(data:state) .dead=(!data:state) x=visualStartX y=visualStartY height=18 width=18>
tag App
def setup
let sizex = 30
let sizey = 30
@cells = []
for x in [0..sizex]
for y in [0..sizey]
@cells.push({ x: x, y: y, state: Math.random() < 0.2 })
def step
@cells = runStep(@cells)
def mount
setInterval(&,100) do
if @playing
step
Imba.commit
def play
@playing = true
def pause
@playing = false
def onpause
pause
def render
<self>
<header>
"Game of Life"
<svg:svg>
for cell in @cells
<CellTag[cell]>
<div.buttons>
if @playing
<button :click.pause>
"Pause"
else
<button :click.step>
"Step"
<button :click.play>
"Play"
Imba.mount <App>
Imba 1 app.scss
@import 'normalize-scss';
@include normalize();
.App {
header {
font-size: 64px;
text-align: center;
}
svg {
height: 600px;
width: 600px;
background-color: #aaa;
margin: auto;
display: block;
}
.dead {
fill: #844;
}
.alive {
fill: #3f3;
}
.buttons {
text-align: center;
}
button {
margin: 0.5em;
}
}
Imba 2 app.imba
def countNeighbours(cells, x, y)
let count = 0
for cell of cells
if !cell.state
continue
let dx = Math.abs(cell.x - x)
let dy = Math.abs(cell.y - y)
if Math.max(dx, dy) == 1
count += 1
count
def runStep(cells)
let nextCells = []
for cell of cells
let n = countNeighbours(cells, cell.x, cell.y)
let nextState = (n == 3 || (cell.state && n == 2))
nextCells.push({x: cell.x, y: cell.y, state: nextState})
nextCells
tag cell
prop data
def onclick
data.state = !data.state
emit("pause")
def render
let visualStartX = 20 * data.x + 1
let visualStartY = 20 * data.y + 1
<self[left:{visualStartX}px top:{visualStartY}px] .alive=(data.state) .dead=(!data.state) @click.onclick>
css
position: absolute
width: 18px
height: 18px
&.dead
background-color: #864
&.alive
background-color: #3f3
tag app
prop cells
prop playing = true
def setup
let sizex = 30
let sizey = 30
cells = []
for x in [0 ... sizex]
for y in [0 ... sizey]
cells.push({ x: x, y: y, state: Math.random() < 0.2 })
def step
cells = runStep(cells)
def mount
imba.setInterval(&,100) do
if playing
step()
def play
playing = true
def pause
playing = false
def render
<self>
<header>
"Game of Life"
<div.board>
for cell in cells
<cell data=cell @pause.pause>
<div.buttons>
if playing
<button @click.pause>
"Pause"
else
<button @click.step>
"Step"
<button @click.play>
"Play"
css
header
font-size: 64px
text-align: center
.board
position: relative
height: 600px
width: 600px
background-color: #aaa
margin: auto
.buttons
text-align: center
button
margin: 0.5em
imba.mount <app>
The main issue here is that we can't use SVG directly. We could make a ton of tiny <svg>
s, each with one <rect>
, but at that point we might as well use <div>s
for components, and position: absolute
them.
Some minor things:
- event model changed, and it doesn't look like we can simply define
onX
, we need to bind every such event manually -
for
syntax changed from Imba 1
Source code
Source code is in imba2-game-of-life repository.
You can also see the live version here.
Coming next
While we didn't do anything too fancy, I think it's a good time to stop. In the next episode I'll give some thoughts about Imba 2.
Posted on March 25, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.