Skip to content

Instantly share code, notes, and snippets.

@gungorkocak
Last active December 6, 2018 23:00
Show Gist options
  • Save gungorkocak/fa24a420209939f5c0e02babeb6fee40 to your computer and use it in GitHub Desktop.
Save gungorkocak/fa24a420209939f5c0e02babeb6fee40 to your computer and use it in GitHub Desktop.
#AdventOfCode 2018 #elixir #elixirlang
defmodule ChronalCoordinates do
def calc_part2(str_coords, threshold) do
coords = parse_coords(str_coords)
{bound_x, bound_y} = find_boundaries(coords)
reduce_grid({bound_x, bound_y}, 0, fn x, y, acc ->
sum = Enum.reduce(coords, 0, &sum_of_distances(&1, &2, {x, y}))
if sum < threshold, do: acc + 1, else: acc
end)
end
def calc_part1(str_coords) do
coords = parse_coords(str_coords)
boundaries = find_boundaries(coords)
grid = populate_grid(coords, boundaries)
infinites = find_infinites(grid, boundaries)
Enum.reduce(grid, %{}, fn {id, _x, _y}, acc ->
cond do
id == 0 -> acc
MapSet.member?(infinites, id) -> acc
true -> Map.update(acc, id, 1, &(&1 + 1))
end
end)
|> Enum.max_by(&elem(&1, 1))
|> elem(1)
end
@doc """
Calculates manhattan distance of two points
iex> manhattan_distance({1, 1}, {1, 5})
4
iex> manhattan_distance({1, 5}, {10, 8})
12
"""
def manhattan_distance({x1, y1}, {x2, y2}) do
abs(x1 - x2) + abs(y1 - y2)
end
def sum_of_distances({_, coord_x, coord_y}, acc, {x, y}) do
acc + manhattan_distance({x, y}, {coord_x, coord_y})
end
def parse_coords(str_coords) do
Enum.reduce(str_coords, {1, []}, fn str, {id, acc} ->
[x, y] = String.split(str, ", ")
{id + 1, [{id, String.to_integer(x), String.to_integer(y)} | acc]}
end)
|> elem(1)
|> Enum.reverse()
end
def find_boundaries(coords \\ []) do
Enum.reduce(coords, {0, 0}, fn {_id, x, y}, {max_x, max_y} ->
{max(x + 1, max_x), max(y + 1, max_y)}
end)
end
def populate_grid(points, {bound_x, bound_y}) do
reduce_grid({bound_x, bound_y}, [], fn x, y, acc ->
{id, _min_distance, _count} =
Enum.reduce(points, {-1, :infinity, 0}, fn {id, px, py}, {old_id, min_distance, count} ->
distance = manhattan_distance({x, y}, {px, py})
cond do
distance < min_distance -> {id, distance, 1}
distance == min_distance -> {0, min_distance, count + 1}
true -> {old_id, min_distance, count}
end
end)
[{id, x, y} | acc]
end)
|> Enum.reverse()
end
def find_infinites(coords, boundaries) do
Enum.reduce(coords, MapSet.new(), &reduce_infinite(&1, &2, boundaries))
end
defp reduce_infinite({id, x, y}, acc, {bound_x, bound_y})
when (x == bound_x or y == bound_y or x == 0 or y == 0) and id != 0 do
MapSet.put(acc, id)
end
defp reduce_infinite(_, acc, _), do: acc
defp reduce_grid({bound_x, bound_y}, acc, fun) do
Enum.reduce(0..bound_y, acc, fn y, acc ->
Enum.reduce(0..bound_x, acc, fn x, acc ->
fun.(x, y, acc)
end)
end)
end
end
test = fn ->
defmodule ChronalCoordinatesTest do
use ExUnit.Case, async: true
import ChronalCoordinates
test "calculates manhattan distance" do
assert 4 == manhattan_distance({1, 1}, {1, 5})
assert 12 == manhattan_distance({1, 5}, {10, 8})
end
test "parses coordinates" do
assert [{1, 2, 2}, {2, 3, 4}] == parse_coords(["2, 2", "3, 4"])
end
test "finds boundaries" do
example = [
{1, 1, 1},
{2, 1, 6},
{3, 8, 3},
{4, 3, 4},
{5, 5, 5},
{6, 8, 9}
]
assert {9, 10} == find_boundaries(example)
end
test "populates grid" do
example = [
{1, 1, 1},
{2, 1, 6},
{3, 8, 3},
{4, 3, 4},
{5, 5, 5},
{6, 8, 9}
]
result = [
{1, 0, 0},
{1, 1, 0},
{1, 2, 0},
{1, 3, 0},
{1, 4, 0},
{0, 5, 0},
{3, 6, 0},
{3, 7, 0},
{3, 8, 0},
{3, 9, 0},
{1, 0, 1},
{1, 1, 1},
{1, 2, 1},
{1, 3, 1},
{1, 4, 1},
{0, 5, 1},
{3, 6, 1},
{3, 7, 1},
{3, 8, 1},
{3, 9, 1},
{1, 0, 2},
{1, 1, 2},
{1, 2, 2},
{4, 3, 2},
{4, 4, 2},
{5, 5, 2},
{3, 6, 2},
{3, 7, 2},
{3, 8, 2},
{3, 9, 2},
{1, 0, 3},
{1, 1, 3},
{4, 2, 3},
{4, 3, 3},
{4, 4, 3},
{5, 5, 3},
{3, 6, 3},
{3, 7, 3},
{3, 8, 3},
{3, 9, 3},
{0, 0, 4},
{0, 1, 4},
{4, 2, 4},
{4, 3, 4},
{4, 4, 4},
{5, 5, 4},
{5, 6, 4},
{3, 7, 4},
{3, 8, 4},
{3, 9, 4},
{2, 0, 5},
{2, 1, 5},
{0, 2, 5},
{4, 3, 5},
{5, 4, 5},
{5, 5, 5},
{5, 6, 5},
{5, 7, 5},
{3, 8, 5},
{3, 9, 5},
{2, 0, 6},
{2, 1, 6},
{2, 2, 6},
{0, 3, 6},
{5, 4, 6},
{5, 5, 6},
{5, 6, 6},
{5, 7, 6},
{0, 8, 6},
{0, 9, 6},
{2, 0, 7},
{2, 1, 7},
{2, 2, 7},
{0, 3, 7},
{5, 4, 7},
{5, 5, 7},
{5, 6, 7},
{6, 7, 7},
{6, 8, 7},
{6, 9, 7},
{2, 0, 8},
{2, 1, 8},
{2, 2, 8},
{0, 3, 8},
{5, 4, 8},
{5, 5, 8},
{6, 6, 8},
{6, 7, 8},
{6, 8, 8},
{6, 9, 8},
{2, 0, 9},
{2, 1, 9},
{2, 2, 9},
{0, 3, 9},
{6, 4, 9},
{6, 5, 9},
{6, 6, 9},
{6, 7, 9},
{6, 8, 9},
{6, 9, 9}
]
boundries = {9, 9}
assert result == populate_grid(example, boundries)
end
test "find infinites" do
example = [
{1, 0, 0},
{1, 1, 0},
{1, 2, 0},
{1, 3, 0},
{1, 4, 0},
{0, 5, 0},
{3, 6, 0},
{3, 7, 0},
{3, 8, 0},
{3, 9, 0},
{1, 0, 1},
{1, 1, 1},
{1, 2, 1},
{1, 3, 1},
{1, 4, 1},
{0, 5, 1},
{3, 6, 1},
{3, 7, 1},
{3, 8, 1},
{3, 9, 1},
{1, 0, 2},
{1, 1, 2},
{1, 2, 2},
{4, 3, 2},
{4, 4, 2},
{5, 5, 2},
{3, 6, 2},
{3, 7, 2},
{3, 8, 2},
{3, 9, 2},
{1, 0, 3},
{1, 1, 3},
{4, 2, 3},
{4, 3, 3},
{4, 4, 3},
{5, 5, 3},
{3, 6, 3},
{3, 7, 3},
{3, 8, 3},
{3, 9, 3},
{0, 0, 4},
{0, 1, 4},
{4, 2, 4},
{4, 3, 4},
{4, 4, 4},
{5, 5, 4},
{5, 6, 4},
{3, 7, 4},
{3, 8, 4},
{3, 9, 4},
{2, 0, 5},
{2, 1, 5},
{0, 2, 5},
{4, 3, 5},
{5, 4, 5},
{5, 5, 5},
{5, 6, 5},
{5, 7, 5},
{3, 8, 5},
{3, 9, 5},
{2, 0, 6},
{2, 1, 6},
{2, 2, 6},
{0, 3, 6},
{5, 4, 6},
{5, 5, 6},
{5, 6, 6},
{5, 7, 6},
{0, 8, 6},
{0, 9, 6},
{2, 0, 7},
{2, 1, 7},
{2, 2, 7},
{0, 3, 7},
{5, 4, 7},
{5, 5, 7},
{5, 6, 7},
{6, 7, 7},
{6, 8, 7},
{6, 9, 7},
{2, 0, 8},
{2, 1, 8},
{2, 2, 8},
{0, 3, 8},
{5, 4, 8},
{5, 5, 8},
{6, 6, 8},
{6, 7, 8},
{6, 8, 8},
{6, 9, 8},
{2, 0, 9},
{2, 1, 9},
{2, 2, 9},
{0, 3, 9},
{6, 4, 9},
{6, 5, 9},
{6, 6, 9},
{6, 7, 9},
{6, 8, 9},
{6, 9, 9}
]
boundries = {9, 9}
result = MapSet.new([1, 2, 3, 6])
assert result == find_infinites(example, boundries)
end
test "solves part#1" do
example =
"""
1, 1
1, 6
8, 3
3, 4
5, 5
8, 9
"""
|> String.split("\n", trim: true)
assert 17 == calc_part1(example)
end
test "solves part#2" do
example =
"""
1, 1
1, 6
8, 3
3, 4
5, 5
8, 9
"""
|> String.split("\n", trim: true)
assert 16 == calc_part2(example, 32)
end
end
end
case System.argv() do
["--test"] ->
ExUnit.start()
test.()
_ ->
# File.read!("./furkan_input.txt")
result1 =
File.read!("./6_chronal_coordinates_input.txt")
|> String.split("\n", trim: true)
|> ChronalCoordinates.calc_part1()
IO.puts("Result of part#1 is... #{result1}")
result2 =
File.read!("./6_chronal_coordinates_input.txt")
|> String.split("\n", trim: true)
|> ChronalCoordinates.calc_part2(10_000)
IO.puts("Result of part#2 is... #{result2}")
end
224, 153
176, 350
353, 241
207, 59
145, 203
123, 210
113, 203
191, 241
172, 196
209, 249
260, 229
98, 231
305, 215
258, 141
337, 282
156, 140
325, 197
179, 279
283, 233
317, 150
305, 245
67, 109
251, 140
245, 59
173, 105
59, 173
257, 70
269, 110
102, 162
179, 180
324, 112
357, 311
317, 245
239, 112
321, 220
133, 97
334, 99
117, 102
133, 112
222, 316
68, 296
150, 287
263, 263
66, 347
128, 118
63, 202
68, 236
264, 122
77, 243
92, 110

Getting Started

  1. Make sure you have elixir installed and running. (Hint: elixir --version)
  2. Download all gist files and run elixir 6_chronal_coordinates.ex. That will compile the code and give you results.
  3. Run elixir 5_chronal_coordinates.ex --test to run tests.
  4. Have more fun!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment