On A Day At The Races – student

Most recently the Baron challenged Sir R----- to a race of knights around the perimeter of a chessboard, with the Baron starting upon the lower right hand square and Sir R----- upon the lower left. The chase proceeded anticlockwise with the Baron moving four squares at each turn and Sir R----- by the roll of a die. Costing Sir R----- one cent to play, his goal was to catch or overtake the Baron before he reached the first rank for which he would receive a prize of forty one cents for each square that the Baron still had to traverse before reaching it.

A Day At The Races – baron m.

Halloo Sir R-----! Pray come join me and partake of a glass of this rather excellent potation!

Might I again tempt you with a wager?

Splendid!

I have in mind a game that always reminds me of my victory upon the turf at Newmarket. Ordinarily I would not participate in a public sporting event such as this since I am at heart a modest man and derive no pleasure in demonstrating my substantial superiority over my fellows.

New game: Tron – frantic multiplayer retro action

My newest game is out now on Smolpxl Games – Tron:

Pixellated lines fight each other to stay alive

Play at smolpxl.gitlab.io/tron.

It’s a frantic multiplayer retro pixellated thingy playable in your browser. Try to stay alive longer than everyone else!

This version allows many players (up to 16 if you can manage it), and is quite pure in its implementation.

There are bots to play against, and you can gather your friends around a keyboard to play together.

Part of the motivation for writing this game was to test my new smolpxl-remote remote-play system, but this is not enabled yet, so watch this space…

I love playing games with other people – preferably at least 3 other people. In theory you could have 8 players around a keyboard playing this – send me a picture if you try!

One feature I worked on in the Smolpxl library for this game: saving configuration to local storage (and asking permission to do so). I ended up with a very ugly hack to do this, so a bit more work is needed before I merge it into the library.

On Triumvirate – student

When last they met, the Baron invited Sir R----- to join him in a wager involving a sequence of coin tosses. At a cost of seven coins Sir R----- would receive one coin for every toss of the coin until a run of three heads or of three tails brought the game to its conclusion.

To evaluate its worth to Sir R----- we begin with his expected winnings after a single toss of the coin.

Triumvirate – baron m.

Welcome Sir R-----! Pray join me for a draught of cider to refresh you on this close summer's eve!

Would you be in the mood for some sporting diversion?

It pleases me to hear so Sir! It pleases me greatly!

I challenge you to a game that reflects the somewhat unique political system adopted by the three sister-queens of Thornborough; Alnitak, Alnilam and Mintaka. Whilst ruling as a triumvirate their constitution requires all three to concur upon any decision, quite unlike any others in antiquity or modernity which, as I'm quite sure that you are aware, require but two.

Why write an entire game (including Graphics) in a single, hand-coded JavaScript file?

My new game, Rightwaves, is out now! It’s a tribute to the great classic R-Type.

A pixel-art spaceship battles aliens

The entire implementation, including all the graphics, is contained within a single ~5000-line JavaScript file. Why?

This is a terrible idea

Let me start by saying I do not recommend writing code this way. It’s a terrible idea, and some aspects of the development process have been severely hampered by doing this.

A pixellated spaceship dodges bullets and heads for a narrow passageway

Complexity

One of my goals for Smolpxl is to strip coding back to the simplest possible thing it can be.

Over the last 40 years, programming has changed a huge amount: the number and variety of the tools we have to work with has increased beyond what I can take in, and almost all of these things are utterly brilliant.

I can’t imagine writing a game like Eat Apples Quick using the line-orientated editor I used on the ZX Spectrum. I thoroughly enjoyed the Rust code completion and documentation I get from running rust-language-server inside NeoVim. (I’ve even heard there are editors that work inside a windowed environment, but I am not brave enough to try one.)

A pacman-like game

I can’t imagine writing the simple physics engine for Spring in assembly language, or trying to concentrate on that while I had to unravel complex graphics rendering conventions and timings. Instead, I was able to write code that looked a bit like the maths it represented, and allow the browser to handle the graphics card.

A spring with a cheery face bounces off a platform

But, along with all these powerful tools like high-level programming languages, fully cross-platform user interface components, and libraries that make writing a game loop simple, comes a new problem: complexity.

We must choose which tools, libraries and paradigms we’re going to use, and to make that choice we need to understand them.

The Smolpxl library makes some of these choices for you, by enforcing an Elm-style model/update/view split, providing a pixellated canvas of known size, and handling a game loop with fixed framerate. This is particularly suited to writing little retro-style games, similar to what I used to write in AMOS Basic on my Amiga.

I want to make everything simple, but I want our game to work on people’s computers. The only platform we can realistically choose is the browser: the exact same code works almost everywhere.

None of this explains why I would write a game inside a single file of source code, but hopefully it begins to demonstrate where I am coming from.

Simplicity

Another goal for Smolpxl is to teach programming, and a huge barrier I see to getting started is the build process.

No build

You can write Smolpxl games in Rust and compile them to WASM (which is how Eat Apples Quick is done), and you could also package the JavaScript with webpack or similar, but I want the first-class way of using Smolpxl to involve no build at all: I want you to be able to copy in a standard index.html and smolpxl.js and then write your code in game.js and have it just work when you double-click on index.html.

A goal for Rightwaves is to demonstrate that you can write a full game in Smolpxl, without stepping outside that simple story: just double-click on index.html.

It’s all inside game.js

So, Rightwaves is a single* JavaScript file containing the code, the level descriptions, and, probably most unusually, the graphics.

* Note: I cheated – the “action-replay” data is in a separate file – it was much bigger than the source code, and would have made it too hard to deal with. If I wanted to stay pure, I would have had to remove the default action replay from the game, but I just liked it too much.

Level design

Many times while I was writing Rightwaves, I wished I had written a level editor. In fact, I am often quoted as saying

“A game without a level editor is only half a game.”
— Andy Balaam, quite often

But instead, the level design is code like this:

const LEVELS = [
    {
        scenery: [
            { x:   0, y: 80, image: "machinery-20x16-01"},
            { x:  20, y: 88, image: "machinery-20x08-01"},
// ... etc.
        ],
        width: 1526,
        aliens: [
            newRedFlat(130, 20),
            newRedFlat(145, 25),
// ... etc.

The full code is at gitlab.com/smolpxl/rightwaves/-/blob/main/public/game.js#L3478.

It’s not a lot of fun to edit, but on the other hand, every time you make a change a simple refresh in the browser lets you see what it really looks like. No build process; no waiting.

Graphics

I drew the graphics for Rightwaves using GIMP, exported the images as PNG files, and converted them to text using a little Rust utility I wrote.

When I wanted to change an image, it was a nightmare, and I would recommend this approach to no-one whatsoever.

The reason why Smolpxl supports creating images in the source code is so you can hand-craft them right there, using an ASCII-art style.

Here’s the spaceship: An ASCII-art spaceship

and here is the code for it:

const IMAGES = {
    "ship": {
        pixels: [
            "..www.......",
            "dddddww.bbb.",
            "rllldddcccwb",
            "dddhlllccccb",
            "rddddddaccb.",
            "..aaa......."
        ],
        key: {
            "w": [255, 255, 255],
            "d": [88, 88, 88],
            "b": [77, 111, 249],
            "r": [141, 0, 0],
            "l": [126, 125, 125],
            "h": [192, 192, 192],
            "c": [3, 157, 157],
            "a": [42, 42, 42]
        }
    },
// ... lots, and I do mean lots, more here for the other graphics ...

The full code is at gitlab.com/smolpxl/rightwaves/-/blob/main/public/game.js#L41.

Note that I painstakingly coloured that code in for you, for this blog post. In the code there is no such luxury!

Openness

All the Smolpxl games are Free/Open Source software, of course. By avoiding a build, anyone can see the source code, just as I wrote, it in their browser. Anyone (including me) can debug problems without any extra steps. Putting everything in one file makes it easier to find the code (but probably makes it harder to understand).

Optimisation

Rightwaves loads really fast. On my machine, the first time you visit the page, it is playing within 1.4 seconds, after downloading 5 files at a total of 149kB (gzipped). If we exclude the included action replay, it is much smaller.

All of this, with no build process.

Maybe it wasn’t such a bad idea after all.

This is a bad idea

Don’t try this.

For fun

Except, of course, if you like fun. I tried this because it was fun. I would heartily recommend trying things because they might be fun.

Also, if you like fun, try playing the games on Smolpxl games, or write your own!

A puzzle game, a cross-the-road game, a tunnel game, a snake game, a Heli game, and a game-of-life thingy

The Fours Reawakens – baron m.

Hail Sir R-----! Come join me for a tankard of this rather exceptional spring ale!

Might you also join me in a little sport?

You are, my friend, a most dependable fellow!

I suggest a game that puts me in mind of my second tenure as the Russian military attaché to Coruscant. Some years after I helped the Emperor-Mage Palpatine crush the uprising led by the blasphemous warrior-priests known as Jedi, news reached the Russian court that they were now waging a guerilla campaign against the duly anointed tyrant's armed forces and I was dispatched post haste to lend support once more.

On Twenty-Niner – student

The Baron's most recent wager set Sir R----- the task of placing tokens upon spaces numbered from zero to nine according to the outcome of a twenty sided die upon which was inscribed two of each of those numbers. At a cost of one coin per roll of the die, Sir R-----'s goal was to place a token upon every space for which he should receive twenty nine coins and twenty nine cents from the Baron.

Twenty-Niner – baron m.

Sir R----- my fine fellow! Come in from the cold and join me at my table for a tumbler of restorative spirits!

Might I also tempt you with a wager?

Good man!

I propose a game that was popular amongst the notoriously unsuccessful lunar prospectors of '29. Spurred on by rumours of gold nuggets scattered upon the ground simply for the taking, they arrived en-masse during winter woefully unprepared for the inclement weather. By the time that I arrived on a diplomatic mission to the king of the moon people they were in a frightful state, desperately short of provisions and futilely trying to work the frost bitten land to grow more.

Making Smolpxl work on phones and tablets

I’ve added the first features intended to make Smolpxl games work well on touch interfaces like phones and tablets:

Spring game with touch controls

I’ve added a button bar at the bottom (and moved the navigation buttons to the top).

I’m looking for feedback on this:

  • Does it work on your device?
  • Are the buttons the right size?
  • Do they look ok? If not, how could they look better?
  • For games that require arrow keys, do you need them in the normal arrow-keys layout, or is a simple row fine?

Duckmaze game with touch controls in a single row

If you’re writing a game and you want to add buttons like this, you just need to add a single line like this:

game.showControls(["MENU", "SELECT", "BUTTON1", "BUTTON2"]);

or this:

game.showControls(["MENU", "SELECT", "LEFT", "DOWN", "UP", "RIGHT"]);

and they should appear.

On Tug O’ War – student

The Baron and Sir R-----'s latest wager comprised of first placing a draught piece upon the fifth lowest of a column of twelve squares and subsequently moving it up or down by one space depending upon the outcome of a coin toss until such time as it should escape, either by moving above the topmost or below the bottommost square. In the former outcome the Baron should have had a prize of three coins and in the latter Sir R----- should have had two.

Streaming video with Owncast on a free Oracle Cloud computer

I just streamed about 40 minutes of me playing Trials Fusion using Owncast. Owncast is a self-hosted alternative to streaming services like Twitch and YouTube live.

Normally, you would need to pay for a computer to self-host it on. Owncast suggest this will cost about $5/month.

But, Oracle Cloud has a “Always Free” tier that includes a “Compute Instance” (a virtual machine running Linux) that is capable of running Owncast.

Here’s how I did it:

Register for Oracle Cloud

This was probably the worst bit.

I went to oraclecloud.com and clicked “Sign up for free cloud tier”. It didn’t work in Firefox(!) so I had to use Chromium.

I had to enter my name, address, email address, phone number and credit card details. The email was verified, the phone number was verified (with a text message), and the credit card was verified (with a real transaction), so there was no getting around any of it.

They promise that they won’t charge my card. I’ll let you know if I discover differently.

Create a Compute Instance

Once I was logged in to the Oracle “console” (web site), I clicked the burger menu in the top left, chose “Compute” and then “Instances” to create a new instance. I followed all the default settings (including using the default “image”, which meant my instance was running Oracle Linux, which I think is similar to Red Hat), and when I got to the ssh keys part, I supplied the public key of my existing SSH key pair. Read the docs there if you don’t have one of these.

As soon as that was done, and I waited for the instance to be created and started, I was able to SSH in to my instance using a username of opc and the Public IP Address listed:

ssh opc@PUBLIC_IP

(Note: here and below, if I say “PUBLIC_IP”, I mean the IP address listed in the information about your compute instance. It should be a list of four numbers separated by dots.)

Allow connecting to the instance on different ports

Owncast listens for HTTP connections on port 8080, and RTMP streams on 1935, so I needed to do two things to make that work.

Modify the Security List to add Ingress Rules

  • On the information about my instance, I clicked on the name of the Subnet (under Primary VNIC).
  • In the subnet, I clicked the name of the Security List (“Default Security List for …”) in the Security Lists list.
  • In the Security List I clicked Add Ingress Rules and entered:
    Stateless: unchecked
    Source Type: CIDR
    Source CIDR: 0.0.0.0/0
    IP Protocol: TCP
    Source Port Range: (blank)
    Destination Port Range: 8080
    Description: (blank)

    and then clicked Add Ingress Rules to create the rule.

  • I then added another Ingress Rule that was identical, except Destination Port Range was 1935.

Allow ports 8080 and 1935 on the instance’s own firewall

It took me a long time to figure out, but it turns out the Oracle Linux running on the Compute Instance has its own firewall. Eventually, thanks to a blog post by meinside: When Oracle Cloud’s Ubuntu instance doesn’t accept connections to ports other than 22, and some Oracle docs on ways to secure resources, I found that I needed to SSH in to the machine (like I showed above) and run these commands:

sudo firewall-cmd --zone=public --permanent --add-port=8080/tcp
sudo firewall-cmd --zone=public --permanent --add-port=1935/tcp
sudo firewall-cmd --reload

Now I was able to connect to the services I ran on the machine on those ports.

Install Owncast

The Owncast install was incredibly easy. I just followed the instructions at Owncast Quickstart. I SSHd in to the instance as before, and ran:

curl -s https://owncast.online/install.sh | bash

and then edited the file owncast/config.yaml to have a custom stream key in it. You can do that by typing:

nano owncast/config.yaml

There is information about this file at: owncast.online/docs/configuration.

Run Owncast

I ran the service like this:

cd owncast
./owncast

In future, if I want to leave it running, I may run it inside screen, or even use systemd or similar.

Open the web site

I could now see the web site by typing this into my browser’s address bar:

http://PUBLIC_IP:8080

(Where PUBLIC_IP is the Public IP copied from the Instance info as before.)

Stream some video

Finally, in OBS‘s Settings I chose the Stream section and entered:

Service: Custom...
Server: rtmp://PUBLIC_IP/live
Stream key: STREAM_KEY

Where “STREAM_KEY” means the stream key I added to config.yaml earlier.

Now, when I clicked “Start Streaming” in OBS, my stream appeared on the web site!

Costs and limits

Oracle stated during sign-up that I would not be charged unless I explicitly chose to use a different tier.

The Compute Instance is part of the “Always Free” tier, so in theory it should stay up and working.

However, if you use lots of resources (which streaming for a long time probably does), I would expect services would be throttled and/or stopped completely. I have no idea whether they will allow enough resources for regular streaming, or whether this is all waste of time. We shall see.

Announcing Smolpxl Scores – a high score table for your game

It’s a very early beta for now, but I’m ready to announce Smolpxl Scores, which provides high-score tables for Free and Open Source games.

Each game can have multiple high-score tables – for example, you might want one for each level.

At the moment it’s deployed in my own web hosting and therefore written using the technologies that are most convenient for me to deploy there, which is PHP+MySQL. If it becomes more widely used and the performance suffers I guess I’ll ask for donations to host it somewhere else, and use more fashionable technologies.

To add a score you make a POST request like this:

curl https://scores.artificialworlds.net/api/v1/myappname/mytablename/ -d \
    '{"appId":"myappid","name":"Megan Tria", "score": 13.5, "notes": ""}'

and to look at some existing scores you can request them by pages:

curl 'https://scores.artificialworlds.net/api/v1/myappname/mytablename/?startRank=11&num=20'

or by name:

curl 'https://scores.artificialworlds.net/api/v1/myappname/mytablename/?startName=David%20Lloyd%20Geo&offset=-5&num=10'

The results are ordered by players’ scores, and are provided as JSON.

Each table stores only one score per player.

Of course, the API will evolve over time, but I hope that what I have now will be good enough to support some real-life games, and provide enough feedback to make it better.

As soon as people are actually using it, I will ensure the current API version (v1) remains stable, and release any incompatible updates as later versions.

If you’d like to use Smolpxl Scores to add a high-score table to your game, please create an issue at gitlab.com/smolpxl/smolpxl-scores/-/issues.

This service is only available to Free and Open Source games. Also, if someone abuses it (accidentally or on purpose) I will talk to them, and may eventually have to remove their access if we can’t fix the problem.

Tug O’ War – baron m.

Season's greetings Sir R-----! Come take a glass of mulled wine to warm your spirits on this chill winter's night!

Will you also accept a wager to warm your blood?

It gladdens my heart to hear so sir!

I propose a game that oft puts me in mind of the banquet held in the great hall upon Mount Olympus to which I was invited as the guest of honour by Zeus himself!

Why a Free Software web games site?

Recently I’ve been having a lot of fun working on Smolpxl, which is a web site featuring some little retro web games that are all Free and Open Source Software.

Here’s a sneak preview of the game I am working on:

A pixellated spaceship avoids some walls, then crashes into them

Why do this?

Apart from the fact that it’s fun, I also think there is a need for a site like this: a safe place for kids to play little games without creepy advertising looking over their shoulder, and perverse incentives for the site creators.

Little web games can be a diversion during train journeys, helpful distractions for parents and teachers to provide for kids, and even be a little educational around mouse and keyboard use. I’ve seen the sites that already exist be helpful in all those contexts, but I’ve always felt uncomfortable that these sites are supported by advertising, which always comes with concerns about privacy, and also leads game creators to focus on “engagement”, creating mechanisms like site-wide currencies and gambling-style rewards that drive addictive behaviours.

Wouldn’t it be nice if we in the Free and Open Source community could write some fun games that are free from those unhealthy influences?

Wouldn’t it be even nicer if we took the opportunity to encourage kids to learn how to make games as well as play them?

Well, that’s the idea. Have a look at smolpxl.artificialworlds.net, play a few games, and think about writing a few more…

Also, if you know of existing Free and Open Source web games that might work well on the site, let me know and I’ll have a chat with their creators: I definitely plan to include games by more people than just me.

Code your first game: Snake in JavaScript (on Raspberry Pi)

Welcome! We are going to code a whole snake game. It’s going to look like this:

A finished snake game being played

It doesn’t matter if you have never written any code before: I am going to try and explain everything from scratch.

I’m going to assume you are using a Raspberry Pi. but you don’t need one – all you need is Git, a text editor (like Notepad on Windows) and a web browser (like Firefox or Chrome or Safari or Edge). All laptops and desktop PCs should have the last two. On a tablet or phone it will be more tricky: try to use a Raspberry Pi or other computer if you can. If you are not using a Raspberry Pi, the screenshots will look a bit different, so you’ll have to do a little detective work to follow along.

For the first part where we download some code, your Raspberry Pi needs to be connected to the Internet, but once the “git clone” part is done, you can do everything else disconnected.

Before we start

If you’ve got a Raspberry Pi with Raspberry Pi OS on it, you are ready to go!

If you’re on another computer, make sure you’ve got Git installed. This should be easy on Linux, and possible on Mac or Windows.

Setting up

The first thing we need to do is download the code we are going to use to help us make a game. We’ll get it from my games web site, Smolpxl games.

Start your web browser:

Click the browser launch button

type in the address: smolpxl.artificialworlds.net

Typing the address into the browser address bar

and press Enter.

Scroll to the bottom of the page and click the link “make your own games at gitlab.com/andybalaam/smolpxl“.

Choosing the gitlab link at the bottom of the page

On the GitLab page that loads, click on Clone on the right:

Clicking the Clone button

and, under “Clone with HTTPS” click the “Copy URL” button:

Clicking the Copy URL button under Clone with HTTPS

Now start the Terminal:

Starting the Terminal by clicking its icon

and type in “git clone” followed by a space, but don’t press Enter yet. Right-click in the Terminal and choose “Paste” to paste in the URL that we copied before.

Your Terminal should look like this:

The Terminal showing text: git clone https://gitlab.com/andybalaam/smolpxl.git

Press Enter, and it should change to look like this:

Results of a successful git clone command

Go to your file manager:

Opening file manager by clicking its icon

and double-click on “smolpxl”:

Double-clicking smolpxl folder

and then double-click on “public”:

Double-clicking public folder

We are going to copy the “snake” folder. Right-click on it:

Right-clicking the snake folder

and choose “Copy”:

Choosing "Copy"

then right-click somewhere in the space below, and click “Paste”:

Choosing Paste

The Pi doesn’t want to paste the new one over the old one, so type a new name for it: “minisnake”, and click “Rename”:

Renaming pasted folder to minisnake

Now go into your new minisnake folder by double-clicking on it:

Double-clicking the new minisnake folder

We’re going to edit the file called game.js. To do this, double-click on it:

Double-clicking game.js

This should open the code in a text editor program called Mousepad. (If you’re not on a Raspberry Pi, you might need to right-click the file and choose “Edit”, or similar, to open it in a text editor.)

We want to delete everything in here and start again. Click “Edit”, then “Select all”:

Choosing Edit, then Select All, and hello to you if you are reading this!

Now press the “Delete” key, and all the code should be gone:

Mousepad with all the code gone

We are ready to start!

A game that does nothing

First, we’re going to type some code that gets us ready, but doesn’t actually do anything useful.

Type in this code:

const game = new Smolpxl.Game();
game.setSize(20, 20);
game.setTitle("Minisnake");

function update(runningGame, model) {
}

function view(screen, model) {
}

game.start("minisnake", {}, view, update);

This sets the size of our screen (20 by 20 squares), and a title, and gets things ready for our game. Notice that we start our game by writing game.start.

Once you’ve typed in the code:

Mousepad with the code I just told you to type in

click “File” and then “Save”:

Choosing "File", then "Save"

Now we’re going to try it out! Go back to the minisnake folder:

Switching back to file manager, which is on the minisnake folder still

and double-click on the file called index.html:

Double-clicking index.html

If you typed everything correctly, a title screen should appear. To figure out any problems, we will want the Developer tools open. To do that, click the three dots in the top right, then “More tools”, and “Developer tools”:

Choosing Chromium's burger menu in the top right, then clicking More tools, then Developer Tools

The tool we want is the Console, so click “Console” to see it:

Choosing the Console tab in Developer tools

If everything went well, the Console should be empty:

Our game on the left, and the Console on the right, with no error messages showing

If you see red error messages in the Console, you probably have a typo: double-check everything you typed, and compare it with this version: game-01-nothing.js.

Now we have everything ready to get started, and you can see our game already has a title screen!

The game is going to be made from three things:

  • a model,
  • a view, and
  • an update function.

Let’s start with the model and the view.

The Model and the View

The first thing we’re going to do is add an apple to the game. To do that, we need to do two things:

  • say where the apple is, and
  • draw the apple on the screen.

To say where the apple is, we need a model. We actually already have a model, but it’s just empty.

Switch back to your code:

Switching back to Mousepad by clicking game.js in the top bar

Look at the last line of code we typed, and find where you typed {}. This is the “model”, or the state of out game when we start it off. Now, we’re going to replace that with newModel(), which means call a function called newModel. (A function is a piece of code that we can re-use, and “calling” a function means running that code.)

So we’re going to write a function called newModel, and then call it. Replace the very last line of your code with this:

function newModel() {
    return {
        apple: [5, 5]
    };
}

game.start("minisnake", newModel(), view, update);

The top part makes a function called newModel, and the bottom part is the same as you had before, except {} is replaced by newModel().

Have another look at the newModel function we wrote (the top part). Can you see where we made the apple? After the word return, we have some stuff inside curly brackets ({ and later, }). When we use curly brackets like that, we are making what JavaScript calls an object. Objects have properties. So far, our object only has one property, which is called “apple”. The right-hand part, [5, 5] is how we are say where our apple is – it’s at the position 5 squares in from the left, and 5 squares down from the top of our screen.

Now we have said where our apple is, we also need to draw it on the screen. That happens inside the view function. Scroll up and find the part that says function view() and add a new line between the opening { and the closing one:

function view(screen, model) {
    screen.set(model.apple[0], model.apple[1], [255, 0, 0]);
}

We are calling a function called screen.set, which draws a square on the screen. We are passing in three things to it: two points for the position to draw, and then the colour to use. The position is model.apple[0], which means take the first part of the [5, 5] we typed before, and model.apple[1], which means take the second part. The color is [255, 0, 0] which means lots of red, and no green or blue, because this is a red-green-blue (RGB) colour.

So let’s try this out and see whether the apple is drawn on the screen. First save your code in Mousepad, then switch back to our game (in Chromium), and click the refresh button to reload it.

Switching back to Chromium in the top bar, then clicking the refresh button

You should see your game saying “Enter to start”. Click on it, and the game should start, and look like this:

The game window is black, except there is a red square for the apple

Well done, you have drawn an apple!

If you see red error messages in the Console, you probably have a typo: double-check everything you typed, and compare it with this version: game-02-just-apple.js.

Drawing a snake

Now that we have an apple, let’s follow the exact same pattern to add a snake. We’re going to add information about it to the model, and then use that information to draw it on the screen.

First, change the newModel function to look like this:

function newModel() {
    return {
        apple: [5, 5],
        body: [[10, 10], [10, 11], [10, 12], [10, 13], [10, 14]]
    };
}

Don’t miss the extra comma at end of the “apple” line!

To give the co-ordinates of the apple, we just used one [x, y] pair. Because the snake’s body is made from 5 points, we need 5 similar pairs.

We’ve described the snake’s body position, so now let’s draw it on the screen. Update the view function so it looks like this:

function view(screen, model) {
    // Snake
    for (const [x, y] of model.body) {
        screen.set(x, y, [0, 255, 0]);
    }

    // Apple
    screen.set(model.apple[0], model.apple[1], [255, 0, 0]);
}

We have added a for loop – it runs through all the points in body, and for each one it draws a square on the screen. This time the colour is [0, 255, 0], which means the snake will be green.

(By the way, did you notice the lines we added that start with // – these are “comments” – we can write anything we like after the slashes and it doesn’t do anything. We can use comments to add notes that help us remember what different bits of our program do.

Save the file, go back to the game in Chromium and click the Refresh button again. If all goes well, you should see the snake appear:

A black game screen, with a red dot and green line for the snake

If you see red error messages in the Console, you probably have a typo: double-check everything you typed, and compare it with this version: game-03-snake.js.

So now we have a snake and an apple, but nothing is really happening … let’s fix that next.

Making the snake move

We’ve made a model in newModel and we’ve drawn it on the screen in view, but how do we make things move around? That is where the update function comes in: this is where we change the model based on what is happening.

Let’s start by making the snake move forward forever. Change the update function to look like this:

function update(runningGame, model) {
    // Move the snake
    let newHead = Smolpxl.coordMoved(model.body[0], model.dir);
    let newTail = model.body.slice(0, -1);

    model.body = [newHead, ...newTail];
    return model;
}

and change the newModel function to look like this:

function newModel() {
    return {
        apple: [5, 5],
        body: [[10, 10], [10, 11], [10, 12], [10, 13], [10, 14]],
        dir: Smolpxl.directions.UP
    };
}

Again, notice the comma at the end of the body line!

We added dir to the model, which is the direction the snake is facing.

The update function makes newHead by moving the snake’s head (the first entry in its body, which it gets with model.body[0]) in the direction it is facing (model.dir). Then we create newTail, which is everything in the old model.body except the last entry in the list (this is what .slice(0, -1) means).

Finally we update the body by setting it to [newHead, ...newTail], which just means make a new list by sticking newHead on to the beginning of newTail.

Save, switch to the game in Chromium, and refresh. Because we set dir to Smolpxl.directions.UP inside newModel, the snake moves updards!

The green snake moves up the screen (and off the top)

If you see red error messages in the Console, you probably have a typo: double-check everything you typed, and compare it with this version: game-04-movement.js.

If the snake disappears off the top, click the refresh button to see it again.

The game isn’t too much fun yet. Let’s add some keyboard controls, and allow you to die when you go off-screen.

Controlling the snake

The update function moves the snake, but now it’s time to make it a bit cleverer, by changing direction when you press a key, and stopping you when you go off-screen. Change it so it looks like this:

function update(runningGame, model) {
    if (!model.alive) {
        return;
    }

    if (runningGame.receivedInput("LEFT"))  {
        model.dir = Smolpxl.directions.LEFT;
    } else if (runningGame.receivedInput("RIGHT")) {
        model.dir = Smolpxl.directions.RIGHT;
    } else if (runningGame.receivedInput("UP")) {
        model.dir = Smolpxl.directions.UP;
    } else if (runningGame.receivedInput("DOWN")) {
        model.dir = Smolpxl.directions.DOWN;
    }

    // Move the snake
    let newHead = Smolpxl.coordMoved(model.body[0], model.dir);
    let newTail = model.body.slice(0, -1);

    // Die if we hit the edge
    if (
        newHead[0] === runningGame.screen.minX ||
        newHead[0] === runningGame.screen.maxX ||
        newHead[1] === runningGame.screen.minY ||
        newHead[1] === runningGame.screen.maxY
    ) {
        model.alive = false;
    }

    model.body = [newHead, ...newTail];
    return model;
}

and change the newModel function to look like this:

function newModel() {
    return {
        alive: true,
        apple: [5, 5],
        body: [[10, 10], [10, 11], [10, 12], [10, 13], [10, 14]],
        dir: Smolpxl.directions.UP
    };
}

We keep track of whether the snake is alive in the model, and we immediately return from update if we are dead, meaning the snake stops moving. (The ! in if (!model.alive) means “not”, so we are saying what to do when we are not alive – when we are dead. The return here means immediately stop running the code in this function.)

The next new part of update allows us to check whether an arrow key was pressed (using the runningGame.receivedInput function), and if so, change the direction of the snake (model.dir).

Finally, nearer the end of update, we check whether the position of the snake’s head (newHead) is at one of the screen edges, by comparing its co-ordinates with the maximum and minimum co-ordinates on the screen. If we are off the edge, we set model.alive to false, meaning the snake is now dead.

Save, switch to the game in Chromium, and refresh. With all that, we can control the snake with the arrow keys, and it can die:

A snake moves around, turning because arrow keys were used to control it

Try clicking on your game and then pressing the arrow keys to control the snake.

If you see red error messages in the Console, you probably have a typo: double-check everything you typed, and compare it with this version: game-05-control.js.

This is kind-of a game, but surely it’s time to eat some apples?

Eating apples

If we’re going to be eating apples, they should probably not always be in the same place, right?

Let’s start off by making a brand new function. Make some space immediately above the update function, and type in this code:

function randApple() {
    return [Smolpxl.randomInt(1, 18), Smolpxl.randomInt(1, 18)];
}

This function gives us some random co-ordinates where we can place an apple. Update newModel to place the first apple at a random place, by making it look like this:

function newModel() {
    return {
        alive: true,
        apple: randApple(),
        body: [[10, 10], [10, 11], [10, 12], [10, 13], [10, 14]],
        dir: Smolpxl.directions.UP
    };
}

So instead of writing the exact co-ordinates we want ([5, 5]), now we’re calling our new randApple function, which gives us back some random co-ordinates.

Now we can place apples randomly, let’s change the update function to allow us to eat apples. While we’re there, let’s check whether we crashed into our own body too:

function update(runningGame, model) {
    ... All the same stuff as before ...

    // Die if we hit the edge
    if (
        newHead[0] === runningGame.screen.minX ||
        newHead[0] === runningGame.screen.maxX ||
        newHead[1] === runningGame.screen.minY ||
        newHead[1] === runningGame.screen.maxY
    ) {
        model.alive = false;
    }

    // If we hit the apple we get longer
    if (Smolpxl.equalArrays(newHead, model.apple)) {
        for (let i = 0; i < 5; i++) {
            newTail.push([-1, -1]);
        }
        model.apple = randApple();
    }

    // If we hit our own body, we die
    if (Smolpxl.arrayIncludesArray(newTail, newHead)) {
        model.alive = false;
    }

    model.body = [newHead, ...newTail];
    return model;
}

We use the Smolpxl.equalArrays function* to ask whether the new position of the snake’s head (newHead) is the same as the position of the apple (model.apple).

* The function is called “equalArrays” because both newHead and model.apple are lists of two co-ordinates (x and y), so we are storing them inside JavaScript “arrays”. You can spot an array because it is surrounded by square brackets ([).

If the head is on top of the apple, we do two things: add new items to the end of newTail, by using a for loop that runs 5 times. Each time it runs, it uses push to add another body part on the to the tail. (It actually adds an off-screen point [-1, -1] every time – this means they won’t get drawn at first, but as the snake moves forward, they will gradually get replaced by on-screen points, and we’ll see the snake gradually get longer.)

The second thing we do if the head is on the apple is move the apple by setting model.apple to another random point given to us by randApple.

We also check whether we have hit our own body using the Smolpxl.arrayIncludesArray function (asking whether newHead is the same point as one of the points in newTail) and set model.alive to false, meaning we’re dead, if so.

Save, switch to the game in Chromium, and refresh. Now we can really play a game of snake!

A snake moves around the screen, eating apples and getting longer when it does

If you see red error messages in the Console, you probably have a typo: double-check everything you typed, and compare it with this version: game-06-eating-apples.js.

We are nearly done. The last jobs are to make the game look a little nicer, and handle starting a new game after we crash.

Finishing off

We need to draw the walls around the edge that you crash into, and it would also be nice to show your score at the top of the screen. We can do both of these by adding a bit more at the beginning of the view function:

function view(screen, model) {
    screen.messageTopLeft(`Score: ${model.body.length}`);

    // Walls
    for (const x of screen.xs()) {
        screen.set(x, screen.minY, [150, 150, 150]);
        screen.set(x, screen.maxY, [150, 150, 150]);
    }
    for (const y of screen.ys()) {
        screen.set(screen.minX, y, [150, 150, 150]);
        screen.set(screen.maxX, y, [150, 150, 150]);
    }

    ... All the same stuff as before ...
}

We use the screen.messageTopLeft function to display a message at the top. To format the message we write some text inside backticks (`), which allows us to substitute values in. Here we typed ${model.body.length}, which means our score is how many points there are inside our body (which is the length of the array model.body). The ${} part just means “substitute this value in here”.

We make use of the screen.xs() and screen.ys() functions that give us a list of all the x and y co-ordinates on the screen to draw the wall.

Save, switch back to the game, and refresh to see how this looks. If you want to check what you have typed so far, compare it against game-07-walls-and-score.js.

The very last thing we need to do is handle restarting the game after we crash.

First, let’s display a message on the screen by updating the view function one last time:

function view(screen, model) {
    ... All the same stuff as before ...

    // Snake
    for (const [x, y] of model.body) {
        screen.set(x, y, [0, 255, 0]);
    }

    // Death
    if (!model.alive) {
        screen.set(model.body[0][0], model.body[0][1], [0, 0, 255]);
        screen.dim();
        const score = model.body.length;
        screen.message(["Well done!", `Score: ${score}`, "Press <SELECT>"]);
    }

    // Apple
    screen.set(model.apple[0], model.apple[1], [255, 0, 0]);
}

When the snake is not alive we draw a blue dot ([0, 0, 255]) where its head is, then make the screen dark with the screen.dim function, and write a message on the screen with the screen.message function.

Last, if we press Enter while the death message is visible, we want to go back to the start. We can do that with a small change to the update function:

function update(runningGame, model) {
    if (!model.alive) {
        if (runningGame.receivedInput("SELECT")) {
            runningGame.endGame();
            return newModel();
        } else {
            return;
        }
    }

    if (runningGame.receivedInput("LEFT"))  {
    ... All the same stuff as before ...

Notice that we deleted the line that just said return; and replaced it with the new if code. We check whether the user pressed the SELECT button (which means the Enter key) and if so, we tell Smolpxl to go back to the title screen by calling runningGame.endGame, and then we reset everything in the model by returning newModel().

Save, switch to the game in Chromium, and refresh. Our game is finished!

A finished snake game being played

If you see red error messages in the Console, you probably have a typo: double-check everything you typed, and compare it with this version: game-08-finished.js.

Well done!

If you got that working, you should be extremely pleased with yourself. Typing all that code correctly is a major challenge, and your determination has paid off.

Take a breath, and have a think about whether you can show what you’ve done to someone else. I’m pretty sure they will be impressed that you coded an entire game!

Challenges

When you’ve properly taken the time to enjoy the great work you’ve done, try reading through the code, and reading back through this blog post to try and understand how the program works.

To learn more about JavaScript and making web sites, you can follow this much more comprehensive tutorial: Getting started with the Web.

You’ve done really well. If you want an extra challenge, try improving your game using these challenges. Bear in mind though, working these out on your own will be much harder than what we’ve done so far:

  • Challenge 1: Display a different message if you don’t eat any apples. If you crash before eating any apples, you might need some extra encouragement: change the part of the view function where we display a “Well done!” message, and if our score is 5 (if (model.body.length === 5) then display a different message – maybe “Bad luck!”. Look for ifelse statements we have already written, to see how they work.
  • Challenge 2: Prevent going back on yourself. Update your code so that when snake is going right, and the user presses left, we ignore it. You will need to change the update function, where we use receivedInput to check what key the user pressed. Instead of just setting the direction, you will need to add a new if statement that check what direction we are facing already.
  • Challenge 3: Remember the high score. Remember the best score anyone has got, and display it at the top-right of the screen. At the moment in our code, we return newModel(); in update, when we want to restart the game. That means we have a totally fresh model, forgetting everything else that happened before. If we want to remember a high score, we can’t do that! If you want some extra inspiration, have a look at the more complete version of snake that comes with the Smolpxl games. It’s actually included in the code you downloaded with the git clone command you typed at the very beginning.

What next?

To learn more, try:

Remember to have fun, and be kind to the people you meet on the way.

Play and create little retro games at Smolpxl

I love simple games: playing them and writing them.

But, it can be overwhelming getting started in the complex ecosystems of modern technology.

So, I am writing the Smolpxl library, which is some JavaScript code that makes it quite simple to write simple, pixellated games. It gives you a fixed-size screen to draw on, and it handles your game loop and frames-per-second, so you can focus on two things: updating your game “model” – the world containing all the things that exist in your game, and drawing onto the screen.

I am also writing some games with this library, and publishing them at smolpxl.artificialworlds.net:

I am hoping this site will gradually gain more and more Free and Open Source games, and start to rival some of the advertising-supported sites for the attention of casual gamers, especially kids.

Smolpxl is done for fun, and for its educational value, so it should be a safer place for kids than a world of advertising, loot boxes and site-wide currencies.

As I write games, I want to show how easy and fun it can be, so I will be streaming myself live doing it on twitch.tv/andybalaam, and putting the recordings up on peertube.mastodon.host/accounts/andybalaam and youtube.com/user/ajbalaam.

I am hoping these videos will serve as tutorials that help other people get into writing simple games.

Would you like to help? If so:

We Three Kings – baron m.

Sir R----- my fine friend! Will you take a glass of perry with me to cool yourself from this summer heat?

Good man!

Might I also presume that you are in the mood for a wager?

Stout fellow!

I suggest a game that ever puts me in mind of that time in my youth when I squired for the warrior king Balthazar during his pilgrimage with kings Melchior and Caspar to the little town of Bethlehem.

On May The Fours Be With You – student

In their most recent wager Sir R-----'s goal was to guess the outcome of the Baron's roll of four four sided dice at a cost of four coins and a prize, if successful, of forty four. On the face of it this seems a rather meagre prize since there are two hundred and fifty six possible outcomes of the Baron's throw. Crucially, however, the fact that the order of the matching dice was not a matter of consequence meant that Sir R-----'s chances were significantly improved.

May The Fours Be With You – baron m.

Sir R-----! Come join me for a glass of chilled wine! I have a notion that you're in the mood for a wager. What say you?

I knew it!

I have in mind a game of dice that reminds me of my time as the Russian military attaché to the city state of Coruscant and its territories during the traitorous popular uprising fomented by the blasphemous teachings of a fundamentalist religious sect known as the Jedi.

On Fruitful Opals – student

Recall that the Baron’s game consisted of guessing under which of a pair of cups was to be found a token for a stake of four cents and a prize, if correct, of one. Upon success, Sir R----- could have elected to play again with three cups for the same stake and double the prize. Success at this and subsequent rounds gave him the opportunity to play another round for the same stake again with one more cup than the previous round and a prize equal to that of the previous round multiplied by its number of cups.

Fruitful Opals – baron m.

Greetings Sir R-----. I trust that I find you in good spirits this evening? Will you take a glass of this excellent porter and join me in a little sport?

Splendid!

I propose a game that is popular amongst Antipodean opal scavengers as a means to improve their skill at guesswork.
Opals, as any reputable botanist will confirm, are the seeds of the majestic opal tree which grows in some abundance atop the vast monoliths of that region. Its mouth-watering fruits are greatly enjoyed by the Titans on those occasions when, attracted by its entirely confused seasons, they choose to winter thereabouts.

On Two By Two – student

The Baron's most recent wager with Sir R----- set him the challenge of being the last to remove a horizontally, vertically or diagonally adjacent pair of draughts from a five by five square of them, with the Baron first taking a single draught and Sir R----- and he thereafter taking turns to remove such pairs.

When I heard these rules I was reminded of the game of Cram and could see that, just like it, the key to figuring the outcome is to recognise that the Baron could always have kept the remaining draughts in a state of symmetry, thereby ensuring that however Sir R----- had chosen he shall subsequently have been free to make a symmetrically opposing choice.

Two By Two – baron m.

Hello there Sir R-----! Come join me by the hearth for a dram of warming spirits! I trust that this cold spell has not chilled your desire for a wager?

Good man! Good man!

I must say that the contrast between the warmth of this fire and the frost outside brings most vividly to my mind an occasion during my tenure as the Empress's ambassador to the land of Oz; specifically the time that I attended King Quadling Rex's winter masked ball during which his southern palace was overrun by an infestation of Snobbles!

On The Octogram Of Seth LaPod – student

The latest wager that the Baron put to Sir R----- had them competing to first chalk a triangle between three of eight coins, with Sir R----- having the prize if neither of them managed to do so. I immediately recognised this as the game known as Clique and consequently that Sir R-----'s chances could be reckoned by applying the pigeonhole principle and the tactic of strategy stealing. Indeed, I said as much to the Baron but I got the distinct impression that he wasn't really listening.

The Octogram Of Seth LaPod – baron m.

Salutations Sir R-----! I trust that this fine summer weather has you thirsting for a flagon. And perhaps a wager?

Splendid! Come join me at my table!

I propose a game played as a religious observance by the parishioners of the United Reformed Eighth-day Adventist Church of Cthulhu, the eldritch octopus god that lies dead but dreaming in the drowned city of Hampton-on-Sea.
Several years ago, the Empress directed me to pose as a peasant and infiltrate their temple of Fhtagn in the sleepy village of Saint Reatham on the Hill when it was discovered that Bishop Derleth Miskatonic had been directing his congregation to purchase vast tracts of land in the Ukraine and gift them to the church in return for the promise of being spared when Cthulhu finally wakes and devours mankind.

On The Hydra Of Argos – student

When the Baron last met with Sir R-----, he proposed a wager which commenced with the placing of twenty black tokens and fifteen white tokens in a bag. At each turn Sir R----- was to draw a token from the bag and then put it and another of the same colour back inside until there were thirty tokens of the same colour in the bag, with the Baron winning a coin from Sir R----- if there were thirty black and Sir R----- winning ten coins from the Baron if there were thirty white.
Upon hearing these rules I recognised that they described the classic probability problem known as Pólya's Urn. I explained to the Baron that it admits a relatively simple expression that governs the likelihood that the bag contains given numbers of black and white tokens at each turn which could be used to figure the probability that he should have triumphed, but I fear that he didn't entirely grasp my point.

The Hydra Of Argos – baron m.

Ho there Sir R-----! Will you join me for a cold tankard of ale to refresh yourself on this warm spring evening?

And, might I hope, for a little sport?

I should not have doubted it for a moment sir!

This fine weather reminds me of the time I spent as the Empress's trade envoy to the market city of Argos, famed almost as much for the remarkable, if somewhat fragile, mechanical contraptions made by its artificers and the most reasonably priced jewellery sold by its goldsmiths as for its fashion for tiny writing implements.

On Pennies From Heaven – student

Recall that the Baron and Sir R-----'s most recent wager first had the Baron place three coins upon the table, choosing either heads or tails for each in turn, after which Sir R----- would follow suit. They then set to tossing coins until a run of three matched the Baron's or Sir R-----'s coins from left to right, with the Baron having three coins from Sir R----- if his made a match and Sir R----- having two from the Baron if his did.

When the Baron described the manner of play to me I immediately pointed out to him that it was Penney-Ante, which I recognised because one of my fellow students had recently employed it to enjoy a night at the tavern entirely at the expense of the rest of us! He was able to do so because it's an example of an intransitive wager in which the second player can always contrive to make a choice that will best the first player's.

Pennies From Heaven – baron m.

Sir R-----, my good friend! Come shake the snow from your boots and join me by the hearth for a draught of warming spirits!

And will you also join me in a wager whilst you let the fire chase the chill from your bones?

Fine fellow! Stout fellow!

I have in mind a game that reminds me of my raid upon the vault of Heaven, which I mounted in order to make amends to the Empress for my failure to snatch the Amulet of Yendor from the inner circle of Hell.

On Onwards And Downwards – student

When last they met, the Baron challenged Sir R----- to evade capture whilst moving rooks across and down a chessboard. Beginning with a single rook upon the first file and last rank, the Baron should have advanced it to the second file and thence downwards in rank in response to which Sir R----- should have progressed a rook from beneath the board by as many squares and if by doing so had taken the Baron's would have won the game. If not, Sir R----- could then have chosen either rook, barring one that sits upon the first rank, to move to the next file in the same manner with the Baron responding likewise. With the game continuing in this fashion and ending if either of them were to take a rook moved by the other or if every file had been played upon, the Baron should have had a coin from Sir R----- if he took a piece and Sir R----- one of the Baron's otherwise.

Onwards And Downwards – baron m.

Greetings Sir R-----! Might I suggest that you take one of these spiced beef pies and a mug of mulled cider to stave off this winter chill? And perhaps a wager to fire the blood?

Good man! Good man!

I propose a game that ever puts me in mind of my ill-fated expedition to recover for the glory of the Empress of Russia the priceless Amulet of Yendor from the very depths of Hell.

Godot: Dragging and dropping physics objects video

Series: 2D Shapes, drag and drop

Continuing to explore the Godot 3 game engine. I want to make a game where you drag blocks around and balance them on each other, but I couldn’t find much documentation on how to drag-and-drop objects (except menu UI elements), and especially I found quite a few wrinkles when doing this with objects that are normally controlled by the physics engine.

This time we actually write some code in Godot’s programming language, GDScript.

Godot version: v3.0.6.stable.official.8314054

On The Rich Get Richer – student

The Baron's latest wager set Sir R----- the task of surpassing his score before he reached eight points as they each cast an eight sided die, each adding one point to their score should the roll of their die be less than or equal to it. The cost to play for Sir R------ was one coin and he should have had a prize of five coins had he succeeded.

A key observation when figuring the fairness of this wager is that if both Sir R----- and the Baron cast greater than their present score then the state of play remains unchanged. We may therefore ignore such outcomes, provided that we adjust the probabilities of those that we have not to reflect the fact that we have done so.

The Rich Get Richer – baron m.

Sir R-----! I must say that it is a relief to have the company of a fellow nobleman in these distressing times. That I have had to sell not one, but two of my several hundred antiquities to settle the burden of tax that this oppressive democracy has put upon me, simply to enrich slugabeds I might add, is quite intolerable!

Come, let us drown our sorrows whilst we still have the means to do so and engage in a little sport to raise our spirits.

I have a fancy for a game that I used to play when I was the Russian ambassador to the Rose Tree Valley commune. Founded by the philosopher queen Zway Remington as a haven for downtrodden wealthy industrialists, it was the purest of pure meritocracies; no handouts to the idle labouring classes there!

On Blockade – student

Recall that the Baron's game is comprised of taking turns to place dominoes on a six by six grid of squares with each domino covering a pair of squares. At no turn was a player allowed to place a domino such that it created an oddly-numbered region of empty squares and Sir R----- was to be victorious if, at the end of play, the lines running between the ranks and files of the board were each and every one straddled by at least one domino.

Blockade – baron m.

Good heavens Sir R----- you look quite pallid! Come take a seat and let me fetch you a measure of rum to restore your humors.
To further improve your sanguinity might I suggest a small wager?

Splendid fellow!

I have in mind a game invented to commemorate my successfully quashing the Caribbean zombie uprising some few several years ago. Now, as I'm sure you well know, zombies have ever been a persistent, if sporadic, scourge of those islands. On that occasion, however, there arose a formidable leader from amongst their number; the zombie Lord J------ the Insensate.

On Quaker’s Dozen – student

The Baron's latest wager set Sir R----- the task of rolling a higher score with two dice than the Baron should with one twelve sided die, giving him a prize of the difference between them should he have done so. Sir R-----'s first roll of the dice would cost him two coins and twelve cents and he could elect to roll them again as many times as he desired for a further cost of one coin and twelve cents each time, after which the Baron would roll his.
The simplest way to reckon the fairness of this wager is to re-frame its terms; to wit, that Sir R----- should pay the Baron one coin to play and thereafter one coin and twelve cents for each roll of his dice, including the first. The consequence of this is that before each roll of the dice Sir R----- could have expected to receive the same bounty, provided that he wrote off any losses that he had made beforehand.

Quaker’s Dozen – baron m.

Sir R-----, my fine friend! The coming of spring always puts one in excellent spirits, do you not find? Speaking of which, come join me in a glass of this particularly peaty whiskey with which we might toast her imminent arrival!

Might I tempt you with a little sport to quicken the blood still further?

It lifts my soul to hear it Sir!

I have in mind a game that I learned when in passage to the new world with a company of twelve Quakers. I was not especially relishing the prospect of yet another monotonous transatlantic crossing and so you can imagine my relief when I spied the boisterous party embarking, dressed in the finest silks and satins and singing a bawdy tavern ballad as they took turns at a bottle of what looked like a very fine brandy indeed!

On Lucky Sevens – student

The Baron's most recent game consisted of a race to complete a trick of four sevens, with the Baron dealing cards from a pristine deck, running from Ace to King once in each suit, and Sir R----- dealing from a well shuffled deck. As soon as either player held such a trick the game concluded and a prize was taken, eleven coins for the Baron if he should have four sevens and nine for Sir R----- otherwise.
The key to reckoning the equity of the wager is to note that it is unchanged should the Baron and Sir R----- take turns dealing out the rest of their cards one by one after the prize has been taken.

Recording gameplay videos on RetroPie

Credits: this is a slightly corrected and shortened version of How To Record A GamePlay Video From A RetroPie by selsine, which is itself based on Recording Live Gameplay in RetroPie’s RetroArch Emulators Natively on the Raspberry Pi by Retro Resolution.

RetroPie is based on RetroArch. RetroArch has a feature to record gameplay videos, but the current version of RetroPie has it disabled, presumably because it was thought to be too intensive to run properly on a Raspberry Pi.

These instructions tell you how to turn the recording feature on, and set it up. This works perfectly on my Raspberry Pi 3, allowing me to record video and sound from games I am playing.

The code for this is here: github.com/andybalaam/retropie-recording – this was code written by RetroRevolution, with small corrections and additions by me.

Before you start, you should have RetroPie working and connected to the Internet, and updated to the latest version.

Note: you should make a backup of your RetroPie before you start, because if you type the command below you could completely break it, meaning you will have to wipe your SD card and start fresh.

Turning on the recording feature

RetroArch uses the ffmpeg program to record video. To turn on recording, we need to log into the Pi using ssh, download and compile ffmpeg, and then recompile RetroArch with recording support turned on.

Log in to the Pi using ssh

Find out the IP address of your Pi by choosing “RetroPie setup” in the RetroPie menu and choosing “Show IP Address”. Write down the IP address (four numbers with dots in between – for example: 192.168.0.3).

On your Linux* computer open a Terminal and type:

ssh pi@192.168.0.3

(put in the IP address you wrote down instead of 192.168.0.3)

When it asks for your password, type: raspberry

If this works right, you should see something like this:
The RetroPie Project joystick logo

* Note: if you don’t have Linux, this should work OK on a Mac, or on Windows you could try using PuTTY.

Download and compile ffmpeg

Log in to the RetroPie as described above. The commands shown below should all be typed in to the window where you are logged in to the RetroPie.

Download the script ffmpeg-install.sh by typing this:

wget https://github.com/andybalaam/retropie-recording/raw/master/ffmpeg-install.sh

Now run it like this:

bash ffmpeg-install.sh

(Note: DON’T use sudo to run this – just type exactly what is written above.)

Now wait a long time for this to work. If it prints out errors, something went wrong – read what it says, and you may need to edit the ffmpeg-install.sh script to figure out what to do. Leave a comment and include the errors you saw if you need help.

Hopefully it will end successfully and print:

FFmpeg and Codec Installation Complete

If so, you are ready to move on to recompiling RetroArch:

Recompile RetroArch with recording turned on

Download the script build-retroarch-with-ffmpeg.sh by typing this:

wget https://github.com/andybalaam/retropie-recording/raw/master/build-retroarch-with-ffmpeg.sh

Now run it like this:

bash build-retroarch-with-ffmpeg.sh

It should finish in about 10 minutes, and print:

Building RetroArch with ffmpeg enabled complete

If it printed that, your RetroPie now has recording support! Restart your RetroPie:

Restart the RetroPie

Restart your RetroPie.

If you want to check that recording support is enabled, Look for “Checking FFmpeg Has Been Enabled in RetroArch” on the RetroResolution guide.

Now you need to set up RetroPie to record your emulator.

Setting up recording for your emulator

To set up an emulator, you need a general recording config file (the same for all emulators), and a launch config for the actual emulator you are using.

Create the recording config file

Log into the RetroPie as described in the first section, and type this to download the recording config file. If you want to change settings like what file format to record in, this is the file you will need to change.

wget https://github.com/andybalaam/retropie-recording/blob/master/recording-config.cfg

Create a launch config for your emulator

Each RetroPie emulator has a config file that describes how to launch it. For example, the NES emulator’s version is in /opt/retropie/configs/nes/emulators.cfg.

To get a list of all the emulators, log into your RetroPie and type:

ls /opt/retropie/configs

In that list you will see, for example, “nes” for the NES emulators, and “gb” for the GameBoy emulators. Find the one you want to edit, and edit it with the nano editor by typing:

nano /opt/retropie/configs/gb/emulators.cfg

(Instead of “gb” type the right name for the emulator you want to use, from the list you got when you typed the “ls” command above.)

Now you need to add a new line in this file. Each line describes how to launch an emulator. You should copy an existing line, and add some more stuff to the end.

For example, my version of this file looks like this:

lr-gambatte = "/opt/retropie/emulators/retroarch/bin/retroarch -L /opt/retropie/libretrocores/lr-gambatte/gambatte_libretro.so --config /opt/retropie/configs/gb/retroarch.cfg %ROM%"
lr-gambatte-record = "/opt/retropie/emulators/retroarch/bin/retroarch -L /opt/retropie/libretrocores/lr-gambatte/gambatte_libretro.so --config /opt/retropie/configs/gb/retroarch.cfg --record /home/pi/recording_GB_$(date +%Y-%m-%d-%H%M%S).mkv --recordconfig /home/pi/recording-config.cfg %ROM%"
default = "lr-gambatte"
lr-tgbdual = "/opt/retropie/emulators/retroarch/bin/retroarch -L /opt/retropie/libretrocores/lr-tgbdual/tgbdual_libretro.so --config /opt/retropie/configs/gb/retroarch.cfg %ROM%"

The line I added is coloured: The green parts are things copied from the line above, and the red parts are new – those parts tell the launcher to use the recording config we made in the previous section.

When you’ve made your edits, press Ctrl-X to exit nano, and type “Y” when it asks whether you want to save.

Once you’ve done something similar to this for every emulator you want to record with, you are ready to actually do the recording!

Actually doing a recording

Launching a game with recording turned on

In the normal RetroPie interface, go to your emulator and start it, but press the A button while it’s launching, and choose “Select emulator for ROM”. In the list that comes up, choose the new line you added in emulators.cfg. In our example, that was called “lr-gambatte-record”.

Now play the game, and exit when you are finished. If all goes well, the recording will have been saved!

(Note: doing this means that every time you launch this game it will be recorded. To stop it doing this, press the “A” button while it’s launching, choose “Select emulator for ROM” and choose the normal line – in our example that would be “lr-gambatte”.)

Getting the recorded files

To get your recording off the RetroPie, go back to your computer, open a terminal, and type:

scp pi@192.168.0.3:recording_*.mkv ./

This will copy all recorded videos from your RetroPie onto your computer (into your home directory, unless you did a cd commmand before you typed the above).

Now you should delete the files from your RetroPie. Log in to the RetroPie as described in the first section, and delete all recording files by typing this:

Note: This deletes all your recordings, and you can’t undo!

rm recording_*.mkv

Note: This deletes all your recordings, and you can’t undo!

Safer: recording onto a USB stick

Note: recording directly onto the RetroPie like we described above is dangerous because you could fill up all the disk space or corrupt your SD card, which could make RetroPie stop working, meaning you need to wipe your SD card and set up RetroPie again.

It’s safer to record onto a separate USB disk. To find out how, read “Recording to an External Storage Device” in Retro Resolution’s guide.

Lucky Sevens – baron m.

Greetings Sir R-----! This evening's chill wind might be forgiven some of its injurious assault upon me by delivering me some good company as I warm my bones. Come, shed your coat and join me in a glass of this rather delightful mulled cyder!

Might you be interested in a little sport whilst we recover?

Excellent!

This foul zephyr puts me in mind of the infantile conflict between King Oberon and Queen Titania that was in full force during my first visit to the faerie kingdom. I had arrived there quite by accident but fortunately my reputation was sufficient to earn me an invitation to dine at the King's table. That the fare was sumptuous beyond the dreams of mortal man goes without saying, but the conflict between the King and his consort cast something of a shadow upon the evening.

On Share And Share Alike – student

When last they met, the Baron challenged Sir R----- to a wager in which, for a price of three coins and fifty cents, he would make a pile of two coins upon the table. Sir R----- was then to cast a four sided die and the Baron would add to that pile coins numbering that upon which it settled. The Baron would then make of it as many piles of equal numbers of no fewer than two coins as he could muster and take back all but one of them for his purse. After doing so some sixteen times, Sir R----- was to have as his prize the remaining pile of coins.

Share And Share Alike – baron m.

Sir R----- my fine fellow! Come join me in quenching this summer eve's thirst with a tankard of cold ale! Might I presume that your thirst for wager is as pressing as that for refreshment?

I am gladdened to hear it Sir! Gladdened to hear it indeed!

This day's sweltering heat has put me in mind of the time that I found myself temporarily misplaced in the great Caloris rainforest on Mercury. I had been escorting the Velikovsky expedition, which had secured the patronage of the Russian Imperial court for its mission to locate the source of the Amazon, and on one particularly close evening our encampment was attacked by a band of Salamanders which, unlike their diminutive Earthly cousins, stood some eight feet tall and wielded vicious looking barbed spears.

Share And Share Alike – baron m.

Sir R----- my fine fellow! Come join me in quenching this summer eve's thirst with a tankard of cold ale! Might I presume that your thirst for wager is as pressing as that for refreshment?

I am gladdened to hear it Sir! Gladdened to hear it indeed!

This day's sweltering heat has put me in mind of the time that I found myself temporarily misplaced in the great Caloris rainforest on Mercury. I had been escorting the Velikovsky expedition, which had secured the patronage of the Russian Imperial court for its mission to locate the source of the Amazon, and on one particularly close evening our encampment was attacked by a band of Salamanders which, unlike their diminutive Earthly cousins, stood some eight feet tall and wielded vicious looking barbed spears.

On Divisions – student

The Baron's game most recent game consisted of a series of some six wagers upon the toss of an unfair coin that turned up one side nine times out of twenty and the other eleven times out of twenty at a cost of one fifth part of a coin. Sir R----- was to wager three coins from his purse upon the outcome of each toss, freely divided between heads and tails, and was to return to it twice the value he wagered correctly.

Clearly, our first task in reckoning the fairness of this game is to figure Sir R-----'s optimal strategy for placing his coins. To do this we shall need to know his expected winnings in any given round for any given placement of his coins.

On Divisions – student

The Baron's game most recent game consisted of a series of some six wagers upon the toss of an unfair coin that turned up one side nine times out of twenty and the other eleven times out of twenty at a cost of one fifth part of a coin. Sir R----- was to wager three coins from his purse upon the outcome of each toss, freely divided between heads and tails, and was to return to it twice the value he wagered correctly.

Clearly, our first task in reckoning the fairness of this game is to figure Sir R-----'s optimal strategy for placing his coins. To do this we shall need to know his expected winnings in any given round for any given placement of his coins.

Divisions – baron m.

Greetings Sir R-----! I trust that I find you in good spirit? Will you join me in a draught of this rather fine Cognac and perchance some sporting diversion?

Good man!

I propose a game that ever puts me in mind of an adventure of mine in the town of Bağçasaray, where I was posted after General Lacy had driven Khan Fetih Giray out from therein. I had received word that the Khan was anxious to retake the town and been given orders to hold it at all costs.

Divisions – baron m.

Greetings Sir R-----! I trust that I find you in good spirit? Will you join me in a draught of this rather fine Cognac and perchance some sporting diversion?

Good man!

I propose a game that ever puts me in mind of an adventure of mine in the town of Bağçasaray, where I was posted after General Lacy had driven Khan Fetih Giray out from therein. I had received word that the Khan was anxious to retake the town and been given orders to hold it at all costs.

On Turnabout Is Fair Play – student

Last time they met, the Baron challenged Sir R----- to turn a square of twenty five coins, all but one of which the Baron had placed heads up, to tails by flipping vertically or horizontally adjacent pairs of heads.
As I explained to the Baron, although I'm not at all sure that he was following me, this is essentially the mutilated chess board puzzle and can be solved by exactly the same argument. Specifically, we need simply imagine that the game were played upon a five by five checker board...

On Turnabout Is Fair Play – student

Last time they met, the Baron challenged Sir R----- to turn a square of twenty five coins, all but one of which the Baron had placed heads up, to tails by flipping vertically or horizontally adjacent pairs of heads.
As I explained to the Baron, although I'm not at all sure that he was following me, this is essentially the mutilated chess board puzzle and can be solved by exactly the same argument. Specifically, we need simply imagine that the game were played upon a five by five checker board...

Turnabout Is Fair Play – baron m.

Why, you look chilled to the bone Sir R-----! Come sit by the hearth and warm yourself whilst I fetch you a medicinal glass of brandy.
To your very good health sir! Will you join me in a wager whilst you recover?

Good show!

I propose a game that I learned upon the banks of the river Styx whilst my fellow travellers and I were waiting for the ferry. This being the third time that I had died, I was quite accustomed to the appalling service quality of the Hadean public transport system and so was most appreciative of a little sport to pass the time.

Turnabout Is Fair Play – baron m.

Why, you look chilled to the bone Sir R-----! Come sit by the hearth and warm yourself whilst I fetch you a medicinal glass of brandy.
To your very good health sir! Will you join me in a wager whilst you recover?

Good show!

I propose a game that I learned upon the banks of the river Styx whilst my fellow travellers and I were waiting for the ferry. This being the third time that I had died, I was quite accustomed to the appalling service quality of the Hadean public transport system and so was most appreciative of a little sport to pass the time.