You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
338 lines
6.0 KiB
Plaintext
338 lines
6.0 KiB
Plaintext
1 year ago
|
(module
|
||
|
(memory (export "shared_memory") 1)
|
||
|
|
||
|
(global $boardWidth (mut i32) (i32.const 0))
|
||
|
(global $boardHeight (mut i32) (i32.const 0))
|
||
|
(global $boardBufferLength (mut i32) (i32.const 0))
|
||
|
(global $buffer0ptr (mut i32) (i32.const -1))
|
||
|
(global $buffer1ptr (mut i32) (i32.const -1))
|
||
|
(global $currentBuffer (mut i32) (i32.const -1))
|
||
|
|
||
|
(func (export "initializeBoard") (param $width i32) (param $height i32)
|
||
|
;; Store width and height for later
|
||
|
(global.set $boardWidth (local.get $width))
|
||
|
(global.set $boardHeight (local.get $height))
|
||
|
|
||
|
;; Compute total cells per board
|
||
|
local.get $width
|
||
|
local.get $height
|
||
|
i32.mul
|
||
|
global.set $boardBufferLength
|
||
|
|
||
|
;; Request enough memory for both boards
|
||
|
global.get $boardBufferLength
|
||
|
i32.const 2
|
||
|
i32.mul
|
||
|
call $growMemoryForBoards
|
||
|
|
||
|
;; Set pointer locations for our two boards
|
||
|
(global.set $buffer0ptr (i32.const 0))
|
||
|
(global.set $buffer1ptr (global.get $boardBufferLength))
|
||
|
|
||
|
;; Set current board
|
||
|
(global.set $currentBuffer (i32.const 0))
|
||
|
)
|
||
|
|
||
|
(func (export "getPagesUsed") (result i32)
|
||
|
memory.size
|
||
|
)
|
||
|
|
||
|
(func $growMemoryForBoards (param $totalBytes i32)
|
||
|
(local $targetPages i32)
|
||
|
|
||
|
;; figure out target page size
|
||
|
local.get $totalBytes
|
||
|
i32.const 1
|
||
|
i32.sub
|
||
|
i32.const 65536 ;; size of a page
|
||
|
i32.div_u
|
||
|
i32.const 1
|
||
|
i32.add
|
||
|
|
||
|
;; get difference
|
||
|
memory.size
|
||
|
i32.sub
|
||
|
|
||
|
;; grow
|
||
|
memory.grow
|
||
|
drop ;; ignore result, we're gonna crash anyways
|
||
|
;; perhaps we should have a way to report errors back to JS next time
|
||
|
)
|
||
|
|
||
|
(func $getBoardPtr (result i32)
|
||
|
global.get $currentBuffer
|
||
|
i32.eqz
|
||
|
if (result i32)
|
||
|
global.get $buffer0ptr
|
||
|
else
|
||
|
global.get $buffer1ptr
|
||
|
end
|
||
|
)
|
||
|
|
||
|
(func $swapBoards
|
||
|
global.get $currentBuffer
|
||
|
i32.eqz
|
||
|
if (result i32)
|
||
|
i32.const 1
|
||
|
else
|
||
|
i32.const 0
|
||
|
end
|
||
|
global.set $currentBuffer
|
||
|
)
|
||
|
|
||
|
(func $positionInRange (param $position i32) (param $min i32) (param $max i32) (result i32)
|
||
|
local.get $position
|
||
|
local.get $min
|
||
|
i32.lt_s
|
||
|
|
||
|
if
|
||
|
i32.const 0
|
||
|
return
|
||
|
end
|
||
|
|
||
|
local.get $position
|
||
|
local.get $max
|
||
|
i32.ge_s
|
||
|
|
||
|
if
|
||
|
i32.const 0
|
||
|
return
|
||
|
end
|
||
|
|
||
|
i32.const 1
|
||
|
return
|
||
|
)
|
||
|
|
||
|
(func $getIndexForPosition (param $row i32) (param $column i32) (result i32)
|
||
|
local.get $row
|
||
|
i32.const 0
|
||
|
global.get $boardHeight
|
||
|
call $positionInRange
|
||
|
|
||
|
local.get $column
|
||
|
i32.const 0
|
||
|
global.get $boardWidth
|
||
|
call $positionInRange
|
||
|
|
||
|
i32.and
|
||
|
i32.eqz
|
||
|
|
||
|
if
|
||
|
i32.const -1
|
||
|
return
|
||
|
end
|
||
|
|
||
|
global.get $boardWidth
|
||
|
local.get $row
|
||
|
i32.mul
|
||
|
local.get $column
|
||
|
i32.add
|
||
|
)
|
||
|
|
||
|
(func $getValueAtPosition (export "getValueAtPosition") (param $row i32) (param $column i32) (result i32)
|
||
|
(local $position i32)
|
||
|
local.get $row
|
||
|
local.get $column
|
||
|
call $getIndexForPosition
|
||
|
|
||
|
local.tee $position
|
||
|
i32.const 0
|
||
|
i32.lt_s
|
||
|
|
||
|
if
|
||
|
i32.const 0
|
||
|
return
|
||
|
end
|
||
|
|
||
|
local.get $position
|
||
|
|
||
|
call $getBoardPtr
|
||
|
i32.add
|
||
|
i32.load8_u
|
||
|
)
|
||
|
|
||
|
(func $setValueAtPosition (export "setValueAtPosition") (param $row i32) (param $column i32) (param $value i32)
|
||
|
(local $position i32)
|
||
|
local.get $row
|
||
|
local.get $column
|
||
|
call $getIndexForPosition
|
||
|
|
||
|
local.tee $position
|
||
|
i32.const 0
|
||
|
i32.lt_s
|
||
|
|
||
|
if
|
||
|
return
|
||
|
end
|
||
|
|
||
|
local.get $position
|
||
|
|
||
|
call $getBoardPtr
|
||
|
i32.add
|
||
|
local.get $value
|
||
|
i32.store8
|
||
|
)
|
||
|
|
||
|
(func $getNewValueAtPosition (param $row i32) (param $column i32) (result i32)
|
||
|
(local $count i32)
|
||
|
|
||
|
local.get $row
|
||
|
i32.const 1
|
||
|
i32.sub
|
||
|
local.get $column
|
||
|
call $getValueAtPosition
|
||
|
|
||
|
local.get $row
|
||
|
i32.const 1
|
||
|
i32.add
|
||
|
local.get $column
|
||
|
call $getValueAtPosition
|
||
|
|
||
|
local.get $row
|
||
|
local.get $column
|
||
|
i32.const 1
|
||
|
i32.sub
|
||
|
call $getValueAtPosition
|
||
|
|
||
|
local.get $row
|
||
|
local.get $column
|
||
|
i32.const 1
|
||
|
i32.add
|
||
|
call $getValueAtPosition
|
||
|
|
||
|
local.get $row
|
||
|
i32.const 1
|
||
|
i32.sub
|
||
|
local.get $column
|
||
|
i32.const 1
|
||
|
i32.sub
|
||
|
call $getValueAtPosition
|
||
|
|
||
|
local.get $row
|
||
|
i32.const 1
|
||
|
i32.add
|
||
|
local.get $column
|
||
|
i32.const 1
|
||
|
i32.sub
|
||
|
call $getValueAtPosition
|
||
|
|
||
|
local.get $row
|
||
|
i32.const 1
|
||
|
i32.sub
|
||
|
local.get $column
|
||
|
i32.const 1
|
||
|
i32.add
|
||
|
call $getValueAtPosition
|
||
|
|
||
|
local.get $row
|
||
|
i32.const 1
|
||
|
i32.add
|
||
|
local.get $column
|
||
|
i32.const 1
|
||
|
i32.add
|
||
|
call $getValueAtPosition
|
||
|
|
||
|
i32.add
|
||
|
i32.add
|
||
|
i32.add
|
||
|
i32.add
|
||
|
i32.add
|
||
|
i32.add
|
||
|
i32.add
|
||
|
|
||
|
;; Exactly 3 neighbors
|
||
|
local.tee $count
|
||
|
i32.const 3
|
||
|
i32.eq
|
||
|
|
||
|
if
|
||
|
;; becomes or stays alive
|
||
|
i32.const 1
|
||
|
return
|
||
|
end
|
||
|
|
||
|
;; If currently dead
|
||
|
local.get $row
|
||
|
local.get $column
|
||
|
call $getValueAtPosition
|
||
|
i32.eqz
|
||
|
if
|
||
|
;; Stay dead
|
||
|
i32.const 0
|
||
|
return
|
||
|
end
|
||
|
|
||
|
;; 2 neighbors
|
||
|
local.get $count
|
||
|
i32.const 2
|
||
|
i32.eq
|
||
|
if
|
||
|
i32.const 1
|
||
|
return
|
||
|
end
|
||
|
|
||
|
i32.const 0
|
||
|
return
|
||
|
)
|
||
|
|
||
|
(func $tick (export "tick")
|
||
|
(local $row i32)
|
||
|
(local $column i32)
|
||
|
(local $value i32)
|
||
|
|
||
|
i32.const 0
|
||
|
local.set $row
|
||
|
|
||
|
loop $rows
|
||
|
|
||
|
;; start at the beginning of a row
|
||
|
i32.const 0
|
||
|
local.set $column
|
||
|
|
||
|
;; for every column in the row
|
||
|
loop $columns
|
||
|
|
||
|
;; compute new value
|
||
|
local.get $row
|
||
|
local.get $column
|
||
|
call $getNewValueAtPosition
|
||
|
local.set $value
|
||
|
|
||
|
;; place in next board
|
||
|
call $swapBoards
|
||
|
local.get $row
|
||
|
local.get $column
|
||
|
local.get $value
|
||
|
call $setValueAtPosition
|
||
|
call $swapBoards
|
||
|
|
||
|
;; increment column
|
||
|
local.get $column
|
||
|
i32.const 1
|
||
|
i32.add
|
||
|
local.tee $column
|
||
|
|
||
|
;; loop back if less than width
|
||
|
global.get $boardWidth
|
||
|
i32.lt_s
|
||
|
br_if $columns
|
||
|
end
|
||
|
|
||
|
;;increment row
|
||
|
local.get $row
|
||
|
i32.const 1
|
||
|
i32.add
|
||
|
local.tee $row
|
||
|
|
||
|
;; loop back if less than height
|
||
|
global.get $boardHeight
|
||
|
i32.lt_s
|
||
|
br_if $rows
|
||
|
end
|
||
|
|
||
|
;; swap to the new board
|
||
|
call $swapBoards
|
||
|
)
|
||
|
)
|
||
|
|