
gittech. site
for different kinds of informations and explorations.
Tiny Challenges for Learning WebAssembly
WebAssembly Wizardry
Tiny programming challenges designed for learning about WebAssembly by writing it by hand.
Each challenge has a .wat
file where you'll need to implement a WebAssembly module to pass the tests.
Run node tests.mjs
to run the tests and to see the recommended order for solving the challenges.
The challenges have descriptions within their .wat
files, but it some cases it will also be useful to look inside tests.mjs
to better understand the different test cases.
Remove the ;; SOLVE
comment when you're ready to test your solution.
If you get stuck or want to compare notes check out my solutions
branch.
These challenges assume you have a programming background and are comfortable with some low-level concepts such as binary representations, bitwise operations, memory and pointers.
Dependencies
To run the tests and compile .wat
to .wasm
, you'll need the following dependencies.
Resources
The challenges aren't designed to teach you WAT syntax or WebAssembly instructions directly, so you'll probably need to do some reading alongside.
Whilst not technically a reference, I found the WebAssembly core test suite incredibly helpful for some exhaustive learning about the various instructions. The files are .wast
and they include some testing directives, but otherwise they are all valid .wat
.
Debugging
Every challenge can import functions for logging debug values at runtime.
(module
;; Add any of the following imports to your .wat module
(import "debug" "i32" (func $debug_i32 (param i32)))
(import "debug" "i64" (func $debug_i64 (param i64)))
(import "debug" "f32" (func $debug_f32 (param f32)))
(import "debug" "f64" (func $debug_f64 (param f64)))
(import "debug" "bool" (func $debug_bool (param i32)))
(import "debug" "char" (func $debug_char (param i32)))
(import "debug" "byte" (func $debug_byte (param i32)))
(import "debug" "bits" (func $debug_bits (param i32)))
;; ...
;; Then call it with the appropriate value type in your program.
(call $debug_f64 (f64.const 123.456))
)
Poker Notes
The poker exercises require you to read values from five cards, which are stored in memory as pairs of u8
values. The first is the rank value and the second is the suit value.
Decimal Value | Rank Value |
---|---|
1 |
A |
2 |
2 |
3 |
3 |
... | ... |
10 |
10 |
11 |
J |
12 |
Q |
13 |
K |
Decimal Value | Suit Value |
---|---|
0 |
♠ Spades |
1 |
♣ Clubs |
2 |
♥ Hearts |
3 |
♦ Diamonds |
So the hand A♠ 2♣️ 3♥ 4♦ 5♠️
would be stored in memory as:
A | ♠ | 2 | ♣️ | 3 | ♥ | 4 | ♦ | 5 | ♠ ️ |
---|---|---|---|---|---|---|---|---|---|
0x1 |
0x0 |
0x2 |
0x1 |
0x3 |
0x2 |
0x4 |
0x3 |
0x5 |
0x0 |
String Notes
The string challenges all work with null-terminated ASCII strings for simplicity, unless stated explicitly otherwise.
Compared to UTF-8 and other multi-byte encodings, ASCII is generally easier to work with, because every single character can be represented with a single byte in memory.
For example, the string "Hello, world"
would be stored in memory as:
H |
e |
l |
l |
o |
, |
|
w |
o |
r |
l |
d |
END |
---|---|---|---|---|---|---|---|---|---|---|---|---|
0x48 |
0x65 |
0x6C |
0x6C |
0x6F |
0x2C |
0x20 |
0x77 |
0x6F |
0x72 |
0x6C |
0x64 |
0x00 |
The strings are null-terminated, which means they always end with a NUL
byte (0x00
).