Mix.install([
{:jason, "~> 1.4"},
{:kino, "~> 0.9", override: true},
{:youtube, github: "brooklinjazz/youtube"},
{:hidden_cell, github: "brooklinjazz/hidden_cell"}
])
You're developing a 2D tactical combat game.
Characters in your game fight on a grid of potentially infinite size.
You're going to use protocols create a Character.can_attack?/3
function
that expects the following:
- A
Barbarian
orWizard
struct. - The player's coordinate
{x, y}
- An enemy's coordinate
{x, y}
It should then return a boolean.
Here's the Character
protocol as well as the Barbarian
and Wizard
struct you're going to use.
Do not modify this code:
defprotocol Character do
def can_attack?(character, origin, target)
end
defmodule Wizard do
defstruct []
end
defmodule Barbarian do
defstruct []
end
A Barbarian can attack in 2 square radius.
You should be able to check if a character can attack a coordinate {x, y}
given their
starting location in {x, y}
.
Character.can_attack?(%Barbarian{}, {4, 4}, {6, 6})
true
Example Solution
defimpl Character, for: Barbarian do
def can_attack?(_character, {init_x, init_y}, {x, y}) do
x_diff = init_x - x
y_diff = init_y - y
abs(x_diff) <= 2 && abs(y_diff) <= 2
end
end
# Implementation Goes Here:
# You May Use The Following Test Suite To Validate Your Solution.
ExUnit.start(auto_run: false)
defmodule BarbarianTests do
use ExUnit.Case
describe "Barbarian" do
test "can attack within two squares of current position" do
for x <- 2..6, y <- 2..6 do
assert Character.can_attack?(%Barbarian{}, {4, 4}, {x, y})
end
end
test "cannot attack beyond two squares of current position" do
refute Character.can_attack?(%Barbarian{}, {4, 4}, {1, 1})
refute Character.can_attack?(%Barbarian{}, {4, 4}, {7, 7})
refute Character.can_attack?(%Barbarian{}, {4, 4}, {7, 1})
refute Character.can_attack?(%Barbarian{}, {4, 4}, {1, 7})
end
test "logic is not hardcoded to the {4, 4} position" do
refute Character.can_attack?(%Barbarian{}, {3, 3}, {6, 6})
end
end
end
ExUnit.run()
A Wizard can attack in straight or diagonal lines of any length.
Character.can_attack?(%Wizard{}, {4, 4}, {6, 6})
true
Example Solution
defimpl Character, for: Wizard do
def can_attack?(_character, {init_x, init_y}, {x, y}) do
x_diff = init_x - x
y_diff = init_y - y
init_x == x || init_y == y || abs(x_diff) == abs(y_diff)
end
end
Create a Wizard
implementation for the Character
protocol.
# Implementation Goes Here:
# You May Use The Following Test Suite To Validate Your Solution.
ExUnit.start(auto_run: false)
defmodule WizardTests do
use ExUnit.Case
describe "Wizard" do
test "can attack in eight directions" do
# up, up-right, right, down-right, down, down-left, left, up-left
assert Character.can_attack?(%Wizard{}, {4, 4}, {4, 5})
assert Character.can_attack?(%Wizard{}, {4, 4}, {5, 5})
assert Character.can_attack?(%Wizard{}, {4, 4}, {5, 4})
assert Character.can_attack?(%Wizard{}, {4, 4}, {5, 3})
assert Character.can_attack?(%Wizard{}, {4, 4}, {4, 3})
assert Character.can_attack?(%Wizard{}, {4, 4}, {3, 3})
assert Character.can_attack?(%Wizard{}, {4, 4}, {3, 4})
assert Character.can_attack?(%Wizard{}, {4, 4}, {3, 5})
end
test "cannot attack invalid squares" do
refute Character.can_attack?(%Wizard{}, {4, 4}, {6, 5})
refute Character.can_attack?(%Wizard{}, {4, 4}, {2, 5})
refute Character.can_attack?(%Wizard{}, {4, 4}, {3, 2})
refute Character.can_attack?(%Wizard{}, {4, 4}, {6, 3})
end
end
end
ExUnit.run()
Create your own customer character with an attack pattern than you decide on. It should not match the existing characters.
For example, you might create an Archer
who can only attack in a 3 radius square.
Character.can_attack?(%Archer{}, {4, 4}, {7, 7})
true
Implement your custom character below.
DockYard Academy now recommends you use the latest Release rather than forking or cloning our repository.
Run git status
to ensure there are no undesirable changes.
Then run the following in your command line from the curriculum
folder to commit your progress.
$ git add .
$ git commit -m "finish Battle Map exercise"
$ git push
We're proud to offer our open-source curriculum free of charge for anyone to learn from at their own pace.
We also offer a paid course where you can learn from an instructor alongside a cohort of your peers. We will accept applications for the June-August 2023 cohort soon.