Connect Four v0.1.2 ConnectFour.Game View Source

A Connect Four game.

Players are distinguished by game piece color (yellow and red). Moves are represented by the columns in which they are made.

Yellow moves first.

This implementation is based on an efficient implementation written by John Tromp, which uses bitboards to be very small and very fast.

This is how it works: https://github.com/denkspuren/BitboardC4/blob/master/BitboardDesign.md

Original Java implementation: https://tromp.github.io/c4/Connect4.java

Link to this section Summary

Types

One of seven Connect Four game columns.

A list of Connect Four moves, describing a game.

A Connect Four player (yellow always moves first).

A Connect Four game result. nil means that the game has not yet ended. :draws occur when all columns are full and no player has connected four.

t()

Functions

Returns a specification to start this module under a supervisor.

Get a list of legal moves for the current position.

Look at the state of the game.

Submit a move for whomever's turn it currently is by specifying a column (0 through 6).

Restart the game. The game does not need to have a result to be restarted.

Start a GenServer process for a Connect Four game.

Link to this section Types

Link to this type

column()

View Source
column() :: 0..6

One of seven Connect Four game columns.

A list of Connect Four moves, describing a game.

Link to this type

player()

View Source
player() :: :yellow | :red

A Connect Four player (yellow always moves first).

Link to this type

result()

View Source
result() :: :yellow_wins | :red_wins | :draw | nil

A Connect Four game result. nil means that the game has not yet ended. :draws occur when all columns are full and no player has connected four.

Link to this type

t()

View Source
t() :: %ConnectFour.Game{
  bitboards: %{yellow: integer(), red: integer()},
  column_heights: column_heights(),
  moves: moves(),
  plies: non_neg_integer(),
  result: result()
}

Link to this section Functions

Returns a specification to start this module under a supervisor.

See Supervisor.

Link to this function

look(pid)

View Source
look(pid()) :: {:ok, %{moves: moves(), result: result()}}

Look at the state of the game.

Examples

iex> {:ok, pid} = Game.start_link()
iex> Game.move(pid, [4, 5, 4])
{:ok, %{moves: [4, 5, 4], result: nil}}
iex> Game.look(pid)
{:ok, %{moves: [4, 5, 4], result: nil}}

Works for finished games, too.

Examples

iex> {:ok, pid} = Game.start_link()
iex> Game.move(pid, [4, 5, 4, 5, 4, 5])
{:ok, %{moves: [4, 5, 4, 5, 4, 5], result: nil}}
iex> Game.move(pid, 4)
{:ok, %{moves: [4, 5, 4, 5, 4, 5, 4], result: :yellow_wins}}
iex> Game.look(pid)
{:ok, %{moves: [4, 5, 4, 5, 4, 5, 4], result: :yellow_wins}}
Link to this function

move(pid, column)

View Source
move(pid(), column() | moves()) ::
  {:ok, %{moves: moves(), result: result()}} | {:error, String.t()}

Submit a move for whomever's turn it currently is by specifying a column (0 through 6).

Make multiple moves at once by passing a list of moves. If any of the moves are invalid, none (including any valid ones preceding the invalid one) will be played.

moves is a list of all the moves completed in the game so far. Moves are represented as integers between 0 and 6, each reflecting the column in which the piece for that turn was dropped. The first integer in the list is yellow's move, the second is red's, the third is yellow's, and so on.

Game results are reported as atoms and can be one of the following:

  • nil (when the game is still in progress)
  • :yellow_wins
  • :red_wins
  • :draw (when the board fills up without four connected pieces)

Examples

iex> {:ok, pid} = Game.start_link()
iex> Game.move(pid, 4)
{:ok, %{moves: [4], result: nil}}
iex> Game.move(pid, 5)
{:ok, %{moves: [4, 5], result: nil}}

iex> {:ok, pid} = Game.start_link()
iex> Game.move(pid, [4, 5])
{:ok, %{moves: [4, 5], result: nil}}

iex> {:ok, pid} = Game.start_link()
iex> Game.move(pid, [4, 7])
{:error, "One or more invalid moves"}

iex> {:ok, pid} = Game.start_link()
iex> Game.move(pid, [1, 1, 2, 2, 3, 3, 4])
{:ok, %{moves: [1, 1, 2, 2, 3, 3, 4], result: :yellow_wins}}
iex> Game.move(pid, 4)
{:error, "Game is over"}
Link to this function

restart(pid)

View Source
restart(pid()) :: :ok

Restart the game. The game does not need to have a result to be restarted.

Examples

iex> {:ok, pid} = Game.start_link()
iex> Game.move(pid, 4)
{:ok, %{moves: [4], result: nil}}
iex> Game.restart(pid)
:ok
iex> Game.move(pid, 4)
{:ok, %{moves: [4], result: nil}}

Start a GenServer process for a Connect Four game.

Examples

iex> {:ok, pid} = Game.start_link()
iex> Process.alive?(pid)
true