RosettaCodeData/Task/Guess-the-number/WebAssembly/guess-the-number.wasm
2023-07-01 13:44:08 -04:00

128 lines
3.5 KiB
Text

(module
(import "wasi_unstable" "fd_read"
(func $fd_read (param i32 i32 i32 i32) (result i32)))
(import "wasi_unstable" "fd_write"
(func $fd_write (param i32 i32 i32 i32) (result i32)))
(import "wasi_unstable" "random_get"
(func $random_get (param i32 i32) (result i32)))
(memory 1) (export "memory" (memory 0))
;; memory usage:
;; 0-7: temp IO Vector used with WASI functions
;; 8-24: temp buffer used for reading numbers
;; 100-: string data
;; string constants
(data (i32.const 100) "Guess a number between 1 and 10.\n")
(data (i32.const 200) "Well guessed!\n")
;; function to print a null-terminated string at the given address
;; (assumes use of an IOVector at address 0)
(func $print_cstr (param $strAddr i32)
(local $charPos i32)
;; store the data address into our IO vector (address 0)
i32.const 0 local.get $strAddr i32.store
;; find the null terminator at the end of the string
local.get $strAddr local.set $charPos
block $loop_break
loop $LOOP
;; get the character at charPos
local.get $charPos i32.load
;; if it is equal to zero, break out of the loop
i32.eqz if br $loop_break end
;; otherwise, increment and loop
local.get $charPos i32.const 1 i32.add local.set $charPos
br $LOOP
end
end
;; from that, compute the length of the string for our IOVector
i32.const 4 ;; (address of string length in the IOVector)
local.get $charPos local.get $strAddr i32.sub
i32.store
;; now call $fd_write to actually write to stdout
i32.const 1 ;; 1 for stdout
i32.const 0 i32.const 1 ;; 1 IOVector at address 0
i32.const 0 ;; where to stuff the number of bytes written
call $fd_write
drop ;; (drop the result value)
)
;; function to read a number
;; (assumes use of an IOVector at address 0,
;; and 16-character buffer at address 8)
(func $input_i32 (result i32)
(local $ptr i32)
(local $n i32)
(local $result i32)
;; prepare our IOVector to point to the buffer
i32.const 0 i32.const 8 i32.store ;; (address of buffer)
i32.const 4 i32.const 16 i32.store ;; (size of buffer)
i32.const 0 ;; 0 for stdin
i32.const 0 i32.const 1 ;; 1 IOVector at address 0
i32.const 4 ;; where to stuff the number of bytes read
call $fd_read drop
;; Convert that to a number!
;; loop over characters in the string until we hit something < '0'.
i32.const 8 local.set $ptr
block $LOOP_BREAK
loop $LOOP
;; get value of current digit
;; (we assume all positive integers for this task)
local.get $ptr i32.load8_u
i32.const 48 i32.sub ;; (subtract 48, ASCII value of '0')
local.tee $n
;; bail out if < 0
i32.const 0 i32.lt_s br_if $LOOP_BREAK
;; multiply current number by 10, and add new number
local.get $result i32.const 10 i32.mul
local.get $n i32.add
local.set $result
;; increment and loop
local.get $ptr i32.const 1 i32.add local.set $ptr
br $LOOP
end
end
local.get $result
)
;; function to get a random i32
;; (assumes use of temporary space at address 0)
(func $random_i32 (result i32)
i32.const 0 i32.const 4 call $random_get drop
i32.const 0 i32.load
)
(func $main (export "_start")
(local $trueNumber i32)
;; get a random integer, then take that (unsigned) mod 10
call $random_i32 i32.const 10 i32.rem_u
local.set $trueNumber
loop $LOOP
;; print prompt
i32.const 100 call $print_cstr
;; input a guess
call $input_i32
;; if correct, print message and we're done
local.get $trueNumber i32.eq if
i32.const 200 call $print_cstr
return
end
br $LOOP
end
)
)