WebAssembly With Zig, Pt. II
Tags: zig, plt, webassembly, javascript
Published: 2022-11-30 18:54:54

Hello everyone, and welcome back to a longer-form series I am (attempting) to write. It has been a few months, but I am here again putting together the next iteration of this series.

This will be a very long, but hopefully reasonably fun dive into more Zig and WebAssembly and seeing what we can do this time around. Grab a drink or snack and let's start digging in.

## What We Know So Far

[From the last article](https://dev.to/sleibrock/webassembly-with-zig-part-1-4onm), I covered the basics of what WebAssembly (or WASM) can do for you. In short, it's a specialized engine inside a browser that we can access by feeding a stream of bytes, and the browser interprets packets of data into instructions to create virtual machine you can interact with. The advantages are pretty clear; WASM is fast, performant, and easy to target for compilers. If you can use WASM, you should try it.

Implementing said things, however, can be tricky, and the community is kind of spread all over the place. Rust is popular, but involves a lot of crates and boilerplate code being strapped on. C/C++ is an easy way of targeting WASM using [Emscripten](https://emscripten.org/), and I'm sure it works well, but I feel it fits in the same place as Rust where a lot needs to be strapped on to bring you up to production speed.

The [Zig](https://ziglang.org/) approach is what I am mostly interested in, as the Zig compiler includes shims for targeting WebAssembly. Since Zig can be used as a compiler for C/C++, this means you could skip the Emscripten part entirely and incorporate a `build.zig` file into your C/C++ project, allowing you to mix C/C++ libraries into a Zig project targeting a WebAssembly backend fairly easily.

I have a very large interest in video game entertainment as well as game development. Games make people happy, games are fun to share with friends, and overall, games are a great way of pushing the envelope for computer science in many categories dealing with visuals, audio, computational geometry, artificial intelligence, and so much more. My goal as such is to get somewhere close to a game that we could perhaps "play" it.

## Where We Last Were

We've seen how it's possible to load a WASM bytefile into a JavaScript-powered page. However, in the time since my last article, I have been working on a repository called `zigtoys` where I deploy my tests and upload the WASM files. You can download this and try out some examples for yourself, but for the most part I have two demos online you can see for yourself right now.

* [life.zig](https://github.com/sleibrock/zigtoys/blob/main/toys/life/life.zig), a small Conway's Game of Life simulator
* [mandelbrot.zig](https://github.com/sleibrock/zigtoys/blob/main/toys/mandelbrot/mandelbrot.zig), a Mandelbrot fractal generator

Mandelbrot is a little simpler than Conway's, because the Game of Life simulator does a lot of grid-based checks and makes use of a statically-defined "world". This idea of a game world is what we're going to need to focus on for a bit to start working on a game.

In both of these apps' folders we have a JS file to begin the WASM loading process and bind function names to Zig functions. This way we can use Zig from inside a JavaScript program, offloading difficult and long computations to the WASM engine instead of relying on the JavaScript engine.

However, we haven't gone backwards much, have we? I haven't really touched upon that much, because well... For better or worse, there are some parts I'm still not sure about on that front. JavaScript functions typically use things like `i32` or dynamically-allocated strings, so it's hard for me to gauge how that can be used within Zig. It's slightly easier for me to judge how things interact when I focus on Zig->JavaScript instead of JavaScript->Zig.

In `life.zig`, a game world is explicitly declared, and that is kept throughout the lifetime of the web page being opened. This makes it very simple; the game world is static, but mutable, so this is what we could use for a jumping-off point to start creating small games in Zig for WASM purposes.

The goal would be to create a game that can update it's internal state with a simple function, and expose the data to JavaScript so it can be presented easily. We might have to mix and match some JavaScript here and there, but for a trade-off of performance and using Zig on the web, I'll take it for now.

## Building a World

Building a world is one thing, it's no different than Conway's Game of Life. Declare an array and fill it with numbers representing the different entities you wish it to have. In Conway's case, it was simply some cells describing a square, and whether that square was dead or alive.

```zig
const State = struct{
    cells: [10*10]u8,
};

var WORLD = State{
    .cells = undefined, // auto-zero the array
};
```
Here I am creating a new struct called `State` which we will want to contain information about our world inside of. Then afterwards, I declare a new variable called `WORLD`, which we will update and occasionally ask for information about the world. I use uppercase here to denote it's importance, but you can use what you wish.

The problem is it doesn't seem like storing `u8`'s will be a great idea, and we should maybe use an `enum` type to describe the types of actors in our little world. Let's shift that over to an enum now and create a micro-world with which we can move around in.

```zig
const Entity = enum{
    Empty,
    Player,
    Wall,
};

const State = struct{
    cells: [W_SIZE]Entity,
};

var WORLD = State{
    .cells = undefined, // auto-zero the array
};
```

The new `Entity` enumeration describes what kind of actors our world will have. This is a pretty basic approach, but for a tiny sample game, this is fine for me. Type-aliasing this info away from a raw number is better and facilitates better naming conventions in code, ie. `currEntity == Entity.Player` versus `currEntity == 5`. Less confusion the better.

We're not quite out of the woods yet, as it might be a good idea to define constants at the top of our file here to indicate a maximum world size and obtain information for bounds checks.

```zig
const WIDTH: u32 = 10;
const HEIGHT: u32 = 10;
const W_SIZE: u32 = WIDTH * HEIGHT;

const Entity = enum{
    Empty,
    Player,
    Wall,
};

const State = struct{
    cells: [W_SIZE]Entity,
};

var WORLD = State{
    .cells = undefined,
};
```

Like in my Game of Life sample, it's a good idea to use some constants to customize your world so you can adjust upwards or downwards as you see fit, or design some crazy stuff. Maybe you can parameterize it later so your world is resizable on the fly instead of statically like this, but that might be a different feature for later.

We haven't defined *any* functions still, so compiling this would lead to the most bare-bones WASM file imaginable. We're going to start working on a function called `update()`, which updates the state of the world by mutating the data it contains. We still need some helper functions to help us communicate with the cells of the world itself, since it is a linear 1-dimensional array. It might be convenient for some calculations from a 2D space using some helper functions to do the math.

```zig
fn calc_pos(x: u8, y: u8) usize {
    return x + (y * HEIGHT);
}

export fn get_pos(x: u8, y: u8) Entity {
    var index = calc_pos(x, y);
    if (index < W_SIZE)
        return WORLD.cells[index];
    return .Empty;
}

export fn set_pos(x: u8, y: u8, v: Entity) bool {
    var index = calc_pos(x, y);
    if (index < W_SIZE) {
        WORLD.cells[index] = v;
        return true;
    }
    return false;
}
```

The `calc_pos(x,y)` function will help us to calculate an index from two Cartesian co-ordinates, while `get_pos(x,y)` and `set_pos(x,y,v)` are the general interface for changing the game. All the updates should be done through those two functions when it comes to changing the cells.

It might help if we have a thing in place to set the world to some initial state, so maybe let's define an `init()` function which will give us some default world we can toy around in.

```zig
export fn init() void {
    _ = set_pos(4, 4, Cell.Wall);
    _ = set_pos(4, 3, Cell.Wall);
    _ = set_pos(4, 5, Cell.Wall);
    _ = set_pos(3, 4, Cell.Wall);
    _ = set_pos(5, 4, Cell.Wall);
    return;
}
```

Granted, since I want `set_pos` to return a Boolean of whether or not it could place an entity on the grid, we don't really need it in our tiny example here, so I use the `_ = <expr>` syntax to discard the result and ignore whatever gets thrown back. Those fixed numbers work for a 10x10 grid, but since I'm not writing them with a variable in mind, it could fail if your grid was too small, or look strange on a board with odd dimensions.

## Displaying Our World

Next let's focus back on the JavaScript aspect, and go back and create a file that loads our WASM and binds our functions here and will actually start rendering our game world. We'll use a basic grid on a `<canvas>` element to portray our little game here.

First, let's look at how we originally loaded our WASM. This is done on a local HTTP server spun up with `python -m http.server`, which is frankly the fastest way I can think of to get something going for this. If you don't have Python, maybe try `nodejs` or a Docker HTTP server runtime of your choice.

```javascript
request = new XMLHttpRequest();
request.open('GET', 'game.wasm');
request.responseType = 'arraybuffer';
request.send();

request.onload = function() {
    var bytes = request.response;
    WebAssembly.instantiate(bytes, {
        env: {}
    }).then(result => {
        // store references to Zig functions
        get_pos = result.instance.export.get_pos;
        // repeat etc ...
    });
};
```

Curiously enough, I never really looked at what is *really* inside the `result.instance.exports` object we seem to get. Let's try now.

Build your Zig first into a WASM (I keep forgetting what this command is so I'm really doing this for myself).

```shell
$ zig build-lib game.zig -target wasm32-freestanding -dynamic -O ReleaseFast
```
This outputs a `game.wasm` file (assuming you also named your file `game.zig`). Then we load it in our browser by pointing our browser to `localhost:8000` (or wherever your local HTTP server is bound), and browsing to our web page, which we haven't made yet.

```html
<!doctype html>
<html>
  <head>
    <title>Game Demo</title>
  </head>
  <body>
    <h3>Game Demo</h3>
    <canvas id="game_canvas" width="100" height="100">
      Browser does not support HTML5 canvas element
    </canvas>
  </body>
  <script src="game.js"></script>
</html>
```

After that, let's load into our web page with the local HTTP server running, and wedge in a tiny `console.log` statement on the results object to see what we're working with. The output looks like this:

```
Object { memory: WebAssembly.Memory, get_pos: 0(), set_pos: 1(), init: 2(), update: 3() }
get_pos: function 0()
init: function 2()
memory: WebAssembly.Memory { buffer: ArrayBuffer }
set_pos: function 1()
update: function 3()
```

Interestingly enough, it seems like my way of manually binding variables to these functions may have been redundant as we have that mapping already created for us. Now we can reduce some cognitive load a bit by assigning this to a namespace we can recognize. Before the WASM loading, let's create an object with some properties filled out.

```javascript
var Game = {
    'init': null,
    'get_pos': null,
    'set_pos': null,
    'update': null,
    'loaded': false;
    'running': false,
};
```

If the WASM fails to load for some reason, we can use this as a means of declaring "empty" functions that will simply error out instead of leaving us with dead, undefined function errors. Maybe we can change this later to actually *be* functions that display better errors, but for right now I think this is okay.

Then all we do (during the WASM load phase) is bind this variable to the WASM export.

```javascript
Game = result.instance.exports;
```

This might pose risks as the memory binding is tied in as well. However, it seems like in the WASM loading process, an `ArrayBuffer` given to the memory is not shared and as such is completely locked down. This might not be full-proof, and I'll come back if there's something leaky about this.

Now to test it, we can call `get_pos()` and `set_pos()` on it.

```javascript
>>> Game.set_pos(4, 4, 2)
1 // indicator of it worked
>>> Game.get_pos(4, 4)
2 // the value we set!
```

This shows us that it's actually working and yields a Boolean indicative of whether it worked or not. Awesome stuff so far.

We need a way of displaying our game world, so let's try to do that quickly with a little canvas JS.

```javascript
var canvas = window.document.getElementById("game_canvas");
var ctx = canvas.getContext('2d');

var main = function() {
    console.log("Main function started");

    var loop = function() {
	ctx.fillStyle = "white"; // clear the canvas
	ctx.fillRect(0, 0, 100, 100);
	for(var x = 0; x < 10; x++) {
	    for(var y = 0; y < 10; y++) {
		var cell = Game.get_pos(x, y);
		if (cell == 1)
		    ctx.fillStyle = "red";
		else if (cell == 2)
		    ctx.fillStyle = "grey";
		else
		    ctx.fillStyle = "white";
		ctx.fillRect(x*10, y*10, (x*10)+10, (y*10)+10);
	    }
	}

        // loop to next frame
	if (Game.running)
	    window.requestAnimationFrame(loop);
    };
    loop();
};
```

This will render a small game world where walls are grey, empty space is white, and a mysterious player is red. However, our player is nowhere to be found, because we never defined how he would move just yet. That will come later. If everything is done correctly up to here, you will see a canvas with this showing.

![A game world with a small grey cross in the middle. I have a dark mode setting so the white game board stands out.](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xve2urpeequ2hmtz1lm0.png)

I am going to make a quick change to our WASM loader to change it from `.instantiate` to `.instantiateStreaming`, as mentioned by @rofrol in my last post (thanks!!). This makes use of an asynchronous promise via the `fetch()` function assuming your browser supports it, otherwise you will have to go back to the old `XMLHttpRequest` way. The WASM code will look like this now.

```javascript
window.document.body.onload = function() {
    var env = { env: {} };
    WebAssembly.instantiateStreaming(fetch("game.wasm"), env).then(result => {
        console.log("Loaded the WASM!");
        Game = result.instance.exports;
        Game.loaded = true;
        Game.init(); // initialize world
        main(); // begin
    });
};
```

With that, it's time we move onto the next section of how we actually interact with this as a player.

## Playing The Game

There isn't really a clear-cut objective here. We have a supposed Player that walks around this small grid of empty walls, with no real gameplay. Kind of sucks, right? Not much of a game.

We can gamify it with a few changes in mind.

1. make it so we can walk the player entity around
2. have a goal in mind, perhaps a destination
3. add a score, make it fun
4. randomization! or levels.

The first is to add controls, so we can move a player around. The second is adding a new entity called `Goal` where the player must step on it to win. The third is adding a tracker to the game state. The fourth is... Well, that's something else entirely I would say, and maybe a little complex a topic for right now.

The first goal in mind is to add the concept of a Player into the game. Naturally by having a cell entity be the `Player` is the first thing in our mind, but we need a little help tracking his position. Each time the player moves, his index in the array gets updated, so anytime you want to move the player, you have to find him again.

Naturally, you can add a variable into the world state, or maybe two, just to make calculations less annoying. The horizontal and vertical position can be stored, and this will help us to calculate his movements.

```zig
const State = struct{
    playerx: u8,
    playery: u8,
    cells: [W_SIZE]Entity,
};
```
We store `playerx` and `playery` as `u8` types for now, because our grid is quite literally a 10x10 grid. We cannot go smaller with Zig custom bit-types like `u4`, because the C translation needs C conformant types, and the lowest is one byte, or eight bits (`u8` in Zig).

Now, any time `update()` is called (which it isn't being called ever), we can update our world by adjusting the `playerx` and `playery` attributes reflecting our changes. So now we can map a value to reflect moving.

```zig
export fn update(dir: u8) void {
    if (dir == 0)
        WORLD.playery -= 1;
    if (dir == 1)
        WORLD.playery += 1;
    if (dir == 2)
        WORLD.playerx -= 1;
    if (dir == 3)
        WORLD.playerx += 1;
    return;
}
```
Okay that seems fine... Except wait, this is probably better reserved for an `enum` type so Zig can check it much easier (and safer). Let's move the direction into it's own `enum`.

```zig
const Direction = enum(u8) {
    Up,
    Down,
    Left,
    Right,
};

export fn update(dir: Direction) void {
    switch (dir) {
        .Up => { WORLD.playery -= 1; },
        .Down => { WORLD.playery += 1; },
        .Left => { WORLD.playerx -= 1; },
        .Right => { WORLD.playerx += 1; },
        else => {},
    }
    return;
}
```
This is also prone to fail since we're not doing bounds check, and this can lead to integer underflow/overflow or just plain going off the map entirely. We need to provide checks to assure we're still going to be on the map after an update.

```zig
export fn update(dir: Direction) void {
    if ((dir == .Up) and (WORLD.playery > 0))
        WORLD.playery -= 1;
    if ((dir == .Down) and (WORLD.playery < HEIGHT))
        WORLD.playery += 1;
    if ((dir == .Left) and (WORLD.playerx > 0))
        WORLD.playerx -= 1;
    if ((dir == .Right) and (WORLD.playerx < WIDTH))
        WORLD.playerx += 1;
    return;
}
```
We lose our `switch` case, but that happens when complex logic starts being required. This moves our player around, but doesn't actually change any of the cells, so nothing really happens other than two numbers being pushed around.

This also doesn't really do anything for us quite yet either, as it isn't contextually aware of our world, nor does it mutate the cells to reflect our new state. We should store new co-ordinates that represent our target cell that we want to move to, and apply logic based on what is in that cell. If the goal cell is invalid, we don't do anything and exit early.

```zig
/// Update our world by attempting to move the player somewhere
export fn update(dir: Direction) void {
    var goalx = WORLD.playerx;
    var goaly = WORLD.playery;
    if ((dir == .Up) and (goaly > 0))
        goaly -= 1;
    if ((dir == .Down) and (goaly < HEIGHT - 1))
        goaly += 1;
    if ((dir == .Left) and (goalx > 0))
        goalx -= 1;
    if ((dir == .Right) and (goalx < WIDTH - 1))
        goalx += 1;

    var goalpos = calc_pos(goalx, goaly);
    if (goalpos == calc_pos(WORLD.playerx, WORLD.playery))
        return;

    var dest_ent = WORLD.cells[goalpos];
    switch (dest_ent) {
        .Empty => {
            _ = set_pos(WORLD.playerx, WORLD.playery, .Empty);
            _ = set_pos(goalx, goaly, .Player);
        },
        else => {},
    }
    return;
}
```

This is a lot of ground to cover, but let's go through it slowly.

First, we need to calculate a "goal" position to move the player from. This is based on it's original co-ordinates in the world state, so we grab that. Then we apply checks based on the given `Direction` value we receive, and apply a range check if we're going to move outside of our world or not. Then we modify the goal co-ordinates if it's a valid move.

Next, we check if the goal position we want to move to is valid, and not the one we're currently standing on. If it's the one we're standing on, exit early, because there's no additional work to do.

Last, we do a `switch` over the `Entity` value that's in our goal index position. If it's an empty space, we move our player, and then we set an empty space where we previously were. To make it easier, I made an update to `set_pos()` to include moving the player if we're setting a player entity, this way there can only ever be one player in the world.

```zig
export fn set_pos(x: u8, y: u8, v: Entity) bool {
    var index = calc_pos(x, y);
    if (index < W_SIZE) {
        switch (v) {
            .Empty => { WORLD.cells[index] = .Empty; },
            .Player => {
                WORLD.playerx = x;
                WORLD.playery = y;
                WORLD.cells[index] = .Player;
            },
            .Wall => { WORLD.cells[index] = .Wall; },
        }
        return true;
    }
    return false;
}
```
We need to update the `init()` function to include an original player position.

```zig
export fn init() void {
    _ = set_pos(4, 4, Entity.Wall);
    _ = set_pos(4, 3, Entity.Wall);
    _ = set_pos(4, 5, Entity.Wall);
    _ = set_pos(3, 4, Entity.Wall);
    _ = set_pos(5, 4, Entity.Wall);

    // set the player
    _ = set_pos(0, 0, Entity.Player);
}
```

This works, and we can try it out by manually punching commands into the console.

```javascript
>>> Game.update(1) // moves player down
>>> Game.update(0) // moves player up
>>> Game.update(2) // moves player left
>>> Game.update(3) // moves player right
```

Here's what it should look like now since we already drew the player in the JS earlier.

![Our world with our player block in red](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xyd2z6bb1n4myq4wtyli.png)

If you move him around, you'll see we don't collide and move into grey wall blocks. Why? Because we checked the target cell, and we never wrote logic for when a wall is encountered. Therefore, if a wall is found, we just don't do anything.

## Binding the Controls

It would be *very* convenient if we could not use the JS console to move our player, and instead maybe use keyboard keys like the arrow keys, or WASD instead. This is something we'll have to patch on the JS side, so let's go back to that JS code and find a way.

Adding a key event to a web page involves adding a reactionary hook function to the DOM model. When keys are pressed down (or any other kind of user I/O event occurs), JavaScript can be executed if bound through an event "listener" function. Let's attempt to bind a listen to the canvas element itself.

```javascript
window.document.body.addEventListener('keydown', function(evt){
    console.log(evt);
});
```
This will first tell us what kind of events we're receiving (if any) for the `keydown` type of events. Using `console.log`, we can see what events we're getting exactly, so let's grab some sample output.

```
keydown { target: body, key: "a", charCode: 0, keyCode: 65 }
keydown { target: body, key: "d", charCode: 0, keyCode: 68 }
keydown { target: body, key: "f", charCode: 0, keyCode: 70 }
keydown { target: body, key: "ArrowUp", charCode: 0, keyCode: 38 }
```
It's pretty basic; we get an object file that shows the key name and the key raw code value. We can map any group of these using either string names or integer values, but for now I will go with string values since it's easier to read at a glance, instead of questioning what each keycode is.

```javascript
window.document.body.addEventListener('keydown', function(evt){
    if (!Game.loaded)
        return;
    if (evt.key == "w" || evt.key == "ArrowUp")
        Game.update(0);
    if (evt.key == "s" || evt.key == "ArrowDown")
        Game.update(1);
    if (evt.key == "a" || evt.key == "ArrowLeft")
        Game.update(2);
    if (evt.key == "d" || evt.key == "ArrowRight")
        Game.update(3);
});
```

First we check if the game even loaded (which I toggle to `true` when the WASM is initiated earlier), then we run through the different string names of all the keys. I want it to be WASD and arrow keys to move around so it's intuitively easy to understand. This unfortunately doesn't work on mobile devices, so that will be a whole different category of inputs we're not equipped for just yet.

...and it still doesn't work. Here's a JavaScript gotcha we didn't prepare for - the `Game.loaded` variable is completely undefined. Why? Look at this snippet of code.

```javascript
Game = result.instance.exports;
Game.loaded = true;
Game.running = true;
Game.init();
main(); // begin
```

Seems valid, but it isn't. The WASM object we get from `result.instance.exports` seems to be *completely* immutable, but JavaScript didn't throw an error for it. The re-assignment changes and even remove old variables we tried binding in our original `Game` object definition, so these no longer hold true or store data. Oops!

No matter, we'll use another object to store metadata which I'll just call `AppState` at the top level near our original `Game` object. That original `Game` object is still handy for error handling in the case the WASM file doesn't load at all.

```javascript
var Game = {
    'init': null,
    'get_pos': null,
    'set_pos': null,
    'update': null,
};

var AppState {
    'loaded': false,
    'running': true,
};
```

```javascript
window.document.body.addEventListener('keydown', function(evt){
    if (!AppState.loaded)
        return;
    if ((evt.key == "w") || (evt.key == "ArrowUp"))
        Game.update(0);
    if ((evt.key == "s") || (evt.key == "ArrowDown"))
        Game.update(1);
    if ((evt.key == "a") || (evt.key == "ArrowLeft"))
        Game.update(2);
    if ((evt.key == "d" || evt.key == "ArrowRight"))
         Game.update(3);
});

```

After switching all the things over, it is now working much better.

## Adding More Gameplay

This game is still really boring. I did mention we could add a goal to move to, but that would still be considerately boring. Maybe we can try to add a level of fun by adding a different type of goal.

This game shares resemblance to top-down 2D games like [The Legend of Zelda](https://en.wikipedia.org/wiki/The_Legend_of_Zelda_%28video_game%29), so it makes sense to me that perhaps we could include a bit of gameplay from those style of games.

![Maybe with enough time we could make something as cool as this game](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/le0kfmkqlm6sqjzhx8oj.png)

A re-occurring theme in these top-down style games is the ability to "move" something else in the world dynamically. For instance, a moving block to solve a puzzle. We can make it a bit like Klotski, where the block must hit a goal to win.

![Peak gaming from 1995, Klotski is the original premier gaming software to this day](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8vs9vhie35s5tg1m71gh.png)

First, we need new entities.

```zig
const Entity = enum(u8) {
    Empty,
    Player,
    Wall,
    Block,
    Goal,
};
```

Now we need new statements to render these new entities.

```javascript
var main = function() {
    console.log("Main function started");

    var loop = function() {
	// clear the background
	ctx.fillStyle = "white";
	ctx.fillRect(0, 0, 100, 100);
	for(var x = 0; x < 10; x++) {
	    for(var y = 0; y < 10; y++) {
		var cell = Game.get_pos(x, y);
		if (cell == 1)
		    ctx.fillStyle = "red";
		else if (cell == 2)
		    ctx.fillStyle = "grey";
		else if (cell == 3)
		    ctx.fillStyle = "blue"; // push block
		else if (cell == 4)
		    ctx.fillStyle = "green"; // goal
		else
		    ctx.fillStyle = "white";
		ctx.fillRect(x*10, y*10, (x*10)+10, (y*10)+10);
	    }
	}

	// loop to next frame
	if (AppState.running)
	    window.requestAnimationFrame(loop);
    };
    loop();
};
```

Now we need to update our `init()` to include these new entities.
```zig
export fn init() void {
    _ = set_pos(4, 4, Entity.Wall);
    _ = set_pos(4, 3, Entity.Wall);
    _ = set_pos(4, 5, Entity.Wall);
    _ = set_pos(3, 4, Entity.Wall);
    _ = set_pos(5, 4, Entity.Wall);

    // set the player and the goal
    _ = set_pos(0, 0, Entity.Player);
    _ = set_pos(5, 5, Entity.Goal);

    // set a block to push
    _ = set_pos(3, 1, Entity.Block);
    return;
}
```

Now we have a new game world we can walk around in and check out. We cannot move anything or walk into the goal, which is fine and testament to some sturdy logic we wrote.

![Our game world with a goal and a blue block](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ljsggy59b5opll1echuh.png)

Adding the logic to the push block will add a new layer of logic we need to account for. Now we need to calculate *another* new destination, then see if we can move the block to that. Annoying, but could be refactored later down the line if needed.

```zig
// .. inside our player moving logic
.Block => {
    // move this block somewhere
    var newblockx = goalx;
    var newblocky = goaly;
    if ((dir == .Up) and (newblocky > 0))
        newblocky -= 1;
    if ((dir == .Down) and (newblocky < HEIGHT - 1))
        newblocky += 1;
    if ((dir == .Left) and (newblockx > 0))
        newblockx -= 1;
    if ((dir == .Right) and (newblockx < WIDTH - 1))
        newblockx += 1;

    var block_dest = calc_pos(newblockx, newblocky);
    if (block_dest == goalpos)
        return;
    var block_dest_ent = WORLD.cells[block_dest];
    switch (block_dest_ent) {
        .Empty => {
            _ = set_pos(WORLD.playerx, WORLD.playery, .Empty);
            _ = set_pos(goalx, goaly, .Player);
            _ = set_pos(newblockx, newblocky, .Block);
        },
        .Goal => {
            _ = set_pos(WORLD.playerx, WORLD.playery, .Empty);
            _ = set_pos(goalx, goaly, .Player);
        },
        else => {},
    }
}
```

And now we can push the block around a bit to try it out.

![The blue block is now pushable by the player square](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qkpr2nk62hr4tci6nonf.png)

But this isn't without it's flaws, because this can happen.

![A block stuck in a corner, now unmovable](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qmwifsxj56q3qhn8t0di.png)

A simple change to the event listener, we can trigger a re-initialization of the world by calling `init()` again. This can hilariously lead to errors, but we're gonna worry about that later.

```javascript
window.document.body.addEventListener('keydown', function(evt){
    if (!AppState.loaded)
	return;
    if ((evt.key == "w") || (evt.key == "ArrowUp"))
	Game.update(0);
    if ((evt.key == "s") || (evt.key === "ArrowDown"))
	Game.update(1);
    if ((evt.key === "a") || (evt.key === "ArrowLeft"))
	Game.update(2);
    if ((evt.key === "d" || evt.key === "ArrowRight"))
	Game.update(3);
    if (evt.key == "r")
	Game.init();
});
```
By pressing `r` after moving the block, you end up with a funny "error" (it's not really an error, more unexpected behavior).

![Multiple blue blocks appear because we never de-initialize all entities for a full reset](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i023s8ts2btmkix03uhr.png)

## Winning

To close out this series, we're going to add one last thing - a win condition. You've already "won" by removing the blue block entirely, but how does the JS know when it's all said and done?

To do this we need a new flag, so we're going to modify the world state struct definition one last time.

```zig
const State = struct{
    playerx: u8,
    playery: u8,
    victory: bool,
    cells: [W_SIZE]Entity,
};

var WORLD = State{
    .playerx = 0,
    .playery = 0,
    .victory = false,
    .cells = undefined, 
};
```

A Boolean flag now exists to tell us when the game is effectively over. Pressing `r` will be how you reset the game back, and can start playing again. This isn't public, so we need to write a function to exposed it to JavaScript.

```zig
export fn is_won() bool {
    return WORLD.victory;
}
```

Now we can call it from JavaScript to write some text on screen when the game is over.

```
// in our rendering code
if (Game.is_won()) {
    ctx.font = '18px serif';
    ctx.fillStyle = "Black";
    ctx.fillText('You won!', 10, 15);
}
```

Lastly, let's update our `update()` function to change the victory flag when the game ends, and we can also change `init()` to reset the victory flag to start over.

```zig
export fn init() void {
    WORLD.victory = false;
    _ = set_pos(4, 4, Entity.Wall);
    _ = set_pos(4, 3, Entity.Wall);
    _ = set_pos(4, 5, Entity.Wall);
    _ = set_pos(3, 4, Entity.Wall);
    _ = set_pos(5, 4, Entity.Wall);

    // set the player and the goal
    _ = set_pos(0, 0, Entity.Player);
    _ = set_pos(5, 5, Entity.Goal);

    // set a block to push
    _ = set_pos(3, 1, Entity.Block);
    return;
}
```

```zig
// inside the update() function near the end
.Goal => {
    _ = set_pos(WORLD.playerx, WORLD.playery, .Empty);
    _ = set_pos(goalx, goaly, .Player);
    WORLD.victory = true; // you win!
},
```

And with all that, we've finally achieved real victory.


![The blue block army was defeated in this screenshot](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i5lxpebv1dl5jhi8itrz.png)

## Plugging the Leaks

There's a few things to go over last, and it's due to the differences in how Zig creates a WASM file, but interactions with JavaScript can be flaky because they don't certain abstractions with each other.

First off, we have an `enum` type called `Entity`, which is a range of values conforming to a singular type. These enumerated names all have differently bound values that Zig understands, but JavaScript does not. For instance, check this out.

```javascript
>>> Game.set_pos(4, 4, 1) // valid, sets a player
1
>>> Game.set_pos(4, 4, 255) // ?? what is this??
1
>>> Game.set_pos(4, 4, 20000) // not even 8-bit now
1
>>> Game.get_pos(4, 4)
32 // ????
```

Because the signature of `set_pos` is `set_pos(u8, u8, Entity)`, it's C-language definition looks more like `set_pos(u8, u8, u8)`, meaning it can support any value of eight bits. There isn't a restriction at this level, so using 255 as an `Entity` value is completely valid to the program, but invalid to us as game developers. This is a bit of a hole that should be plugged for safety.

We can define some level of safety by ensuring our input is an `Entity` value or not. This involves a Zig-level switch to check for all possible `Entity` values.

```zig
export fn set_pos(x: u8, y: u8, v: Entity) bool {
    var index = calc_pos(x, y);
    if (index < W_SIZE) {
        switch (v) {
            .Empty => { WORLD.cells[index] = .Empty; },
            .Player => {
                WORLD.playerx = x;
                WORLD.playery = y;
                WORLD.cells[index] = .Player;
            },
            .Wall => { WORLD.cells[index] = .Wall; },
            .Goal => { WORLD.cells[index] = .Goal; },
            .Block => { WORLD.cells[index] = .Block; },
            else => { return false; },
        }
        return true;
    }
    return false;
}
```
This might look reasonable, except this is actually a compiler error! Since we have five elements in `Entity`, this enum is considered 100% checked and safe in Zig's eyes. But for us, translating Zig into C-level code for WASM, this is not concrete.

There are two trains of thought here, and I am going to pick the one of least resistance after a bit of explaining. Our choices are:

* bind all possible values of `Entity` on the JS side, making it easier to use `set_pos()` by using binded values instead of raw integers.
* create a `.Null` property in the `Entity` enum, don't match against it in the switch, fallback to an `else` clause, and let Zig view that as "valid".

The lesser of two evils here is using the latter, and tricking Zig. Some may take issue with this, but I think it's a better work-around than attempting to fix the JS side, where there are less restrictions. An `Entity.Null` doesn't take up any extra space since the `Entity` enum is only a `u8`, and those addresses are already defined, so it's not like we're adding major overhead. This is simply a precaution I'm willing to make in the name of stricter safety.

With this set of code, Zig no longer errors on compile and we have a new layer of safety in our interface.

```zig
const Entity = enum(u8) {
    Empty,
    Player,
    Wall,
    Block,
    Goal,
    Null, // goes last, otherwise is the default value
};

fn set_pos(x: u8, y: u8, v: Entity) bool {
    var index = calc_pos(x, y);
    if (index < W_SIZE) {
        switch (v) {
            .Empty => { WORLD.cells[index] = .Empty; },
            .Player => {
                WORLD.playerx = x;
                WORLD.playery = y;
                WORLD.cells[index] = .Player;
            },
            .Wall => { WORLD.cells[index] = .Wall; },
            .Block => { WORLD.cells[index] = .Block; },
            .Goal => { WORLD.cells[index] = .Goal; },
            else => { return false; },
        }
        return true;
    }
    return false;
}
```

Now using `set_pos()` should start showing some safer results.

```javascript
>>> Game.set_pos(1, 1, 20000)
0
>>> Game.set_pos(1, 1, 1)
1
```

This helps to further solidify the abstraction of the game to make it less leaky and error prone. The user might get a little crazy and try to nullify the entire map! We can secure our code more by making `set_pos()` not a publicly exported function as well, and since our JS doesn't manipulate the board, the user shouldn't be affected by this at all.

The other issue that can occur is what happens when the game resets and is re-initialized. In no capacity does the world get initialized to an empty state, and we cannot rely on the `undefined` keyword to do this for us. Simply setting something to `undefined` doesn't act as a means of setting an array full of values, unless it's the first time being initialized.

We can fix this by changing `init()` to fill values in the array all the way with empty values instead using a simple `while` loop.

```zig
export fn init() void {
    var index = 0;
    while (index < W_SIZE) : (index += 1) {
        WORLD.cells[index] = .Empty;
    }
    WORLD.victory = false;
    _ = set_pos(4, 4, Entity.Wall);
    _ = set_pos(4, 3, Entity.Wall);
    _ = set_pos(4, 5, Entity.Wall);
    _ = set_pos(3, 4, Entity.Wall);
    _ = set_pos(5, 4, Entity.Wall);

    // set the player and the goal
    _ = set_pos(0, 0, Entity.Player);
    _ = set_pos(5, 5, Entity.Goal);

    // set a block to push
    _ = set_pos(3, 1, Entity.Block);
    return;
}
```

Now the extra blue block glitch will go away after each reset. I am sad to see it go, personally.

## Wrap-Up

We're slowly inching forward in better understanding how to use Zig for WebAssembly purpsoses. This was an important write-up for me because I now feel a little more confident in writing WASM with Zig, and can now start possibly focusing on developing more games with Zig targeting WASM.

The next write-up I do, however long it may take, I would like to delve into more complex things like using asset images and bringing that into JavaScript to use on a Canvas. This project could be extended to load levels or a score counter, but I will implement those on the side, as they would be slightly trivial to do. Check out my GitHub repo for more developments on it.

If you've made it this far, thank you for reading. I apologize if it seems too long, but hopefully the length is what will make it able to provide resourceful info for those looking to delve into WebAssembly with Zig.