Julian Noble
2 years ago
commit
cf00dc57ba
11 changed files with 430 additions and 0 deletions
@ -0,0 +1,4 @@ |
|||||||
|
# Used by "mix format" |
||||||
|
[ |
||||||
|
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] |
||||||
|
] |
@ -0,0 +1,26 @@ |
|||||||
|
# The directory Mix will write compiled artifacts to. |
||||||
|
/_build/ |
||||||
|
|
||||||
|
# If you run "mix test --cover", coverage assets end up here. |
||||||
|
/cover/ |
||||||
|
|
||||||
|
# The directory Mix downloads your dependencies sources to. |
||||||
|
/deps/ |
||||||
|
|
||||||
|
# Where third-party dependencies like ExDoc output generated docs. |
||||||
|
/doc/ |
||||||
|
|
||||||
|
# Ignore .fetch files in case you like to edit your project deps locally. |
||||||
|
/.fetch |
||||||
|
|
||||||
|
# If the VM crashes, it generates a dump, let's ignore it too. |
||||||
|
erl_crash.dump |
||||||
|
|
||||||
|
# Also ignore archive artifacts (built via "mix archive.build"). |
||||||
|
*.ez |
||||||
|
|
||||||
|
# Ignore package tarball (built via "mix hex.build"). |
||||||
|
tetris-*.tar |
||||||
|
|
||||||
|
# Temporary files, for example, from tests. |
||||||
|
/tmp/ |
@ -0,0 +1,21 @@ |
|||||||
|
# Tetris |
||||||
|
|
||||||
|
**TODO: Add description** |
||||||
|
|
||||||
|
## Installation |
||||||
|
|
||||||
|
If [available in Hex](https://hex.pm/docs/publish), the package can be installed |
||||||
|
by adding `tetris` to your list of dependencies in `mix.exs`: |
||||||
|
|
||||||
|
```elixir |
||||||
|
def deps do |
||||||
|
[ |
||||||
|
{:tetris, "~> 0.1.0"} |
||||||
|
] |
||||||
|
end |
||||||
|
``` |
||||||
|
|
||||||
|
Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc) |
||||||
|
and published on [HexDocs](https://hexdocs.pm). Once published, the docs can |
||||||
|
be found at <https://hexdocs.pm/tetris>. |
||||||
|
|
@ -0,0 +1,19 @@ |
|||||||
|
Stack trace: |
||||||
|
Frame Function Args |
||||||
|
000FFFFBBF0 00180062DF7 (000FFFFBDF8, 00000000002, 00000000002, 000FFFFDE50) |
||||||
|
00000000000 00180064EE5 (00000000064, 00000000000, 00000000420, 00000000000) |
||||||
|
000FFFFC300 00180136238 (00100000000, 000FFFFC708, 000FFFFC770, 000FFFFC798) |
||||||
|
00000000041 0018013186B (00100640281, 00000000000, 00000000000, 000FFFFC770) |
||||||
|
000FFFFC798 00180131C75 (000FFFFC770, 000FFFFC798, 001006F6B40, 000FFFFC750) |
||||||
|
000FFFFC798 00180218948 (00180111A72, 000FFFFC750, 00180194D3B, 000FFFFC6D8) |
||||||
|
000FFFFC798 00100668785 (00180249BA0, 001006E0C1D, 001006EB201, 0018027FF30) |
||||||
|
000FFFFC798 001005EF056 (00000000002, 0010068C902, 000000000AC, 00000323731) |
||||||
|
00100747200 001005A21A2 (000FFFFCC58, 00000000000, 0010061F260, 0010068D3B0) |
||||||
|
00100747200 0010042D381 (0018005DAE7, 008000628B5, 0010060E7D0, 001007477C0) |
||||||
|
00100747200 0010040203B (00180249BA0, 00000000000, 001800DB27E, 00000000030) |
||||||
|
000FFFFCC58 001004025A3 (000FFFFCC58, 04949435341, 000FFFFCC70, 00180328FE0) |
||||||
|
000FFFFCD30 001006686E4 (00000000020, 00000000000, 00180049B25, 000FFFFCC70) |
||||||
|
000FFFFCD30 00180049B91 (00000000000, 00000000000, 00000000000, 00000000000) |
||||||
|
000FFFFFFF0 00180047716 (00000000000, 00000000000, 00000000000, 00000000000) |
||||||
|
000FFFFFFF0 001800477C4 (00000000000, 00000000000, 00000000000, 00000000000) |
||||||
|
End of stack trace |
@ -0,0 +1,152 @@ |
|||||||
|
defmodule Tetris.Brick do |
||||||
|
alias Tetris.Points |
||||||
|
|
||||||
|
@x_centre 40 |
||||||
|
|
||||||
|
defstruct [ |
||||||
|
name: :i, |
||||||
|
location: {40,0}, |
||||||
|
rotation: 0, |
||||||
|
reflection: false |
||||||
|
] |
||||||
|
|
||||||
|
def new(attributes \\ []), do: __struct__(attributes) |
||||||
|
|
||||||
|
def new_random() do |
||||||
|
%__MODULE__{ |
||||||
|
name: random_name(), |
||||||
|
location: {40,0}, |
||||||
|
rotation: random_rotation(), |
||||||
|
reflection: random_reflection() |
||||||
|
} |
||||||
|
end |
||||||
|
|
||||||
|
def random_name() do |
||||||
|
~w(i l z o t)a |
||||||
|
|> Enum.random() |
||||||
|
end |
||||||
|
|
||||||
|
def random_rotation() do |
||||||
|
[0, 90, 180, 270] |
||||||
|
|> Enum.random() |
||||||
|
end |
||||||
|
|
||||||
|
|
||||||
|
def random_reflection() do |
||||||
|
[true, false] |
||||||
|
|> Enum.random |
||||||
|
end |
||||||
|
|
||||||
|
def left(brick) do |
||||||
|
%{brick| location: point_left(brick.location)} |
||||||
|
end |
||||||
|
|
||||||
|
def right(brick) do |
||||||
|
%{brick| location: point_right(brick.location)} |
||||||
|
end |
||||||
|
|
||||||
|
def down(brick) do |
||||||
|
%{brick| location: point_down(brick.location)} |
||||||
|
end |
||||||
|
|
||||||
|
def point_down({x,y}) do |
||||||
|
{x,y+1} |
||||||
|
end |
||||||
|
def point_left({x,y}) do |
||||||
|
{x-1,y} |
||||||
|
end |
||||||
|
def point_right({x,y}) do |
||||||
|
{x+1,y} |
||||||
|
end |
||||||
|
|
||||||
|
def spin_90(brick) do |
||||||
|
%{brick| rotation: rotate(brick.rotation)} |
||||||
|
end |
||||||
|
def rotate(270), do: 0 |
||||||
|
def rotate(degrees), do: degrees + 90 |
||||||
|
|
||||||
|
|
||||||
|
def shape(%{name: :l}) do |
||||||
|
[ |
||||||
|
{2,1}, |
||||||
|
{2,2}, |
||||||
|
{2,3}, {3,3} |
||||||
|
] |
||||||
|
end |
||||||
|
def shape(%{name: :i}) do |
||||||
|
[ |
||||||
|
{2,1}, |
||||||
|
{2,2}, |
||||||
|
{2,3}, |
||||||
|
{2,4} |
||||||
|
] |
||||||
|
end |
||||||
|
def shape(%{name: :o}) do |
||||||
|
[ |
||||||
|
{2,2}, {3,2}, |
||||||
|
{2,3}, {3,3} |
||||||
|
] |
||||||
|
end |
||||||
|
def shape(%{name: :z}) do |
||||||
|
[ |
||||||
|
{2,2}, |
||||||
|
{2,3}, {3,3}, |
||||||
|
{3,4} |
||||||
|
] |
||||||
|
end |
||||||
|
def shape(%{name: :t}) do |
||||||
|
[ |
||||||
|
{2,1}, |
||||||
|
{2,2}, {3,2} , |
||||||
|
{2,3} |
||||||
|
] |
||||||
|
end |
||||||
|
|
||||||
|
def prepare(brick) do |
||||||
|
brick |
||||||
|
|> shape |
||||||
|
|> Points.rotate(brick.rotation) |
||||||
|
|> Points.mirror(brick.reflection) |
||||||
|
end |
||||||
|
|
||||||
|
def to_string(brick) do |
||||||
|
brick |
||||||
|
|> prepare |
||||||
|
|> Points.to_string |
||||||
|
end |
||||||
|
|
||||||
|
def print(brick) do |
||||||
|
brick |
||||||
|
|> prepare |
||||||
|
|> Points.print |
||||||
|
|
||||||
|
brick |
||||||
|
end |
||||||
|
|
||||||
|
def colour(%{name: :i}), do: :blue |
||||||
|
def colour(%{name: :l}), do: :green |
||||||
|
def colour(%{name: :z}), do: :orange |
||||||
|
def colour(%{name: :o}), do: :red |
||||||
|
def colour(%{name: :t}), do: :yellow |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def x_centre(), do: @x_centre |
||||||
|
|
||||||
|
defimpl Inspect do |
||||||
|
import Inspect.Algebra |
||||||
|
def inspect(brick, _opts) do |
||||||
|
concat([ |
||||||
|
"\n", |
||||||
|
Tetris.Brick.to_string(brick), |
||||||
|
"\n", |
||||||
|
"location : #{inspect(brick.location)}", |
||||||
|
"\n", |
||||||
|
"reflection: #{inspect(brick.reflection)}", |
||||||
|
"\n", |
||||||
|
"rotation : #{inspect(brick.rotation)}" |
||||||
|
]) |
||||||
|
end |
||||||
|
end |
||||||
|
|
||||||
|
end |
@ -0,0 +1,68 @@ |
|||||||
|
defmodule Tetris.Points do |
||||||
|
|
||||||
|
def move_to_location(points, {x,y}=_location) do |
||||||
|
Enum.map(points,fn {dx, dy} -> {dx + x, dy + y} end ) |
||||||
|
end |
||||||
|
|
||||||
|
def transpose(points) do |
||||||
|
points |
||||||
|
|> Enum.map( fn {x,y} -> {y,x} end ) |
||||||
|
end |
||||||
|
def mirror(points) do |
||||||
|
points |
||||||
|
|> Enum.map( fn{x,y} -> {5-x,y} end ) |
||||||
|
end |
||||||
|
def mirror(points, false), do: points |
||||||
|
def mirror(points, true), do: mirror points |
||||||
|
|
||||||
|
def flip(points) do |
||||||
|
points |
||||||
|
|> Enum.map( fn{x,y} -> {x,5-y} end ) |
||||||
|
end |
||||||
|
|
||||||
|
def rotate_90(points) do |
||||||
|
#by 90 degrees clockwise |
||||||
|
points |
||||||
|
|> transpose |
||||||
|
|> mirror |
||||||
|
end |
||||||
|
|
||||||
|
def rotate(points, 0), do: points |
||||||
|
def rotate(points, degrees) do |
||||||
|
rotate( |
||||||
|
rotate_90(points), |
||||||
|
degrees - 90 |
||||||
|
) |
||||||
|
end |
||||||
|
|
||||||
|
def with_colour(points, colour) do |
||||||
|
Enum.map(points,fn point -> add_colour(point, colour) end) |
||||||
|
end |
||||||
|
|
||||||
|
defp add_colour({_x, _y, _c} = point, _colour), do: point |
||||||
|
defp add_colour({x,y}, colour), do: {x,y,colour} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#🔴 |
||||||
|
#⬜ |
||||||
|
#🟥 |
||||||
|
def to_string(points) do |
||||||
|
map = |
||||||
|
points |
||||||
|
|> Enum.map(fn key -> {key, "🟥"} end) |
||||||
|
|> Map.new() |
||||||
|
|
||||||
|
for y <- (1 .. 4), x <- (1 .. 4) do |
||||||
|
Map.get(map,{x,y},"⬜") |
||||||
|
end |
||||||
|
|> Enum.chunk_every(4) |
||||||
|
|> Enum.map(&Enum.join/1) |
||||||
|
|> Enum.join("\n") |
||||||
|
end |
||||||
|
|
||||||
|
def print(points) do |
||||||
|
IO.puts __MODULE__.to_string(points) |
||||||
|
points |
||||||
|
end |
||||||
|
end |
@ -0,0 +1,28 @@ |
|||||||
|
defmodule Tetris.MixProject do |
||||||
|
use Mix.Project |
||||||
|
|
||||||
|
def project do |
||||||
|
[ |
||||||
|
app: :tetris, |
||||||
|
version: "0.1.0", |
||||||
|
elixir: "~> 1.14", |
||||||
|
start_permanent: Mix.env() == :prod, |
||||||
|
deps: deps() |
||||||
|
] |
||||||
|
end |
||||||
|
|
||||||
|
# Run "mix help compile.app" to learn about applications. |
||||||
|
def application do |
||||||
|
[ |
||||||
|
extra_applications: [:logger] |
||||||
|
] |
||||||
|
end |
||||||
|
|
||||||
|
# Run "mix help deps" to learn about dependencies. |
||||||
|
defp deps do |
||||||
|
[ |
||||||
|
# {:dep_from_hexpm, "~> 0.3.0"}, |
||||||
|
# {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"} |
||||||
|
] |
||||||
|
end |
||||||
|
end |
@ -0,0 +1,98 @@ |
|||||||
|
defmodule BrickTest do |
||||||
|
use ExUnit.Case |
||||||
|
|
||||||
|
import Tetris.Brick |
||||||
|
alias Tetris.Points |
||||||
|
|
||||||
|
def new_brick(attributes \\[]), do: new(attributes) |
||||||
|
|
||||||
|
test "Creates a new brick" do |
||||||
|
assert new_brick().name == :i |
||||||
|
end |
||||||
|
|
||||||
|
test "Create a new random brick" do |
||||||
|
actual = new_random() |
||||||
|
|
||||||
|
assert actual.name in [:i, :l, :z, :t, :o] |
||||||
|
assert actual.rotation in [0, 90, 180, 270] |
||||||
|
assert actual.reflection in [true, false] |
||||||
|
|
||||||
|
end |
||||||
|
|
||||||
|
test "should manipulate brick" do |
||||||
|
actual = |
||||||
|
new_brick() |
||||||
|
|> left |
||||||
|
|> right |
||||||
|
|> right |
||||||
|
|> down |
||||||
|
|> spin_90 |
||||||
|
|> spin_90 |
||||||
|
|
||||||
|
assert actual.location == {x_centre() + 1,1} |
||||||
|
assert actual.rotation == 180 |
||||||
|
end |
||||||
|
|
||||||
|
test "should return points for o shape" do |
||||||
|
points = |
||||||
|
new_brick(name: :o) |
||||||
|
|> shape() |
||||||
|
|
||||||
|
assert {3,3} in points |
||||||
|
end |
||||||
|
|
||||||
|
|
||||||
|
test "should translate a list of points" do |
||||||
|
actual_points = |
||||||
|
new_brick() |
||||||
|
|> shape |
||||||
|
|> Points.move_to_location({1,1}) |
||||||
|
|> Points.move_to_location({0,1}) |
||||||
|
|
||||||
|
assert actual_points == [{3, 3}, {3, 4}, {3, 5}, {3, 6}] |
||||||
|
end |
||||||
|
|
||||||
|
test "should mirror flip rotate and rotate" do |
||||||
|
[{1,1}] |
||||||
|
|> Points.mirror |
||||||
|
|> assert_point({4,1}) |
||||||
|
|> Points. flip |
||||||
|
|> assert_point({4,4}) |
||||||
|
|> Points.rotate_90 |
||||||
|
|> assert_point({1,4}) |
||||||
|
|> Points.rotate_90 |
||||||
|
|> assert_point({1,1}) |
||||||
|
end |
||||||
|
|
||||||
|
def assert_point([actual],expected) do |
||||||
|
assert actual == expected |
||||||
|
[actual] |
||||||
|
end |
||||||
|
|
||||||
|
test "should convert brick to string" do |
||||||
|
actual = new_brick() |> Tetris.Brick.to_string |
||||||
|
|
||||||
|
expected = "⬜🟥⬜⬜\n⬜🟥⬜⬜\n⬜🟥⬜⬜\n⬜🟥⬜⬜" |
||||||
|
|
||||||
|
assert actual == expected |
||||||
|
end |
||||||
|
|
||||||
|
test "should inspect bricks" do |
||||||
|
actual = new_brick() |> inspect |
||||||
|
|
||||||
|
expected = |
||||||
|
""" |
||||||
|
|
||||||
|
⬜🟥⬜⬜ |
||||||
|
⬜🟥⬜⬜ |
||||||
|
⬜🟥⬜⬜ |
||||||
|
⬜🟥⬜⬜ |
||||||
|
location : {#{x_centre()}, 0} |
||||||
|
reflection: false |
||||||
|
rotation : 0 |
||||||
|
""" |
||||||
|
assert "#{actual}\n" == expected |
||||||
|
end |
||||||
|
|
||||||
|
|
||||||
|
end |
Loading…
Reference in new issue