Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/chess/application.ex
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ defmodule Chess.Application do
# Start the PubSub system
{Phoenix.PubSub, name: Chess.PubSub},
# Start the Endpoint (http/https)
Chess.State,
ChessWeb.Endpoint
# Start a worker by calling: Chess.Worker.start_link(arg)
# {Chess.Worker, arg}
Expand Down
98 changes: 98 additions & 0 deletions lib/chess/board.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
defmodule Chess.Board do
defstruct a1: "figure white rook",
b1: "figure white knight",
c1: "figure white bishop",
d1: "figure white queen",
e1: "figure white king",
f1: "figure white bishop",
g1: "figure white knight",
h1: "figure white rook",
a2: "figure white pawn",
b2: "figure white pawn",
c2: "figure white pawn",
d2: "figure white pawn",
e2: "figure white pawn",
f2: "figure white pawn",
g2: "figure white pawn",
h2: "figure white pawn",
a3: nil,
b3: nil,
c3: nil,
d3: nil,
e3: nil,
f3: nil,
g3: nil,
h3: nil,
a4: nil,
b4: nil,
c4: nil,
d4: nil,
e4: nil,
f4: nil,
g4: nil,
h4: nil,
a5: nil,
b5: nil,
c5: nil,
d5: nil,
e5: nil,
f5: nil,
g5: nil,
h5: nil,
a6: nil,
b6: nil,
c6: nil,
d6: nil,
e6: nil,
f6: nil,
g6: nil,
h6: nil,
a7: "figure black pawn",
b7: "figure black pawn",
c7: "figure black pawn",
d7: "figure black pawn",
e7: "figure black pawn",
f7: "figure black pawn",
g7: "figure black pawn",
h7: "figure black pawn",
a8: "figure black rook",
b8: "figure black knight",
c8: "figure black bishop",
d8: "figure black queen",
e8: "figure black king",
f8: "figure black bishop",
g8: "figure black knight",
h8: "figure black rook"

@num_conversion %{
"a" => 1,
"b" => 2,
"c" => 3,
"d" => 4,
"e" => 5,
"f" => 6,
"g" => 7,
"h" => 8
}

@letter_conversion %{
1 => "a",
2 => "b",
3 => "c",
4 => "d",
5 => "e",
6 => "f",
7 => "g",
8 => "h"
}

def from_square_to_position(square) do
positions = String.graphemes(square)

{@num_conversion[List.first(positions)], positions |> List.last() |> String.to_integer()}
end

def from_position_to_square(x, y) do
Enum.join([@letter_conversion[x], y], "")
end
end
256 changes: 256 additions & 0 deletions lib/chess/move.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,256 @@
defmodule Chess.Move do
alias Chess.Board
alias Chess.State

@kings ["figure white king", "figure black king"]

def validate_move("figure white bishop", from_square, to_square, board, turn, id) do
{from_x, from_y} = Board.from_square_to_position(from_square)

{to_x, to_y} = Board.from_square_to_position(to_square)

bishop_posibilities(from_x, from_y, to_x, to_y, board, turn, id)
end

def validate_move("figure black bishop", from_square, to_square, board, turn, id) do
{from_x, from_y} = Board.from_square_to_position(from_square)

{to_x, to_y} = Board.from_square_to_position(to_square)
bishop_posibilities(from_x, from_y, to_x, to_y, board, turn, id)
end

def validate_move("figure white rook", from_square, to_square, board, turn, id) do
{from_x, from_y} = Board.from_square_to_position(from_square)

{to_x, to_y} = Board.from_square_to_position(to_square)

rook_posibilities(from_x, from_y, to_x, to_y, board, turn, id)
end

def validate_move("figure black rook", from_square, to_square, board, turn, id) do
{from_x, from_y} = Board.from_square_to_position(from_square)

{to_x, to_y} = Board.from_square_to_position(to_square)
rook_posibilities(from_x, from_y, to_x, to_y, board, turn, id)
end

def validate_move("figure white queen", from_square, to_square, board, turn, id) do
{from_x, from_y} = Board.from_square_to_position(from_square)

{to_x, to_y} = Board.from_square_to_position(to_square)

queen_posibilities(from_x, from_y, to_x, to_y, board, turn, id)
end

def validate_move("figure black queen", from_square, to_square, board, turn, id) do
{from_x, from_y} = Board.from_square_to_position(from_square)

{to_x, to_y} = Board.from_square_to_position(to_square)
queen_posibilities(from_x, from_y, to_x, to_y, board, turn, id)
end

def validate_move("figure black pawn", from_square, to_square, board, turn, id) do
{from_x, from_y} = Board.from_square_to_position(from_square)

{to_x, to_y} = Board.from_square_to_position(to_square)

forward_pawn_posibility(from_x, from_y, to_x, to_y, 0, -1, board, turn, id) ++
forward_pawn_posibility(from_x, from_y, to_x, to_y, 0, -2, board, turn, id)
end

def validate_move("figure white pawn", from_square, to_square, board, turn, id) do
{from_x, from_y} = Board.from_square_to_position(from_square)

{to_x, to_y} = Board.from_square_to_position(to_square)

forward_pawn_posibility(from_x, from_y, to_x, to_y, 0, 1, board, turn, id) ++
forward_pawn_posibility(from_x, from_y, to_x, to_y, 0, 2, board, turn, id)
end

def validate_move("figure white knight", from_square, to_square, board, turn, id) do
{from_x, from_y} = Board.from_square_to_position(from_square)

{to_x, to_y} = Board.from_square_to_position(to_square)

forward_knight_posibility(from_x, from_y, to_x, to_y, 2, 1, board, turn, id) ++
forward_knight_posibility(from_x, from_y, to_x, to_y, -2, 1, board, turn, id) ++
forward_knight_posibility(from_x, from_y, to_x, to_y, -2, -1, board, turn, id) ++
forward_knight_posibility(from_x, from_y, to_x, to_y, 2, -1, board, turn, id) ++
forward_knight_posibility(from_x, from_y, to_x, to_y, -1, 2, board, turn, id) ++
forward_knight_posibility(from_x, from_y, to_x, to_y, 1, 2, board, turn, id) ++
forward_knight_posibility(from_x, from_y, to_x, to_y, -1, -2, board, turn, id) ++
forward_knight_posibility(from_x, from_y, to_x, to_y, 1, -2, board, turn, id)
end

def validate_move("figure black knight", from_square, to_square, board, turn, id) do
{from_x, from_y} = Board.from_square_to_position(from_square)

{to_x, to_y} = Board.from_square_to_position(to_square)

forward_knight_posibility(from_x, from_y, to_x, to_y, 2, 1, board, turn, id) ++
forward_knight_posibility(from_x, from_y, to_x, to_y, -2, 1, board, turn, id) ++
forward_knight_posibility(from_x, from_y, to_x, to_y, -2, -1, board, turn, id) ++
forward_knight_posibility(from_x, from_y, to_x, to_y, 2, -1, board, turn, id) ++
forward_knight_posibility(from_x, from_y, to_x, to_y, -1, 2, board, turn, id) ++
forward_knight_posibility(from_x, from_y, to_x, to_y, 1, 2, board, turn, id) ++
forward_knight_posibility(from_x, from_y, to_x, to_y, -1, -2, board, turn, id) ++
forward_knight_posibility(from_x, from_y, to_x, to_y, 1, -2, board, turn, id)
end

def validate_move("figure black king", from_square, to_square, board, turn, id) do
{from_x, from_y} = Board.from_square_to_position(from_square)

{to_x, to_y} = Board.from_square_to_position(to_square)

forward_knight_posibility(from_x, from_y, to_x, to_y, 1, 1, board, turn, id) ++
forward_knight_posibility(from_x, from_y, to_x, to_y, -1, 1, board, turn, id) ++
forward_knight_posibility(from_x, from_y, to_x, to_y, -1, -1, board, turn, id) ++
forward_knight_posibility(from_x, from_y, to_x, to_y, 1, -1, board, turn, id) ++
forward_knight_posibility(from_x, from_y, to_x, to_y, 1, 0, board, turn, id) ++
forward_knight_posibility(from_x, from_y, to_x, to_y, -1, 0, board, turn, id) ++
forward_knight_posibility(from_x, from_y, to_x, to_y, 0, -1, board, turn, id) ++
forward_knight_posibility(from_x, from_y, to_x, to_y, 0, 1, board, turn, id)
end

def validate_move("figure white king", from_square, to_square, board, turn, id) do
{from_x, from_y} = Board.from_square_to_position(from_square)

{to_x, to_y} = Board.from_square_to_position(to_square)

forward_knight_posibility(from_x, from_y, to_x, to_y, 1, 1, board, turn, id) ++
forward_knight_posibility(from_x, from_y, to_x, to_y, -1, 1, board, turn, id) ++
forward_knight_posibility(from_x, from_y, to_x, to_y, -1, -1, board, turn, id) ++
forward_knight_posibility(from_x, from_y, to_x, to_y, 1, -1, board, turn, id) ++
forward_knight_posibility(from_x, from_y, to_x, to_y, 1, 0, board, turn, id) ++
forward_knight_posibility(from_x, from_y, to_x, to_y, -1, 0, board, turn, id) ++
forward_knight_posibility(from_x, from_y, to_x, to_y, 0, -1, board, turn, id) ++
forward_knight_posibility(from_x, from_y, to_x, to_y, 0, 1, board, turn, id)
end

def bishop_posibilities(from_x, from_y, to_x, to_y, board, turn, id) do
posibilities(from_x, from_y, to_x, to_y, 1, -1, [], board, turn, id) ++
posibilities(from_x, from_y, to_x, to_y, 1, 1, [], board, turn, id) ++
posibilities(from_x, from_y, to_x, to_y, -1, -1, [], board, turn, id) ++
posibilities(from_x, from_y, to_x, to_y, -1, 1, [], board, turn, id)
end

def queen_posibilities(from_x, from_y, to_x, to_y, board, turn, id) do
posibilities(from_x, from_y, to_x, to_y, 1, -1, [], board, turn, id) ++
posibilities(from_x, from_y, to_x, to_y, 1, 1, [], board, turn, id) ++
posibilities(from_x, from_y, to_x, to_y, -1, -1, [], board, turn, id) ++
posibilities(from_x, from_y, to_x, to_y, -1, 1, [], board, turn, id) ++
posibilities(from_x, from_y, to_x, to_y, 1, 0, [], board, turn, id) ++
posibilities(from_x, from_y, to_x, to_y, 0, 1, [], board, turn, id) ++
posibilities(from_x, from_y, to_x, to_y, -1, 0, [], board, turn, id) ++
posibilities(from_x, from_y, to_x, to_y, 0, -1, [], board, turn, id)
end

def rook_posibilities(from_x, from_y, to_x, to_y, board, turn, id) do
posibilities(from_x, from_y, to_x, to_y, 1, 0, [], board, turn, id) ++
posibilities(from_x, from_y, to_x, to_y, 0, 1, [], board, turn, id) ++
posibilities(from_x, from_y, to_x, to_y, -1, 0, [], board, turn, id) ++
posibilities(from_x, from_y, to_x, to_y, 0, -1, [], board, turn, id)
end

def posibilities(from_x, from_y, to_x, to_y, x, y, acc, board, turn, id) do
next_x = from_x + x
next_y = from_y + y

if end_of_road?(next_x, next_y, to_x, to_y, board, turn, id) do
acc
else
acc = acc ++ [{next_x, next_y}]
posibilities(next_x, next_y, to_x, to_y, x, y, acc, board, turn, id)
end
end

def forward_pawn_posibility(from_x, 2, to_x, to_y, x, y, board, turn, id)
when abs(y) == 2 do
next_x = from_x + x
next_y = 2 + y

if end_of_road?(next_x, next_y, to_x, to_y, board, turn, id) do
[]
else
[{next_x, next_y}]
end
end

def forward_pawn_posibility(from_x, 7, to_x, to_y, x, y, board, turn, id)
when abs(y) == 2 do
next_x = from_x + x
next_y = 7 + y

if end_of_road?(next_x, next_y, to_x, to_y, board, turn, id) do
[]
else
[{next_x, next_y}]
end
end

def forward_pawn_posibility(from_x, from_y, to_x, to_y, x, 1, board, turn, id) do
next_x = from_x + x
next_y = from_y + 1

if end_of_road?(next_x, next_y, to_x, to_y, board, turn, id) do
[]
else
[{next_x, next_y}]
end
end

def forward_pawn_posibility(from_x, from_y, to_x, to_y, x, -1, board, turn, id) do
next_x = from_x + x
next_y = from_y - 1

if end_of_road?(next_x, next_y, to_x, to_y, board, turn, id) do
[]
else
[{next_x, next_y}]
end
end

def forward_pawn_posibility(_, _, _, _, _, _, _, _, _), do: []

def forward_knight_posibility(from_x, from_y, to_x, to_y, x, y, board, turn, id) do
next_x = from_x + x
next_y = from_y + y

if end_of_road?(next_x, next_y, to_x, to_y, board, turn, id) do
[]
else
[{next_x, next_y}]
end
end

def end_of_road?(-1, _, _, _, _, _, _), do: true
def end_of_road?(_, -1, _, _, _, _, _), do: true
def end_of_road?(0, _, _, _, _, _, _), do: true
def end_of_road?(_, 0, _, _, _, _, _), do: true
def end_of_road?(9, _, _, _, _, _, _), do: true
def end_of_road?(_, 9, _, _, _, _, _), do: true
def end_of_road?(10, _, _, _, _, _, _), do: true
def end_of_road?(_, 10, _, _, _, _, _), do: true

def end_of_road?(next_x, next_y, _, _, board, turn, id) do
position = next_x |> Board.from_position_to_square(next_y) |> String.to_existing_atom()

player =
Map.get(board, position)
|> then(&if not is_nil(&1), do: String.split(&1, " ") |> Enum.at(1), else: nil)

eaten = eat_or_stop(Map.get(board, position), turn, player)

if not eaten and Enum.member?(@kings, Map.get(board, position)) do
player = Map.get(board, position) |> String.split(" ") |> Enum.at(1)
State.won(%{won: player}, id)
eaten
else
eaten
end
end

defp eat_or_stop(figure, _, _) when is_nil(figure), do: false
defp eat_or_stop(_figure, turn, player) when player != turn, do: false
defp eat_or_stop(_figure, _turn, _player), do: true
end
30 changes: 30 additions & 0 deletions lib/chess/state.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
defmodule Chess.State do
use Agent

alias Phoenix.PubSub

def start_link(_) do
Agent.start_link(fn -> %{} end, name: __MODULE__)
end

def value do
Agent.get(__MODULE__, & &1)
end

def won(%{won: won}, topic) do
state = Map.get(value(), topic)
state = Map.put(state, :won, won)
Agent.update(__MODULE__, &Map.put(&1, topic, state))
make_change(state, topic)
end

def set(state, topic) do
Agent.update(__MODULE__, &Map.put(&1, topic, state))
make_change(state, topic)
end

defp make_change(state, topic) do
PubSub.broadcast(Chess.PubSub, topic, {:state, state})
{:reply, state}
end
end
Loading