# paulfioravanti's solution

## to Queen Attack in the Elixir Track

Published at Sep 11 2019 · 0 comments
Instructions
Test suite
Solution

#### Note:

This exercise has changed since this solution was written.

Given the position of two queens on a chess board, indicate whether or not they are positioned so that they can attack each other.

In the game of chess, a queen can attack pieces which are on the same row, column, or diagonal.

A chessboard can be represented by an 8 by 8 array.

So if you're told the white queen is at (2, 3) and the black queen at (5, 6), then you'd know you've got a set-up like so:

``````_ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _
_ _ _ W _ _ _ _
_ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _
_ _ _ _ _ _ B _
_ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _
``````

You'd also be able to answer whether the queens can attack each other. In this case, that answer would be yes, they can, because both pieces share a diagonal.

## Running tests

Execute the tests with:

``````\$ mix test
``````

### Pending tests

In the test suites, all but the first test have been skipped.

Once you get a test passing, you can unskip the next one by commenting out the relevant `@tag :pending` with a `#` symbol.

For example:

``````# @tag :pending
test "shouting" do
assert Bob.hey("WATCH OUT!") == "Whoa, chill out!"
end
``````

Or, you can enable all the tests by commenting out the `ExUnit.configure` line in the test suite.

``````# ExUnit.configure exclude: :pending, trace: true
``````

If you're stuck on something, it may help to look at some of the available resources out there where answers might be found.

## Source

J Dalbey's Programming Practice problems http://users.csc.calpoly.edu/~jdalbey/103/Projects/ProgrammingPractice.html

## Submitting Incomplete Solutions

It's possible to submit an incomplete solution so you can see how others have completed the exercise.

### queen_attack_test.exs

``````defmodule QueenAttackTest do
use ExUnit.Case

# @tag :pending
test "default positions" do
queens = Queens.new()
assert queens.white == {0, 3}
assert queens.black == {7, 3}
end

@tag :pending
test "specific placement" do
queens = Queens.new({3, 7}, {6, 1})
assert queens.white == {3, 7}
assert queens.black == {6, 1}
end

@tag :pending
test "cannot occupy same space" do
assert_raise ArgumentError, fn ->
Queens.new({2, 4}, {2, 4})
end
end

@tag :pending
test "string representation" do
queens = Queens.new({2, 4}, {6, 6})

board =
String.trim("""
_ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _
_ _ _ _ W _ _ _
_ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _
_ _ _ _ _ _ B _
_ _ _ _ _ _ _ _
""")

assert Queens.to_string(queens) == board
end

@tag :pending
test "another string representation" do
queens = Queens.new({7, 1}, {0, 0})

board =
String.trim("""
B _ _ _ _ _ _ _
_ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _
_ W _ _ _ _ _ _
""")

assert Queens.to_string(queens) == board
end

@tag :pending
test "yet another string representation" do
queens = Queens.new({4, 3}, {3, 4})

board =
String.trim("""
_ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _
_ _ _ _ B _ _ _
_ _ _ W _ _ _ _
_ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _
""")

assert Queens.to_string(queens) == board
end

@tag :pending
test "queen placed on the bottom right corner" do
queens = Queens.new({4, 3}, {7, 7})

board =
String.trim("""
_ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _
_ _ _ W _ _ _ _
_ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _
_ _ _ _ _ _ _ B
""")

assert Queens.to_string(queens) == board
end

@tag :pending
test "queen placed on the edge of the board" do
queens = Queens.new({4, 3}, {2, 7})

board =
String.trim("""
_ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _
_ _ _ _ _ _ _ B
_ _ _ _ _ _ _ _
_ _ _ W _ _ _ _
_ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _
""")

assert Queens.to_string(queens) == board
end

@tag :pending
test "cannot attack" do
queens = Queens.new({2, 3}, {4, 7})
refute Queens.can_attack?(queens)
end

@tag :pending
test "can attack on same row" do
queens = Queens.new({2, 4}, {2, 7})
assert Queens.can_attack?(queens)
end

@tag :pending
test "can attack on same column" do
queens = Queens.new({5, 4}, {2, 4})
assert Queens.can_attack?(queens)
end

@tag :pending
test "can attack on diagonal" do
queens = Queens.new({1, 1}, {6, 6})
assert Queens.can_attack?(queens)
end

@tag :pending
test "can attack on other diagonal" do
queens = Queens.new({0, 6}, {1, 7})
assert Queens.can_attack?(queens)
end

@tag :pending
test "can attack on yet another diagonal" do
queens = Queens.new({4, 1}, {6, 3})
assert Queens.can_attack?(queens)
end

@tag :pending
test "can attack on a diagonal slanted the other way" do
queens = Queens.new({6, 1}, {1, 6})
assert Queens.can_attack?(queens)
end
end``````

### test_helper.exs

``````ExUnit.start()
ExUnit.configure(exclude: :pending, trace: true)``````
``````defmodule Queens do
@board_length 8
@black "B"
@white "W"
@blank "_"

@type t :: %Queens{black: {integer, integer}, white: {integer, integer}}
defstruct black: nil, white: nil

@doc """
Creates a new set of Queens
"""
@spec new() :: Queens.t()
@spec new({integer, integer}, {integer, integer}) :: Queens.t()
def new(white \\ {0, 3}, black \\ {7, 3})
def new(queen, queen), do: raise(ArgumentError)
def new(white, black), do: %Queens{white: white, black: black}

@doc """
Gives a string representation of the board with
white and black queen locations shown
"""
@spec to_string(Queens.t()) :: String.t()
def to_string(queens) do
generate_row(&row(queens, &1, &2))
|> Enum.map(&Enum.join(&1, " "))
|> Enum.join("\n")
end

@doc """
Checks if the queens can attack each other
"""
@spec can_attack?(Queens.t()) :: boolean
def can_attack?(%Queens{black: {row, _col1}, white: {row, _col2}}), do: true
def can_attack?(%Queens{black: {_row1, col}, white: {_row2, col}}), do: true

def can_attack?(%Queens{black: {row1, col1}, white: {row2, col2}}) do
abs(row1 - row2) == abs(col1 - col2)
end

defp generate_row(fun) do
0..(@board_length - 1)
|> Enum.reduce([], &fun.(&1, &2))
|> Enum.reverse()
end

defp row(queens, row_num, acc) do
row =
case queens do
%Queens{white: {^row_num, white_col}, black: {^row_num, black_col}} ->
generate_row(&add_column(white_col, black_col, &1, &2))

%Queens{white: {^row_num, white_col}} ->
generate_row(&add_column(white_col, nil, &1, &2))

%Queens{black: {^row_num, black_col}} ->
generate_row(&add_column(nil, black_col, &1, &2))

_ ->
List.duplicate(@blank, @board_length)
end

[row | acc]
end

defp add_column(white_col, _black_col, white_col, acc), do: [@white | acc]
defp add_column(_white_col, black_col, black_col, acc), do: [@black | acc]
defp add_column(_white_col, _black_col, _column, acc), do: [@blank | acc]
end``````