diff --git a/lib/chess/moves/generator.ex b/lib/chess/moves/generator.ex index da7dff9..3cb39a3 100644 --- a/lib/chess/moves/generator.ex +++ b/lib/chess/moves/generator.ex @@ -1,6 +1,7 @@ defmodule Chess.Moves.Generator do @moduledoc false + # Move generation for pieces that move in straight lines def moves(_colour, _board, {0, _rank}, {-1, _}), do: [] def moves(_colour, _board, {_file, 0}, {_, -1}), do: [] def moves(_colour, _board, {7, _rank}, {1, _}), do: [] @@ -10,21 +11,40 @@ defmodule Chess.Moves.Generator do cond do can_take_piece?(colour, board, next_square) -> [next_square] - obstruction?(board, next_square) -> + obstruction?(colour, board, next_square) -> [] true -> [next_square | moves(colour, board, next_square, {fv, rv})] end end + # Move generation for pieces that follow a pattern + def moves(_colour, _board, {_file, _rank}, []), do: [] + def moves(colour, board, {file, rank}, [{fv, rv} | moves]) do + move_square = {file + fv, rank + rv} + cond do + outside_board?(move_square) || + obstruction?(colour, board, move_square) -> + moves(colour, board, {file, rank}, moves) + can_take_piece?(colour, board, move_square) -> + [move_square | moves(colour, board, {file, rank}, moves)] + true -> + [move_square | moves(colour, board, {file, rank}, moves)] + end + end + + defp outside_board?({file, rank}) do + file < 0 || file > 7 || + rank < 0 || rank > 7 + end + defp can_take_piece?(colour, board, {file, rank}) do piece = board["#{file},#{rank}"] - piece && piece["colour"] != colour end - defp obstruction?(board, {file, rank}) do - board - |> Map.has_key?("#{file},#{rank}") + defp obstruction?(colour, board, {file, rank}) do + piece = board["#{file},#{rank}"] + piece && piece["colour"] == colour end end diff --git a/lib/chess/moves/knight.ex b/lib/chess/moves/knight.ex index e976fdf..0b4a109 100644 --- a/lib/chess/moves/knight.ex +++ b/lib/chess/moves/knight.ex @@ -1,12 +1,12 @@ defmodule Chess.Moves.Knight do @moduledoc false - def moves(_board, {file, rank}) do - patterns() - |> Enum.map(fn ({fv, rv}) -> {file + fv, rank + rv} end) - |> Enum.reject(fn ({file, rank}) -> - file < 0 || rank < 0 || file > 7 || rank > 7 - end) + alias Chess.Moves.Generator + + def moves(board, {file, rank}) do + board["#{file},#{rank}"] + |> Map.get("colour") + |> Generator.moves(board, {file, rank}, patterns()) end defp patterns do diff --git a/test/chess/moves/knight_test.exs b/test/chess/moves/knight_test.exs index 76e5309..f89042d 100644 --- a/test/chess/moves/knight_test.exs +++ b/test/chess/moves/knight_test.exs @@ -23,6 +23,19 @@ defmodule Chess.Moves.KnightTest do assert Enum.sort(moves) == expected_moves end + test "knights are blocked by other pieces of the same colour" do + board = %{ + "0,0" => %{"type" => "knight", "colour" => "white"}, + "1,2" => %{"type" => "king", "colour" => "white"}, + } + moves = Moves.available(board, {0, 0}) + + expected_moves = Enum.sort([ + {2, 1}, + ]) + assert Enum.sort(moves) == expected_moves + end + def board do Chess.Board.default end