The other day my son and I were at a friend's house, and we were
just on our way home. As we were leaving he saw they had the game
Connect 4
and asked if we could play. Since we were on our way I told him,
"We can't play the game now, but when we get home, we
can program the game, and then play that." I wasn't sure
exactly how this would work out, but I thought we'd have some fun
on the way.

This isn't the first time I've adapted a physical
game to a program with my kids. But since then I've
done mostofmygames using
LÖVE, the 2D Lua game framework
along
with Polywell,
a text editor and development tool that runs in it. Polywell is
roughly a port of Emacs, and I've found that the foundation it
provides of buffers, modes, and keymaps is useful for all kinds
of games. As a bonus, you can use the text editing features of
Polywell to code the game from within the game itself,
which makes experimentation and reloading seamless.

My son and I sat down and knocked out an implementation of
Connect 4 pretty quickly using Polywell, and I thought it would be
interesting to step through how it works since it can serve as a
very succinct explanation for how to use Polywell.

State and Drawing

We start out by loading "polywell" and putting it in
the e local (e for editor). Most of the
game state is in the board table[1], which has an empty
table for each column in it. The Connect 4 board has seven columns
in which pieces can be dropped. It's a bit unusual, but we
represent columns as lists of pieces from the bottom up, because
the tokens are subject to gravity and fall to the bottom of the
column they're placed in. Finally we set up colors
which maps each player's color name to an RGB triplet and store
the final bit of state (the current turn) in the turn
local. So far so good!

Our draw function is very natural once you understand
the unusual structure of the board; we simply loop over
each column with an inner loop over each piece in the column. The
piece is represented by n, its numeric position within
the list of pieces, and its color. We
calculate x and y from the col
and n respectively and draw a colored circle for each
piece from the bottom of the column upwards. This is basically the
only place we use the LÖVE framework directly.

Modes and Bindings

e.define_mode("connect4", nil, {draw=draw, read_only=true})

Using Polywell's define_mode function we create a
"connect4" mode which will contain all the key bindings for the
game. Modes in Polywell are assumed to be textual unless otherwise
specified, but since our game is graphical we pass nil as
the second argument because our mode does not inherit from any
existing mode. For our third argument, we pass in our
previously-defined draw function as the
mode's draw property, overriding the default draw which
simply displays the current mode's text. We also mark it
as read_only to avoid accidentally inserting any text
into the buffer.

Polywell's bind function allows us to attach a function
to be called when a specific keystroke is pressed in a specific
mode. In this case we say that escape will switch back to
the Lua console while backspace will just clear each column in
the board.

Almost done! Here's where the meat of the game is. We loop from 1
to 7, which is the number of columns in the game. For each column,
we bind that number key to a function which grabs the
corresponding column table from the board. It
checks to make sure the column isn't full (each one can
only hold 6 pieces) and if not it inserts the color of the current
player into the column with table.insert. Then it
changes the turn to the next player.

e.open(nil, "*connect4*", "connect4")

Finally it uses the open function to create a new buffer
named "*connect4*" with "connect4" mode
active. The first argument is nil because this buffer is
not attached to the filesystem; it's a free-floating thing that
doesn't get loaded or saved. You could leave this line out and
Polywell would simply boot to a Lua console where you could
invoke connect4 mode manually from there.

And that's it! 27 lines is all it took, and me and my son were
off to the races playing the game. While we were writing it I kept
him involved by asking each step of the way what we should do
next. Once I wrote the draw function we were able to test
it out by editing the board table directly using Lua code
in the console. Our first pass of the number key function simply
called table.insert, so once we tried it out he was able
to point out which features were still missing, and I could ask
leading questions which helped him piece together roughly what was
needed to address those things.

Of course there's a lot more that Polywell can do, but it doesn't
take much code to get a simple game going. Try it for yourself;
you might have a lot of fun.

[1] Lua tables can be a bit confusing since
they're a single data structure that can act both sequentially (as
with board here which is basically used as a vector/array) or
associatively (as with colors which acts like a map). The
thing to remember is that the sequential/associative property is
not inherent in the table but rather part of how it's used.