Code-forward Othello

Mark Bastian gave a thought provoking talk at the Conj about bottom up design. It triggered interesting conversations with my friends. I venture to say Mark exaggerate the top down object oriented approach, and I liked that he did, because it allowed me to think about the contrasts more concretely. One of my friends commented that it would be interesting to see how he would design his game if it had to support multiple rules. I thought it would be an interesting screencast... and have been wanting to show some devcards dual build usage for a while. So here it is, Tic Tac Toe to Othello: https://youtu.be/7fYmxt29Id4

Watch: Screencast (24 minutes)

Play: Game
Read: Code


Write: Another board game? Go? Checkers?


Transcript of screencast:


CoderX here.

In the last screencast we setup a ClojureScript project,
implemented a tic tac toe game, and published it online.
Today I want to show you how to work with a larger codebase.
We are going to convert our tic tac toe game into Othello,
focusing on our workflow along the way.

Othello is played on an 8 by 8 board with black and white discs.
Each player places their discs in such a way as to capture the opponent's discs.
When placing a disc, opponent discs that become surrounded are captured.
Captured discs are converted to the capturing player's color by flipping them.

Before we get coding let's add testing feedback to our workflow.
Don't worry, this won't be the boring style of testing you may be expecting!
But it will take some setup to get going.

First add a dependency to our project.clj
Devcards is a library that showcases our components in various states.
Copy the dev build section to create a devcards build.
Give it a different output directory,
so that the compiled files do not collide with other builds.
Create a devcards.html file,
Copy and paste the contents from the devcards README on github.
Start the new build we configured by typing:
`lein figwheel devcards`
Open localhost:3449/devcards.html
Seeing this page indicates that everything is working so far.
In the core.cljs source file, add devcards to the namespace require.
Refer the `defcard` macro.
Now define a card with some text in it.
The text can contain markdown; you can create titles and even format code.
Refer deftest from devcards instead of test.
See how our existing tests are now rendered into the page.

Failing tests are colored red.

Instead of `defcard`, we will be using a more specific version `defcard-rg`
which renders reagent components.

We can define a card that shows a single piece of the board in a given state.

Now we can isolate a single component to work on,
instead of having to observe the entire application.

We need a little more space here...
Let's show our existing pieces,
and adjust the sizing.

O.K. let's make some discs.

We'll use blue instead of white for now so that we can see the disc on a white background.
We need to pass the coordinates to place them in the right location.

Now we need a green background.
Let's copy the existing blank piece but make it green.
And the put blank pieces behind our discs.
That looks about right.
Let's parameterize the blank component so that it takes the background color.
We'll add an argument, but keep a default of grey if only 2 parameters are passed.
Does it work if we pass red?
Yes, great!

Let's make a card with a complete board.
We don't need the title and button, so let's extract just the board.

We'll change our convention slightly so that blank cells on the board are represented with a space,
then we can use a B for black disc and W for white disc.
Update the render cases to default to a blank.
The top left nine positions are currently being initialized to B,
because that was our tic tac toe starting condition.

Let's make a function to create a `new-othello-board`.
An Othello game starts with four pieces in the center in a diagonal configuration.

Now we will add another card to show the tic tac toe game.
We need to update `new-tictactoe-game` to use space instead of B.

Notice that we now have two cards that show the same component in two different states.
Adding cards and tests reduces our time spent clicking through the application while developing.

Our blank cells don't do anything when clicked,
because they are modifying the global app-state.
We'll make them update the state passed instead.

There is quite a bit of logic in this click handler, let's extract that into a function.
We'll need to pass a game atom through, so that it can be modified.
Checking the console for errors reveals that we forgot to pass an atom to our original card.
We can use an empty map atom for those, as they need not respond to clicks.

Our game atom needs a status, because we prevented further moves after a win or draw.
Great, we can now click on the tic tac toe board and see the game progress.
When we click on the othello board, we are still using tic tac toe rules.

It is time to implement the othello rules.
The objective in othello is to capture the opponent's discs by surrounding them.
Here are the valid moves white can make in response to my move.

Let's start with detecting which cells positions are valid moves.
And placing a disc instead of a naught.
To preserve the tic tac toe rules we need two separate logic paths that dispatch on the game type.
Multimethods are a good way to express this.
You can think of multimethods as case statements as functions.

`defmulti` declares a name and the dispatch function.
`defmethod` declares a function to call for a dispatch value.
`defmulti` needs to have the same signature as the methods.

To start with, let's constrain the othello `can-move?` function to cells that are adjacent to a white disc.
To dispatch by type, we need to give our games a type.
Let's convert our `new-board` function into a `new-game` function,
returning a map containing the game type, status and board.

Oh no, something went wrong:
`Uncaught Error: 4 is not ISeqable.`
Expand the stacktrace by clicking the triangle at the start of the error message.
Scan down the stacktrace to the 4th row:
`tictactoe$core$available_QMARK_` Means in the namespace `tictactoe.core`, in the function `available?`
`@ core.cljs?rel:96` is the filename and line number.
:96 tells us the problem is on line 96 of our core.cljs source file.
The line above indicates that the problem occurred when calling `get-in` from the ClojureScript core namespace.

Ah yes, get-in is expecting a vector containing i and j. Fixed.

Player moves are limited now, but we still need to apply the same restrictions to the computer's moves.
Let's rearrange a little so that we can call the same function from `computer-move`.
Put the `board-size` inside the game.
And the `background-color`.
After these changes, the board-size is not coming through to the `game-board`.
Aha... `game-board` takes an atom, so we need to dereference the atom to pull out the values we are interested in.
But the computer is still not making moves.
Let's print out what `can-move?` is doing...
That all looks fine.
Aha... we should be updating the game board here.

We can make `computer-move` more generic.
Convert `can-move?` to return the game that would result from the move.
Now `computer-move` is just the first successful result of `can-move?`,
when examining cells in a shuffled order.
The computer is now placing white discs when we place a black disc.
`can-move?` needs to be parameterized to behave differently depending upon who is making the move.

The movement rule for othello is more than adjacency.
An othello move is one that captures opponent discs between your move and one of your existing discs.
Captured discs are flipped over and converted to your color.
To check for a valid move we check for capture lines in every direction.
A capture line is a sequence of the opponents disc that is terminated with one of your discs.

Let's write a test to see if this definition is correct.
Given a board "space W W W B", placing a B at 0 0 should capture the 3 W discs,
capture should return the coordinates 1 0, 2 0, 3 0.
Given a board "B W space W B", placing a B at 2 0 should capture the 2 W discs on either side,
capture should return the coordinates 1 0, 3, 0.

We need to pass a game to our `computer-move` test.

Now we need the next game state to contained the result of flipping all the captured discs.
Hmmm looks like I missed the terminating disc requirement.
Let's add a failing test to capture that.
Given a board "space W W space", placing a B at 0 0 should not return any capture coordinates.
`capture-line` needs to collect a sequence of potential flips,
but only return them when we encounter a terminating disc.

Great, the move rules are in place now.
If we ignore the `win?` condition, it looks very much like othello.

Let's rearrange `win?` to be game specific.
Let's convert it into a multimethod on game type.
In othello, the player with the most pieces at the end of the game wins.

Players must make a capturing move if possible, or pass.
We can use the `frequencies` function to discover the count of space, W and B in the board.
`apply concat` flattens the board from a 2 by 2 matrix into a one dimensional sequence.
If there are no remaining spaces, the player is a winner if they have more discs than the opponent.
In a 2 by 2 game board, B B B W is a win condition for black.

Now that we have several tests, it is inconvenient to scroll through the page to view them.
Let's get some output in the console to alert us on failures.
In our `project.clj` in the devcards build under figwheel, add an on-jsload hook.
Add the test directory to source-paths, and create a source file run.cljs under test/tictactoe
`run` will call ClojureScript's `run-all-tests` function.
Well also define a method to print out success or fail when the tests complete.
Now we can see a summary of the tests in the browser console whenever we change code.

In othello it is possible to reach a configuration where neither player can move,
but not all cells are taken yet.
Let's extract an `available-moves` function so we can use it in both the `computer-move` and `win?` condition.
Hmmm even though we extracted it, our current `win?` code is much higher up in the file,
so we will need to rearrange our functions to get the order of declaration correct.

This is a symptom of a larger issue:
There is a lot of code in core.cljs now!
Let's think about how to split the code up into more coherent namespaces.

Clearly we have Tic Tac Toe specific code and Othello specific code.
`can-move?` and `win?` will go in there.
And we might create in the future some other game implementations.
Our core namespace should be kept pretty small.
Core will be focused on connecting a game state with the desired logic and a view.
We'll need a central definition of the logic of a game,
in which we can declare the multimethods which will be implemented by the more specific namespaces.
It will contain the code that is common across games.
We have a bunch of component drawing code which we can put in a view namespace.

Tic Tac Toe, Othello, and other implementations will depend on Game,
as they need the defmulti to connect methods to.
Core will depend on Game and View, and the implementations of `new-game`.
View won't need to depend on anything because it will just be rendering data.

O.K. let's move these functions to the appropriate namespaces!

We need a draw? condition.

By printing out the game in the console, we can see victory is reached.
Let's check tic tac toe is still working.

I think we are all set, let's play our game!
So far we have been running the devcards build,
We want to switch over to viewing the dev build.
In your terminal, interrupt the current build by pressing "control c".
Now run both builds simultaneously, by typing`lein figwheel dev devcards`.
Navigate to localhost:3449 to see the dev build.

We only want to mount the main game when viewing the dev build,
so let's put that inside a conditional.

Let's play our game!

Hmmm this is interesting, I cannot move, but the computer has already moved.
In this situation the computer should move again in the last remaining cell.
We can achieve this by making check-game-status recurse while there is no player move available.
Let's add a test to make sure our logic works.
Here is a small 3 by 3 board where there are 2 computer moves and no player moves.

Let's play some more games.
I think the victory message should be on a different line from the buttons.

A strong strategy when playing othello is to focus on positions instead of how many discs you can flip.
The most advantageous positions in othello are the corners,
which can never be lost and allow you to recapture long lines in many directions.
Next best are the sides, for the same reason.
When starting a game it is better to capture fewer discs,
This limits your opponents options, and allows you to force your way into a side or corner.
Once you can establish the safety of a side and corner, you will have many opportunities to reclaim the central discs.

Time to publish our boardgames.
Our project source files are now core, game, othello, tictactoe and view.
And we added a devcards.html file to the resources directory.

I created a new repository for the combined games,
so that there is a separate repository for each video.
But you don't need to.
I'll rename my output file to othello.js to differentiate it from my previous project.

Let's check that the minified build still works.
Interrupt the current build with "control c"
and type `lein cljsbuild once min`
open index.html if you want to check it locally.
Commit and push to the gh-pages branch.
Navigate to username.github.io/project to see your page.

Let's review:
We converted our original game into two games.

The othello namespace contains our game specific rules for othello:
An othello game has a green background, the player is B, and computer is W.
The board has four discs in a diagonal configuration at the center.
Valid moves capture one or more lines of discs of the other player.
A draw occurs if there are no available moves to the player or computer.
We can shorten this test by using a new-board instead of repeating the values.
A win occurs when neither player can move, and one has more discs.

The core namespace has the game selection view and attaches the rendering.
The view namespace has the blank, circle, cross, discs, and game-board component.
The game namespace declares the multimethods that will dispatch by game type,
and some logic functions which are common between games.
The tictactoe namespace contains implementations specific to Tic Tac Toe.

We have a minified build which is published on github pages,
a dev build, and a devcards build.
Devcards presents cards and tests that occur in our namespaces,
so that we can see what our components will look like in predefined states.
We added an on-jsload hook to report a test summary to the console while developing.

If you have any questions, please drop a comment.

Until next time, keep coding!

Curious about ClojureScript, but not sure how to use it?

A close friend was intrigued by a Tetris clone I recently wrote about, but was having difficulty getting an initial project up and running. CoderX and I recorded a step by step guide which shows just how simple and fast it is to start, build and publish an interactive webpage using ClojureScript.

Watch: Screencast (20 minutes)
Play: Game
Read: Code
Write: Make your own version! Try a bigger board? Smarter computer? Different look?


Transcript of screencast:

CoderX here

If you aren't using ClojureScript to make web pages, you are missing out.
This style of programming is fast, fun, simple and rewarding.
And when I say fast, I mean really fast.
It is a quantum leap from any other style of programming.
You really have to experience it to appreciate it.

Today Timothy and I will take you step by step through the process of building a tic tac toe game from start to finish.
Follow along with us, and publish a web page to show your friends.
We’ll be coding in ClojureScript.
You will need Java, Leiningen, and your favourite text editor installed.

To create a new Clojure project open a Terminal and type
`lein new figwheel tictactoe -- --reagent`
Go into the tictactoe project directory
`cd tictactoe`
We have a readme file, a project file, a style sheet, index.html and core.cljs source file.
Type `lein figwheel` to start the process that builds and notifies the browser of file changes.
Position your browser on the left and navigate to `localhost:3449`
Wait until you see the “Successfully compiled” message in the terminal, and reload the browser.
The “Hello world” page indicates that everything is working so far.
Open up the dev console in your browser.

We are ready to start coding now.
Open up the core.cljs file from the source directory under tictactoe.
Position your text editor on the right so you can see the code and your page side by side.
Edit the print string on line 6 of the source code to write a new message.
The browser console logs the output immediately.

The current state of our game will be kept inside an `atom` called `app-state`.
This is a Reagent atom, which causes our web page to be re-rendered whenever the `app-state` changes.
“Def once” is not re-evaluated when the code reloads, so app-state can only be updated by either code execution or refreshing the browser.
Let’s update the app-state text with “Hi”.
The app renders our new message.
The `on-js-reload` function is called whenever new code is loaded from any namespace.
When working with multiple namespaces, it is a good idea to re-render the application here.
For now we can ignore it as we only need to work in the core namespace.

Rename the “hello-world” component to “tictactoe”.
Reagent components are functions that return HTML in hiccup form.
Hiccup looks quite similar to HTML but is much more compact.
The first element is the tag, followed by a map of attributes, then any children nodes.

Let’s add a SVG element to our page, with a circle in it of radius 10.
It looks more like a quarter circle, because the center is in the top left of the drawing area.
In your browser, right click and “inspect element” on the quarter circle.
The code has produced DOM elements, just like normal HTML.

When we set the center coordinates to 10, we immediately see the full circle.

Wrap everything we have in a `center` tag,
and set the SVG width and height to 500 to make a good sized square area to work with.
SVG has a neat feature called viewbox which allows you to specify the coordinate frame.
When we assign a viewbox of size 30, and draw a circle of size 30 at location 30, the center of the circle is at the far bottom right of the SVG area.
The viewbox allows us to use whatever coordinate system is convenient, regardless of the SVGs size.

We now have the basics in place to draw our game board.
How are we going to model our game?
A game looks like this:
There are nine cells where you can mark your move.
So we can draw 9 rectangles.
When the player clicks on any of these rectangles,
we will check if that location is a valid move.

We need to add a game board to our app state.
“new-board” is a function that returns a matrix;
a vector of vectors.
We’ll initialize all the positions with zero.
And print out the board to the console.
Great!
Now let’s place a rectangle in each of the nine locations.
This `for` expression creates a sequence containing every combination of i and j in the range of our board size.
We set the view-box to be 0 to 3 so each square is of size 1.
Black looks pretty intense, how about green?
O.K. now we want to be able to click on the rectangles.
Attach an `on-click` function that just prints out a message.
I like to give my handler functions a name, so I can understand error stacktraces when they happen.
We can now see our message when we click the rectangle.
Now we need to change the board in the app-state.
To start with we will increment the current value at the coordinates we click.
These warnings are because we have a lazy sequence of non-keyed elements.
I will explaining what that means in future screencasts,
but for now let’s just put all these elements into the parent svg using the into function.
Now when we click the rectangle, we can see the app state board is updated.
Let’s make the fill color of the rectangle dependent on the number in the board matrix.
Now when we click on squares they turn yellow.
Instead of just green and yellow, what we really want are rectangles, crosses, or circles.

Remember a reagent component is a function that returns hiccup.
So let’s make a separate function for each of those three components we need.
Now for every cell in the matrix,
When it contains a 0, we will draw a blank.
When it contains a 1, we will draw a circle.
When it contains a 2, we will draw a cross.
Reagent components are nested in vectors.
So instead of calling blank, circle or cross directly by placing them inside parentheses,
we place them inside square brackets.

Make a blank function by cutting and pasting the rectangle code.
Make a circle function that returns the hiccup syntax for a circle element.
Make a cross function, just a div for now until we figure that part out.

If I save the code with an error in it, I see the problem reported at the bottom of the browser.
It tells me the line number of the code with the problem.

O.K. let’s position this circle a little better…
and try some different colors…

Now for the cross shape.
We need two lines inside a group element.
Update the app-state to have a cross at 0,0
Ah we need to use a stroke color for the lines,
and make the stroke-width smaller.
We can adjust the position using translations and scaling.
Set the stroke-linecap property to “rounded”, and we have a pretty good looking cross.

Let’s add a button to reset the app-state to an empty board.
And now a function “computer-move” for the computer player logic.
For now the computer will always try to take 0,0

Using 0 1 2 to indicate blank, player and computer is a bit cryptic.
Let’s refactor those to “B” for blank, “P” for player, and “C” for computer.
When we click on a position, the computer now takes 0,0
When we print the board out on the console, it’s a little easier to interpret.
We’ll improve the computer player slightly by choosing randomly any unused cell.
Repeating 3 all over the place is a sign we should declare the board-size.

Groovy, now when we click on a blank location, the computer randomly selects any remaining blank position. We almost have a playable game.

Let’s take a look at what our game would be like with a different board size.
This is kind of like the game “Go”.

When possible, I recommend writing functions that take state and return new state instead of modifying it directly. “computer-move” currently does too much state manipulation, so let’s refactor it to take a board and return a new board instead of updating the app state.

Oh no, I introduced a bug somewhere!
Let’s add some logging to see how our function behaves.
Aha! I have :board in the path, but it is not necessary anymore because we are now updating a board, not the entire app-state.
Defining tests is very similar to Clojure.
In future screencasts I’ll explain how to incorporate unit testing in your workflow;
but for now don’t worry too much that they seem to be silent.

Let’s move on to implementing the victory condition for tic tac toe.
We want to detect a straight line of cells owned by the same player.
For every cell we can check for 3 in a row to the right, down, diagonal right down, and diagonal right up.
We can check each direction with a single function if we pass dx dy parameters which define the direction of the step we want to travel in.
A straight is detected if every cell has the owner we are evaluating as a potential winner.
When we look up a value outside of a vector, we get nil, which is falsy.
So we don’t need to explicitly check the bounds of our board.

Our win condition is if there is some true value in any combination of starting location with direction, such that we detect 3 owned cells in a row.

Let’s check that this logic is working by printing out to the console.
Given a board of a single cell owned by “P”, and looking for straights of length 1,
we expect that checking for the `win?` condition will return true.
But when looking for straights of length 2, it should return false.
Let’s see if it works with a 2x2 board, checking for length 2 on a diagonal.
Yes, cool. This is looking promising.

Our game status can be player victory, computer victory, draw or in progress.
A draw occurs when the board is full, but there is no victor.
The definition of full is that every cell is in the set of “P” and “C”.

Time to hook up our game-status check to the player click event.
After the player moves, check for victory.
If the player has not won yet, the computer should try to move.
We always need to check for a draw.
Add the game-status to the app-state.
Modify the tictactoe component to display different text messages according to the game-status.
Move the new game button up near the message text.
Let’s play!
Great, winning was detected…
but oh no, the draw did not work.
The problem is that our computer-move throws an exception when there are no possible moves, let’s fix that.
Our game is working!

Let’s look over our code.
We have a function to create a new board.
We have a computer-move function.
A straight line detector, which is used to detect a winning condition.
We have a way to update the game status.
We have functions to draw a blank rectangle, a circle, and a cross.
Actually let’s make the circle a zero by setting its fill to none and setting the stroke-width.
This cross could be a little bit smaller.
The tictactoe component displays the game status, new game button, and the board.

Time to publish our web page.
Github pages is an easy way to get your code online.
We need to copy the index.html page up to the project directory.
And point the minified build target to the project directory as well.
“git init” our project.
“lein clean” to get rid of intermediate compiled files.
“lein cljsbuild once min” to build the minified version of our javascript file.
Add and commit all our files.
Make a gh-pages branch. Github publishes what it finds on this branch.
Navigate to username.github.io/tictactoe to see your page!
Share the link with your friends, so they can see what you built.

Let’s review what we did today.
We setup a new ClojureScript project.
When we changed the code, it loaded in the browser immediately.
We debugged some code by printing to the browser console.
`defonce` prevented `app-state` from changing when new code was loaded.
Reagent components are functions. They return HTML in a compact hiccup syntax.
Reagent components are nested inside a vector instead of a function call.
Most importantly, we are able to quickly and interactively build a game.

I am super excited about how easy it is to build interactive pages in ClojureScript. Please follow these steps through and publish your own version, I would love to see what you make, so drop a comment here with the link to your published version, and any questions that come up for you.

Until next time, keep coding.