Connect Four in Elixir

Build a bot in fifteen minutes

by Justus Eapen 🖋 ✒️ @justuseapen

What are we doing here?

Using games (Connect Four) to learn a language (Elixir).

First, clone the repo:


              $ git clone git@github.com:alanvoss/connect_four.git
          

The Rules

To win Connect Four ou must be the first player to get four of your colored checkers in a row either horizontally, vertically or diagonally.


Thanks Google

Important Things


                bin/match PureRandomness PureRandomness
              

                lib/connect_four/contenders
              

                lib/connect_four/board_helper.ex
              

Strategy

An OK Strategy

  1. Take the winning move if it's available
  2. Block your opponent if they have a winning move available
  3. DEFAULT TO RANDOMNESS (AKA madness)

OK... But what's the least we can do?

PURE RANDOMNESS HAHAHAHAHAHAHHAHAHHAHIEGHJDSIONG V?

lib/connect_four/contenders/pure_randomness.ex

            defmodule ConnectFour.Contenders.PureRandomness do  
              use GenServer

              def start(default) do
                GenServer.start(__MODULE__, default)
              end

              def handle_call(:name, _from, state) do
                letters = for n <- ?A..?Z, do: n
                random_name =
                  for _ <- 1..12 do
                    Enum.random(letters)
                  end

                {:reply, List.to_string(random_name), state}
              end

              def handle_call({:move, board}, _from, state) do
                random_column =
                  board
                  |> Enum.at(0)
                  |> Enum.with_index
                  |> Enum.filter(&(elem(&1, 0) == 0))
                  |> Enum.map(&(elem(&1, 1)))
                  |> Enum.random

                {:reply, random_column, state}
              end
            end
          

Check for winning moves

lib/connect_four/contenders/basic.ex


              def win_check(board, contender) do
                for sim_move <- possible_moves() do 
                  with {:ok, board} <- BoardHelper.drop(board,contender,sim_move),
                       {:winner, winner} <- BoardHelper.evaluate_board(board) do
                     sim_move
                  else 
                    _ ->nil
                  end
                end
              end
          

Take a winning move

lib/connect_four/contenders/basic.ex


            def handle_call({:move, board}, _from, state) do
              random_column =
                board
                |> Enum.at(0)
                |> Enum.with_index
                |> Enum.filter(&(elem(&1, 0) == 0))
                |> Enum.map(&(elem(&1, 1)))
                |> Enum.random

              winning_move = win_check(board, 1)
              |> Enum.reject(fn(column) -> is_nil(column) end)
              |> List.first

              blocking_move = win_check(board, 2)
              |> Enum.reject(fn(column) -> is_nil(column) end)
              |> List.first

              {:reply, (winning_move || random_column), state}
            end
          

Take a blocking move

* Elegant solution time

lib/connect_four/contenders/basic.ex


            def handle_call({:move, board}, _from, state) do
              random_column =
                board
                |> Enum.at(0)
                |> Enum.with_index
                |> Enum.filter(&(elem(&1, 0) == 0))
                |> Enum.map(&(elem(&1, 1)))
                |> Enum.random

              winning_move = win_check(board, 1)
              |> Enum.reject(fn(column) -> is_nil(column) end)
              |> List.first

              blocking_move = win_check(board, 2)
              |> Enum.reject(fn(column) -> is_nil(column) end)
              |> List.first

              {:reply, (winning_move || blocking_move || random_column), state}
            end
          

DEMO TIME

#Winning

Beating Randomness is easy though. What about real bots?

BATTLE!

The Challenge: Defeating Mediocrity

Connect 4 is a solved game.


But not in Elixir...

THE END