Building and Playing the Go Game with Phoenix LiveView
Tags: elixir, phoenix, beginners
Published: 2019-06-18 13:49:04

---
title: Building and Playing the Go Game with Phoenix LiveView
layout: layout_elixir_alchemy
intro: Today we play the Go game. But we implement it in Phoenix LiveView first.
tags: elixir-alchemy, engineering
cover_image: https://blog.appsignal.com/images/blog/2019-06/go.jpg
canonical_url: https://blog.appsignal.com/2019/06/18/elixir-alchemy-building-go-with-phoenix-live-view.html
published: true
tags: elixir, phoenix, beginners
---

Welcome back to another Elixir Alchemy! This time, we'll discover the power of [Phoenix LiveView](https://github.com/phoenixframework/phoenix_live_view) by building an interactive game.

By rendering HTML on the server and communicating between the frontend and backend over web sockets, LiveView helps us build real-time interfaces without writing JavaScript or worrying about updating the state in the browser. By updating the state on the server side, LiveView makes sure to only update the parts of the page that need to be, resulting in fast applications that send minimal amounts of data over the wire.

To illustrate this, we’ll build our game in Phoenix, and we’ll use LiveView to make it interactive. Although tic-tac-toe is fun, we’ll go for something a bit more ambitious by building [Go](https://en.wikipedia.org/wiki/Go_(game)).

> Go is an abstract strategy board game for two players, in which the aim is to surround more territory than the opponent. The game was invented in China more than 2,500 years ago and is believed to be the oldest board game continuously played to the present day.

The [final result](https://hayago.herokuapp.com) is an implementation of the Go game that allows players to take turns placing stones on the board. Players can capture each other's stones, and the game keeps track of which stones were captured.

![The Go game, implemented with Phoenix LiveView](https://blog.appsignal.com/images/blog/2019-06/go.png)

Along the way, we’ll learn how [Phoenix LiveView](https://github.com/phoenixframework/phoenix_live_view) can help you build interactive applications without duplicating code between the frontend and the backend by keeping everything in Elixir.

## Let’s Go!

The [starter app](https://github.com/jeffkreeftmeijer/hayago/tree/starter) is a Phoenix application with some parts already set up. It cleans up some generated files, adds styling for the Go board, pre-installs Phoenix LiveView according to the install guide in the [README](https://github.com/phoenixframework/phoenix_live_view/tree/108c96aca0245fa673307f0e1a617f4b0704e981#readme), and has a module that keeps track of the game’s state.

In our game, the `State` module describes the state of the game. The starter app already comes with the `State` module so we can focus on working with LiveView.

The `State` struct keeps track of which stones are on the board in its `:positions` list, and it knows which player is up next in its `:current` key.

``` elixir
# lib/hayago/state.ex
defmodule Hayago.State do
  alias Hayago.State
  defstruct positions: Enum.map(1..81, fn _ -> nil end), current: :black

  # ...
end
```

A newly created state is initialized with list of 81 `nil` values as its `:positions`, as the board is empty and has 9 by 9 positions. The player with the black stones is the first to move, so the `:current` key is set to `:black` for any new state.

The `State` module exposes two functions. The first is `place/2` which places a new stone on the board. If the new stone steals all the liberties of another stone, the captured stone is removed from the board automatically.

The `legal?/2` function checks if a move is legal by checking if another stone already occupies the position and making sure the stone wouldn't be immediately captured.

-> If you’d like to learn more about the implementation of the `State` module that we’ll use, check out the [module’s documentation](https://github.com/jeffkreeftmeijer/hayago/blob/starter/lib/hayago/state.ex), which explains how it handles placing stones on the board, capturing stones and validating possible moves.

## The `GameLive` Module

We’ll start by rendering the board. First, we add a live view to our application to handle rendering and updating the board. It’s called `GameLive`, and it has `render/1` and `mount/2` callback functions.

``` elixir
# lib/hayago_web/live/game_live.ex
defmodule HayagoWeb.GameLive do
  use Phoenix.LiveView

  def render(assigns) do
    HayagoWeb.GameView.render("index.html", assigns)
  end

  def mount(_session, socket) do
    {:ok, assign(socket, state: %Hayago.State{})}
  end
end
```

The `mount/2` callback sets up the assigns in the `socket` to set the initial state for the view. We use it to create a new state, then add it to the socket assigns to make it available in the template.

Next, we’ll add a template to render the board. We name it `index.html.leex`, making it a *Live EEx* template. Although similar to regular EEx templates, live templates track changes in order to send a minimal amount of data over the wire whenever the view updates.

``` elixir
# lib/hayago_web/templates/game/index.html.leex
<div class="board <%= @state.current %>">
  <%= for _position <- @state.positions do %>
    <button></button>
  <% end %>
</div>
```

We loop over all positions in the `@state` struct we assigned in the live view and an empty `<button>` elements for each. The buttons are in a `<div>` element, which the stylesheet automatically styles as a Go board. We’ll also add the current color as a class name to the board, to allow the stylesheet to show the stone you’re about to place when you hover over a position.

Finally, we route any requests to `/` to our `GameLive` module in our router:

``` elixir
# lib/hayago_web/router.ex
defmodule HayagoWeb.Router
  # ...

  scope "/", HayagoWeb do
    pipe_through :browser

    live "/", GameLive
  end
end
```

If we start the Phoenix server and navigate to https://localhost:4000 in our browser, we'll see the app render an empty Go board. While we can't place stones just yet, hovering over the positions on the board shows us where a new stone would be placed.

## Making Moves

To place stones on the board, `State` implements a `place/2` function that takes a `State` struct and an index. It replaces the position that corresponds to the index with the value in the `:current` key, which is either `:black` or `:white`, depending on which player’s turn it is.

In the template, we add `phx-click` and `phx-value` attributes to our buttons. These attributes tell LiveView to send an event to our `GameLive` module.

``` elixir
# lib/hayago_web/templates/game/index.html.leex
<div class="board">
  <%= for {value, index} <- Enum.with_index(@state.positions) do %>
    <button phx-click="place" phx-value="<%= index %>" class="<%= value %>"></button>
  <% end %>
</div>
```

In our live view, we handle the event by matching on the attributes we set in the template. We use the passed index to call `State.place/2`, which returns a new state with the stone placed on the board. We'll return a `:noreply`-tuple with the new state.

``` elixir
# lib/hayago_web/live/game_live.ex
defmodule HayagoWeb.GameLive do
  # ...

  def handle_event("place", index, %{assigns: assigns} = socket) do
    new_state = State.place(assigns.state, String.to_integer(index))
    {:noreply, assign(socket, state: new_state)}
  end
end
```

By updating the state in the socket, LiveView knows to rerender the parts of the template that changed. The updated page is then compared to the rendered page to apply a minimal patch to the already-rendered page.

Back in our browser, which automatically refreshed the page after we made our changes, our project is already starting to look like a proper Go game.  We can place stones on the board and even surround an enemy stone to have it removed!

Look at all the things we're not doing! We didn't have to write any code to send data to the browser, and we didn't have to worry about updating the rendered page. LiveView took care of updating the page whenever the state changed.

However, if we click the same position twice, an already placed stone is replaced by another. To prevent this from happening, we should disable the buttons that represent illegal moves.

## Preventing Illegal Moves

To prevent illegal moves, we’ll render a disabled button for every position that either has a stone on it already or one where a newly placed stone has no liberties.

To make that work, we’ll use `State.legal?/2`, which takes the current state and an index, and returns a value indicating whether the current player can place a stone there or not.

``` elixir
<div class="board <%= @state.current %>">
  <%= for {value, index} <- Enum.with_index(@state.positions) do %>
    <%= if Hayago.State.legal?(@state, index) do %>
      <button phx-click="place" phx-value="<%= index %>" class="<%= value %>"></button>
    <% else %>
      <button class="<%= value %>" disabled="disabled"></button>
    <% end %>
  <% end %>
</div>
```

Because LiveView takes care of updating the page, we can add an if-statement to the template that checks if placing a stone on each position is a legal move. If it is, we render the same button as before. Otherwise, we render a disabled button.

The stylesheet makes sure not to show hovers for disabled buttons, and changes the cursor to indidcate that a stone can be placed there.

## Capturing Stones

When capturing a stone, the `place/2` function increments a counter in the current state's `:captures` map, which holds a counter for both the black and the white stones.

For each captured stone, we’ll show a stone above the board. Since the captures are already available in the `@state` struct we receive from the live view, we’ll loop over each of the counters to render a `<span>` with the correct class name for the stylesheet to turn into a button.

``` elixir
<div class="captures">
  <div>
    <%= for _ <- 1..@state.captures.black, @state.captures.black > 0 do %>
      <span class="black"></span>
    <% end %>
  </div>
  <div>
    <%= for _ <- 1..@state.captures.white, @state.captures.white > 0 do %>
      <span class="white"></span>
    <% end %>
  </div>
</div>
```

Since we’re using a range in our list comprehension, we’ll make sure to add a filter that ensures that the list isn’t empty when looping over it.

Now, we have a way to keep track of which stones were captured, as the stones are displayed above the board.

## Scoring, History and the Ko Rule

We've made some strides implementing Go, and we’ve now learned how to set up a LiveView project. We've seen that carefully updating the state is enough to make build an interface without having to worry about updating the view. Instead, we focussed on rendering a static representation of the current state, and left the work of updating the page the player sees up to LiveView. Aside from setting up our live view module, the code we wrote to show the state of the board was all done by adding logic to the template, and we didn't have to write any JavaScript ourselves.

However, there are still some things we should do. The next time we meet, we’ll add history to our game to allow players to undo moves and we’ll implement the [ko rule](https://senseis.xmp.net/?Ko) to prevent repeating moves. Finally, we’ll add a score counter to show each player’s current score. See you then!