One moment please, while I arrange the galaxy

PET Star Trek screengrab

In 1977, the second computer I ever used was my dad’s Commodore PET 2001. This massive, sphinx-like machine of bent-steel with its terrible calculator keyboard, built-in cassette drive and ghostly white CRT monitor surrounded with a slightly IBM-ish shade of blue plastic sat in my dad’s radio shack, a small spare room upstairs in our bungalow. Yes, I know bungalows don’t have upstairses. Ours did.

Commodore PET

Ostensibly bought for business purposes, this machine with 8K of RAM was mostly used by me for playing, and occasionally writing, games. The two games I spent longest on were an insanely good and mysterious Space Invaders clone, possibly Japanese, written in machine code to add to its mystique. The other was Star Trek.

The original 60s Star Trek re-ran constantly on BBC TV in my childhood, and I loved it, so this game was instantly addictive.

There were a lot of Star Trek games around in the 1970s. I probably didn’t know this at the time, but they originated on mainframe computers in the early 70s, a version by Mike Mayfield in HP BASIC became popular, especially when it was modified up by David Ahl and published in 101 BASIC Computer Games in 1975 and Basic Computer Games in 1978.

These are mostly text-based games designed to be played over a teletype terminal: you type instructions and you get a printout. Typically you’d explore a galaxy of 8 x 8 quadrants, come in peace and shoot to kill Klingons as you find them. Different commands allowed you to see a grid printout of the quadrant you’re in, a longer range scanner to see a numerical representation of adjacent quadrants (how many stars, Klingons and bases) and a computer map of quadrants you’ve explored.

giles-surias-may81

This PET Star Trek was a bit different though. It had fewer instructions, and a pretty good attempt had been made to adapt it to the PET. It wasn’t just a text game. When you move, the ‘E’ for Enterprise was animated. Same for firing torpedoes.

I recently had a hankering to play this game again, and maybe translate it to Python. So I managed to track it down, and get it running in the VICE Commodore emulator on my MacBook. All good. But then a few odd things happened.

Stranger things

As I mentioned, there are a LOT of versions of Star Trek out there, and it took me a bit longer than I expected to find the one I remembered, even when searching Commodore sites. There’s a lot of stuff on the Commodore 64, understandably. Not so much on the PET. And when I went digging for the origins of the version I played, I hit a brick wall. Sites about BASIC Star Trek games of the 70s are old, rare and frustratingly full of dead links.

No prior or contemporary version of the game was quite like the PET Star Trek. It seems to have come out of nowhere.

So I looked at the program listing, initially thinking about my Python translation. On screen it’s an impenetrable fog, even though it’s written in BASIC. My programs were always well-spaced and easy to read, but I guess to save memory, this one has multi-statement lines and every strictly unnecessary space is omitted:

146 gosub63500:fori=1topd/3:poke59464,100:poke59464,140:next:gosub63600

This soup of pokes to memory to store numbers, opening channels to the CRT, and opaque bitwise AND and OR operations, all totally uncommented, makes it very hard to reverse engineer and translate. I decided I’d be better off recreating the game from scratch knowing what I do of the gameplay. But its very complexity, and intimate relationship with the hardware, suggests the author knew the PET very well indeed.

So who wrote it?

I looked at the listing again. There was one REM statement only:

1 REM SOUND&PROG.MODS: DUNCAN LANGFORD

It seems Duncan Langford may have been a Computer Science fellow at the University of Kent many years ago, but I’ve not been able to track him down so far. But he only added sound to it, who actually wrote it?

Memo to future self

I needed a proper program listing in a text file to study the game in more detail, so I decided to export one from the VICE emulator. Oh brother, little did I know what fun that would be. It took me an entire evening, at least 4 or 5 hours to get it to work. Indulge me for a moment, but the internet needs this recording. I need it recording when I forget and have to Google my own answer.

If you have a Mac and VICE 3.5 and you want to get a text file dump of a program listing, strap in and pay attention. this is what you need to do.

printing dialogue from VICE

In VICE, go to settings, peripherals, printer #4.

If it was already enabled, you must first disable printing by setting emulation type to none, then close the dialogue and re-open it. It took me literally hours to figure that out.

Then choose File system access, ASCII, text, output device #1 (print.dump)

In the emulator type

OPEN4,4
CMD4:LIST
PRINT#4:CLOSE4

Close emulator. You’ll find the listing in a print.dump file inside the app!

So right-click on VICE.app > Show package contents > Contents > Resources > print.dump and open it in your text editor of choice. And save it somewhere sensible.

Oh, I also ran the emulator at the command line with sudo open xpet.app – no idea if that was necessary but I was waving all the dead chickens by the time I got it working.

The hidden REM

It was gone 1am by now, so flushed with success I went to bed and it wasn’t until the next day I started to study the code. And I found something very odd. There was a second REM statement. One you can’t see when you list the program on a PET or in the emulator. A secret, hidden REM statement! I had no idea such things were possible.

11 rem"property of leonard tramiel .....................................

The name Tramiel is instantly recognisable to anyone who knows anything about the history of Commodore computers. Jack Tramiel (1928-2012) was a Polish Holocaust survivor who eventually settled in the US and founded Commodore. I discovered Leonard is his son, who is best-known for his work at Atari, but around this time, Leonard was working for the family firm. Did Leonard write this version of Star Trek? Was it merely from his personal collection, and he fingerprinted it, so if copies turned up anywhere he could trace them back to his original tape?

I’m still digging, and I’m very grateful to anyone who can help me track down Leonard or Duncan Langford. I’ll post any updates here.

In the meantime, I’ll be roaming the quadrants in search of a wasted youth.

ONE MOMENT PLEASE, WHILE I ARRANGE THE GALAXY

2022 update: Python port

I’m working on a Python port of the classic Commodore PET Star Trek so I can play it in my laptop’s console. It’s a fork of a Python translation of a C# port of the 1976 Super Start Trek BASIC game, so I’m gradually stripping out functionality and making it work more like the PET version which was optimised for a CRT with crude graphics, rather than a teletype console.

Source code is here: https://github.com/blogmywiki/pet-python-startrek

And you can play an early version of it in your browser here: https://trinket.io/python/38adc68043

July 2023 update: contact with Leonard Tramiel!

I am very grateful for Colin Haynes who contacted Leonard Tramiel for me on the Commodore International Historical Society Facebook group. This is what he said: “That’s a long time ago. I know I played a version of that game. I probably wrote one at one point but it wouldn’t have been an actual completed version. I have no idea how my name wound up in there.”

So the mystery remains!

Posted in computers, gaming, nostalgia | Tagged , , , , | Leave a comment

Simple machine learning abstraction for kids

Update: this also works on a BBC micro:bit, scroll down to find out more!

There are some great resources for teaching machine learning to kids, but I’ve noticed a lot of them rely on some magic happening in the cloud, or the code or training model is really complex, or they’re quite hard for a teacher to set up and explain.

This probably isn’t an original idea, but see what you think.

I made a really simple abstraction of what machine learning is: training a machine with data to do a task that a human would normally do.

In this case I’ve picked the task of teaching a machine number bonds to 10.

Number bonds are fundamental building blocks of maths that should be familiar to any school student: you learn early on to recognise what numbers you need to add to a given number to get to a round figure. For example:
1 + 9 = 10
2 + 8 = 10
70 + 30 = 100
and so on.

Here a simple Python program has an array 10 digits long to store its training data. Position 0 in the array holds the number bond for 0, position 1 holds the bond for 1, and so on.

We start by setting them all to 5, somewhere in the middle. The program generates random number between 0 and 9 and tells us what it thinks the bond to 10 is for that number. It also keeps score of right and wrong answers, and then we, the humans, get to have a go. When we give a correct answer, the program improves its training data not by changing its answer to ours – we might be wrong, and different people could be playing the game – but by taking an average of its existing answer and our new one. This means students can see the process gradually unfolding, and watch the training data get better over time.

So gradually you can see the machine’s answers getting closer to the correct ones. When you think it’s learned all or most of its number bonds to 10, you can reset the scores by typing ‘reset’ which keeps the training data in the array but allows us to have a game on something like equal terms.

A few things to note: the array holds averages that aren’t integers, for example it could hold 2.5 as a number bond, but the program rounds it using the Python round() function when displaying it and using it as an answer. This is to speed up the process a bit without making it too quick. You might want also to look at rounding numbers in Python, which is a whole other topic but potentially crucial for data science work. This seems like a good primer: https://realpython.com/python-rounding/. In short: rounding numbers in Python probably doesn’t work the way you think it does or should!

You might want to tweak the code so the training data can learn from incorrect answers as well, I’d love to know if you try that and if misleading the machine could be a sneaky strategy to beat it, albeit missing the point of the exercise entirely. In my experience, at least one student would do something like this.

Have a play with it, let me know what you think. Does this help explain ML in a simple way? What other examples can you think of?

Download the code here, read it below or try it out in Repl.it

# Simple machine learning example for kids by Giles Booth @blogmywiki
# https://youtu.be/h-Arrtg6x7c

# using decimals not integers so we can see it improve, thanks @veryalien!
bonds = [5.0,5.0,5.0,5.0,5.0,5.0,5.0,5.0,5.0,5.0]
import random
human_wins = 0
machine_wins = 0
turns = 0

print('Train a machine to learn its number bonds to 10!')
print('If I give you a number, you tell me what you add to it to make 10')

while True:
    number = random.randint(0,9)
    print()
    print(bonds) # added so you can see it improve its data set
    print('Number is ' + str(number))
    print('Machine says the bond to 10 is ' + str(round(bonds[number])))
    if number + round(bonds[number]) == 10:
        print('Machine is right!')
        machine_wins += 1
    else:
        print('Machine is wrong, more training data needed.')
    human_answer = input('Give me your answer 1-10: ')
    if human_answer == 'quit':
        break
    elif human_answer == 'reset':
        human_wins = 0
        machine_wins = 0
        turns = 0
    elif number + int(human_answer) == 10:
        print('Correct!')
        human_wins += 1
        bonds[number] = (bonds[number] + int(human_answer)) / 2
        print('Now machine thinks it is ' + str(round(bonds[number])))
    else:
        print('Wrong! Are you trying to mislead a poor machine?')
    turns += 1
    print('Human score ' + str(human_wins) + ' out of ' + str(turns))
    print('Machine score ' + str(machine_wins) + ' out of ' + str(turns))

Scratch version for younger students

If you’d like to try this with younger students, elfwoo is recreating this game in Scratch. Check it out!

Run it on a BBC micro:bit

This program will run unmodified on a BBC micro:bit in a serial console, or you can download this version that adds some sound and LED images. The video above explains more.

Posted in computers, education, microbit | Tagged , , , , , , | 5 Comments

Easy new OLED driver for the micro:bit

I love OLED displays! The 128×64 pixel ones are really cheap and easy to interface with a BBC micro:bit, Arduino or Raspberry Pi.

Here are a few things I’ve made with them:

One thing that’s been missing is a really good micro:bit driver or MakeCode extension for OLED displays.

The good folk at Kitronik have just released a new product, a micro:bit OLED display board. The good news is, their MakeCode extension also works with the cheap OLED displays I have lying around. (I’ve not tried the Python modules yet, but will do).

OLED display connected to micro:bit

It’s possible some other displays will have different I2C addresses, so you may need to tweak the code of the extension, but I was pleased to find mine worked with no changes.

This means you can use them with an OLED connected to a micro:bit’s I2C pins via a breakout board and 4 female-female jumper wires.

A couple of things I really like about their extension:

  • The text is small so you can get a useful amount of stuff on the screen
  • The ‘plot’ block, which is more useful than it sounds – it’s a really simple way of drawing live graphs of sensor data with a number to show the current reading. The graph even scrolls when it gets to the end, a lovely touch.

You can load Kitronik’s MakeCode extension pasting this URL into MakeCode: https://github.com/KitronikLtd/pxt-kitronik-128x64Display

Here’s just how simple the code is to put some text, a light reading number and plot a live graph using the Kitronik extension:

MakeCode blocks for plotting graph

If you don’t already have a breakout board and OLED display to hand, the Kitronik accessory just snaps on to your micro:bit’s edge connector, and leaves other pins free for connecting more goodies, which is an excellent feature. It’s currently £13.80 including VAT, which seems like a very reasonable price point for a well-supported accessory – though I must say I’ve not actually tested the Kitronik board itself, just their MakeCode extension!

Posted in computers, microbit | Tagged , , , | Leave a comment

Adventures in Arduino TinyBASIC

I’ve been watching Wifi Sheep’s Arduino simple BASIC computer builds and this cool little project using LCD and OLED displays with interest, and I thought I might have a go at building something similar myself with parts I have lying around including an old PS/2 keyboard I found on the street, an Arduino UNO and a Pro Mini I bought for the KIM-1 clone project but never used.

PCC magazine article September 1975 on TinyBASIC

As a language, TinyBASIC may be ‘awful’ as someone told me, but it has an interesting history. It stemmed from a challenge made in the September 1975 issue of the People’s Computer Company magazine (later better known as Dr Dobb’s Journal) to write a simple, free version of BASIC. Around this time two dudes called Bill and Steve were getting annoyed at people illegally copying their new MicroSoft BASIC, and TinyBASIC was written to give people a free, legal, ‘copyleft’ alternative. I really recommend browsing old issues of PCC magazine, there are some great articles in there some of which are still relevant today. (I was also inspired by reading about the origins of TinyBASIC to create my own ultra-simple text-based language for the BBC micro:bit.)

You can run Tiny BASIC on a BBC micro:bit, but for this project I decided to make some Tiny BASIC computers using some Arduinos to see if I could make a standalone computer with keyboard and display.

I used this project from a few years ago by Rob Cai as the basis. Like the Wifi Sheep computer, it uses two Arduinos, one to handle keyboard input and run TinyBASIC, and the second to act as a kind of video card generating surprisingly hi-res video using the MRETV software. It turned out I had almost all the components I needed to build this, except some diodes. So while I was waiting for the diodes to arrive in the post, I pondered alternative output devices…

It occurred to me that I have a serial thermal printer, and I could maybe use that as an output device, a bit like the old Rockwell AIM-65 computer from 1978. And it sort of worked! I just changed the baud rate in the Arduino program running TinyBASIC to 19200 baud to match the printer, and connected the TX pin of the Arduino to the RX pin of the printer. As you can see from the video, I still needed a serial console on a laptop so I could see what I was typing, and the last line of text output was hidden by the printer case, but it basically worked.

I got thinking about some kind of hybrid computer with an LCD or OLED display for text entry and showing what you’re typing, and a thermal printer for hard copy and program output. I couldn’t be bothered to solder up pins to my spare Arduino Pro Mini, so I decided to see if I could use a micro:bit instead to drive an OLED display. The micro:bit is great for quick prototyping – no soldering required and it’s a breeze to program in MakeCode or Python rather than C++ used by the Arduino.

First I had to do some level shifting: the Arduino works at 5v and the micro:bit at 3v, so I used a 1K and 2K resistor as per this guide to make a voltage divider, dropping 5v to just over 3v so I didn’t damage the micro:bit. So, the serial TX pin of the Arduino is connected to a 1K resistor, the other side of which is connected to Pin 1 on the micro:bit and also to a 2K resistor which goes to ground. It’s a very crude level shifter and it may explain why I had to reduce the baud rate, but it does seem to do the job. The grounds on the micro:bit and Arduino are linked, and I back-powered the micro:bit from the 3.3v pin on the Arduino UNO. I also used a MonkMakes I2C breakout board to connect the OLED display to the micro:bit and used two Python libraries ssd1306.py and ssd1306_text.py to drive the OLED display.

As you can see that was a bit flaky, but slowing the baud rate down to 1200 and adding some delays at the start of the Arduino TinyBASIC program worked a treat:

All good fun and confirms the idea is sound, but alas the text is too big and the display too small, so my next step will be to replace the micro:bit with an Arduino that can print smaller text on an OLED display – or maybe even a 4 line LCD display? And if that doesn’t prove workable, then I just may well fall back on making a machine that has an old-fashioned composite video output!


FYI, the current version of my micro:bit Python program looks like this. It just polls pin 1 for serial data and prints anything it receives on the OLED display. If it gets confused it shows a ‘?’ on the micro:bit’s LED display.

from microbit import *
from ssd1306 import initialize, clear_oled
from ssd1306_text import add_text
import micropython
# baudrate was 19200 for thermal printer
uart.init(baudrate=1200, bits=8, parity=None, stop=1, tx=None, rx=pin1)
micropython.kbd_intr(-1) # disable accidental keyboard interrupt

initialize()
clear_oled()
x = 0
y = 0

while True:
    if uart.any():
        msg_bytes = uart.readline()
        msg_str = str(msg_bytes, 'UTF-8')
        if len(msg_str) > 0:
            try:
                for char in msg_str:
                    if ord(char) > 31:
                        add_text(x, y, char)
                        x += 1
                        if x > 11:
                            x = 0
                            y += 1
                        if y > 2:
                            y = 0
                            clear_oled()
                        if x < 0:
                            x = 0
                        if y < 0:
                            y = 0
                    elif ord(char) == 13:  # new line / CR
                        x = 0
                        y += 1
            except:
                display.show('?')

Update 1 - adding a 2nd Arduino with an OLED display

Despite hating soldering so much previous me hid my solder from myself in the loft, I've made progress replacing the micro:bit with a cheap Arduino Pro Mini clone driving the OLED display with a smaller, and hence more useful, font.

TinyBASIC on an OLED display

I just connected the serial TX pin on the Arduino UNO running BASIC and polling the keyboard to the serial RX pin on the Arduino Pro Mini that's driving the OLED display. Despite my truly awful soldering of pins on the Pro Mini, it works!

Here's the wiring for the OLED on the Pro Mini:

Arduino > OLED
--------------
Pin 4   > SDA
Pin 5   > SCL
VCC     > VCC
GND     > GND

The Pro Mini doesn't have a USB adaptor, so you need something like an FTDI adaptor to bridge between the Pro Mini and a computer running the Arduino IDE. My adaptor needed 2 extra pins soldering (CTS and RTS) and I had to figure out what they connected to. In the highly unlikely event anyone has the same FTDI adaptor and is wondering how to connect one to a Pro Mini, here's the wiring you need:

Pro mini > FTDI adaptor
-----------------------
DTR      > RTS (data terminal ready > ready to send)
TX       > RX
RX       > TX
VCC      > 5v
GND      > GND
GND      > CTS (clear to send)

You'll also need to disconnect anything from the Pro Mini's serial input before you flash a program or it won't work. Also make sure that you have the correct voltage FTDI adaptor - mine has jumpers that allow you to select 3v or 5v, I've selected 5v as I have a 5v version of the Arduino Pro Mini.

My FTDI adaptor

My FTDI adaptor with 2 extra pins soldered

Here's the Arduino program I wrote to put text received on the serial port on the OLED display. It uses the Adafruit SSD1306 library. Note that I had to change the I2C address from the Adafruit code example to 0x3C for my display, and if you try this you may also need a different number. Also it's still using the very slow serial transfer rate of 1200 baud I was using with the micro:bit, which almost certainly could be speeded up.

#include <Wire.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

int incomingByte = 0; // for incoming serial data
int x = 0;   // counters for working out rough cursor position to clear screen when full
int y = 0;

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

void setup() {
  Serial.begin(1200);

// you may need to change 0x3C depending on your type of OLED display
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println("SSD1306 allocation failed");
    for(;;);
  }
  delay(1000);
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.display();
  display.setCursor(0, 0);     // Start at top-left corner
  display.cp437(true);         // Use full 256 char 'Code Page 437' font
}

void loop() {
  if (Serial.available() > 0) {
    incomingByte = Serial.read();
    display.write(incomingByte);
    display.display();
    ++x;
    if (x == 20) {
      x = 0;
      ++y;
      }
    if (incomingByte == '\n') {
      ++y;
      x = 0;
      }
    if (y == 8) {
      display.clearDisplay();
      display.setCursor(0, 0);
      y = 0;
      x = 0;
    }
  }
}

Update 3 - video out

I think the best solution for this project would be a 256 x 64 pixel OLED display driven by an Arduino. They cost around £27, compared with less than £5 for a 128x64 OLED, but as someone pointed out to me on Twitter, a wide OLED would have similar dimensions to a Radio Shack TRS80 Model 100, which is exactly the vibe I'm aiming for.

video output from Arduino computer

So, before I get one of those, I decided to see how the video out version in Rob Cai's original project worked. It was amazingly simple to make. I removed the OLED display and repurposed the second Arduino as a 'video card'.

First I added the MRETV library to the Arduino IDE as per his instructions, then I flashed Rob's TVtext_slave.ino file to my second Arduino. I found 1 typo in this file I had to fix. The line
#include <MrETV.h>
should read
#include <MRETV.h>
(capital letter R).

As per Rob's guide, I connected pin D2 on the Arduino via a switching diode to a 1K resistor. The other end of the 1K resistor is connected via a diode to TX pin 1 on the Arduino. Where the two resistors join, I tapped off a wire that goes to the centre pin on an RCA / phono plug that provides the video out. Connect this plug to the composite video input of a TV.

I've not connected the sound yet, so I'll do that next then see if I can improve the keyboard mapping, maybe wire up a reset button and investigate if I can get a delete key working. And maybe even see if I can modify the font!

I've also been messing about with KiCad for the first time, and I think this is what Rob Cai's circuit looks like:
schematic of computer with 2 Arduinos

Posted in Arduino, computers, microbit | Tagged , , , , | Leave a comment

micro:bit NIM maths and computing investigation

NIM is a simple but potentially infuriating, ancient 2 player game. You have some counters or matchsticks, you’re allowed to take a limited number in each turn, say 1, 2 or 3. The winner is the person who takes the last counter.

Sometimes it’s played the other way round, so the player left with the last counter loses. This is called a misère game, but there’s enough misère in the world as it is, frankly, so we’ll play the happier version of the game today.

Thinking about this game makes a great maths investigation, and it can be a good computing activity too. Challenge your students to write a program that will play and beat a human, or modify and improve the programs I’m going to show you in this video.

As you can learn a simple trick to always win NIM, it also makes a great game to annoy people with, as Matt Parker of Stand Up Maths shows in his superb video about the game and a 60s American plastic computer version of it. Watch his video, just as soon as you’ve finished watching this. He and his colleagues also played this game with members of the public on the South Bank in London, using pegs and trying to get people to win £20 off them, which they could never do.

The wonderful folk at the NRICH project at the University of Cambridge have written up a lovely simple version here: https://nrich.maths.org/1204

I used to use NRICH games and resources a lot when I was teaching primary school maths, I highly recommend them for creative maths investigations.

Back in the 1970s there was even a version of NIM for the Sinclair Cambridge Programmable calculator. You can read a bit about that elsewhere on my blog.

Anyway, I decided to see if I could write a BBC micro:bit program so that the micro:bit could play a human at NIM and always win. Perhaps you could challenge your students to do the same and see what they come up with – can they identify winning strategies, and abstract them into a working computer program?

I approached this challenge by taking the really simple NRICH example and applying Matt Parker’s strategy from his Dr Nim video.

The key here is to think of the end game and the position you want to get your opponent into.

In the Dr Nim game Matt Parker shows in his video, you have 12 marbles and can take 1, 2 or 3 counters in each turn. So he chunks the game into multiples of 4.

In every go, whatever you take, Dr Nim will take whatever number he needs to make sure you’ve taken 4 between you.

oooo / oooo / oooo

So if you take 1
oooo / oooo / ooo

Dr Nim will take 3.
oooo / oooo /

If you take 2
oooo / oo

he’ll take 2.
oooo /

If you take 3,
o

he’ll take 1 – and win!

Now, we’re computer scientists so we always want to abstract some kind of pattern if we can, to make any coding more efficient, so straight away I notice that if the human takes n counters, Dr Nim takes 4-n counters.

Also I notice that with the option to take up to x counters, you want to break down into chunks of x+1, so that if your opponent goes first, you always have the advantage. You want to make sure they always have x+1 counters at some point when it’s their turn to go.

Hold that thought! We’ll come back to it later.

So, back to our micro:bit version of the game. I’m going to follow the NRICH example and say you can only take 1 or 2 counters in each turn, but I’m going to start with 9 counters instead of 7.

This simple version is easier to think about, work out all the permutations, and easier to code. Also we can use micro:bit button A to take 1 counter, and button B to take 2 counters, so we’ve got a nice simple user interface.

So I coded a version for the micro:bit. Try and beat it:

You could play many more games, and trust me the micro:bit will always win.

So how does it work?

Remember Matt Parker with his 12 marbles or pegs which he treated as 3 lots of 4? Well he had sets of 4 because the choices were to take 1, 2 or 3. The chunk you’re working with should be one more than the highest number you can take in a turn.

We can only take 1 or 2 counters in our micro:bit version of the game, so we’ll treat it as three lots of three:

ooo / ooo / ooo

We’ll make the sap, sorry the human, go first. Remember, in a pair of turns, we need to make sure the human and machine have taken 3 counters between them.

Each time, if the human takes 1 counter…
ooo / ooo / oo
our program will take 2:
ooo / ooo /

If they take 2
ooo / o
the program will take 1:
ooo /

As there are only two choices at each turn, we can hard code this into blocks that follow each button press:

Simple micro:bit NIM game

Here we use a function to update the display and check if the game’s over. I added a bit of logic to show different messages depending on whose turn it was when the last counter was taken, though with these numbers, the ‘you win!’ message will never be displayed. Try altering the number of counters you start with and see if that makes a difference. Does the program still work?

Main part of the code

Now, do you notice anything about these two sets of code?

They are very similar! There’s a pattern here, and when computer scientists spot patterns, they get all excited because there’s an opportunity to be clever and make the code more compact.

We do that in this new version of the project by creating a function that does the same work, just slightly differently depending on how many counters the human took.

Clever version of the NIM code

Remember that formula 4-n earlier? I spotted that in Dr Nim, if the human takes n or marbles, Dr Nim would always take 4-n marbles and be guaranteed to win, because that game works in blocks of 4 counters.

I kind of use that here.

The variable humanGo keeps track of how many counters the human player took.

We set the number for the computer to take, by using 3-n. Our game works in blocks of 3, so we set the computer’s go to be 3 (or minus 3 here) minus the human go.

Why is it minus 3 here not 3? I’m using negative numbers here just to make the block simpler when we change the total number of counters, stored in the counters variable. MakeCode doesn’t have a block to change the sign of a number. Well, not yet. I’ll have to see what I can do about that. I’ve managed to sneak at least one new block into MakeCode, possibly even one used in this project, it’d be fun to have another one to call my own.

So this version of the code works in exactly the same way, it’s just a bit more efficiently coded. It’s cleverer, using a function to avoid repeating two very similar sets of code.

But is it easier to read, follow and understand?

Probably not. This is something that would make a great discussion point with a class of students. Which version of these programs is ‘better’? Which is easier for someone to come along and understand and modify, or if you yourself look back at your own code months or years later and wonder how on earth you wrote it and what it does?

The first one makes it very easy to follow what happens in each case. But if you want to adapt this to play a more complex version of NIM, say with 12 counters and the ability to take 1, 2 or 3 at each turn, the version with the clever function is probably going to be more adaptable.

Have a play with these, and if you adapt my code to make a more advanced game of NIM, please let me know. You could use shake gestures, wire up 3 tin foil buttons to the pins, or use the touch logo on the new micro:bit (V2) to get more button inputs for more choices.

Like the Dr Nim game in Matt Parker’s video, perhaps you can create an ‘equaliser’ mode where the poor human player has at least a chance of winning?

Have fun annoying your friends and relations with your unbeatable NIM micro:bit machines!


Oh, and here’s that Matt Parker video on Dr Nim:

Posted in education, microbit | Tagged , , , , | Leave a comment