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