4
0

More than 1 year has passed since last update.

# Advent Of Code 2021 (Day 3: Binary Diagnostic)をElixirで楽しむ

Last updated at Posted at 2022-04-20

Advent Calendar 2022 104日目1の記事です。
I'm looking forward to 12/25,2022

# はじめに

この記事は、Advent Of Code 2021 Day 3: Binary DiagnosticElixirで楽しんでみます。

# 私の回答

`input`はサンプルです。
ログインをすると、たくさんあるインプットデータがみえます。

## Part 1

``````input = """
00100
11110
10110
10111
10101
01111
00111
11100
10000
11001
00010
01010
"""

map = input
|> String.split("\n", trim: true)
|> Enum.map(&String.codepoints/1)
|> Enum.map(&Enum.with_index(&1))
|> Enum.reduce(%{}, fn list, acc ->
Enum.reduce(list, acc, fn {number, index}, acc ->
number = String.to_integer(number)
Map.update(acc, index, [number], & &1 ++ [number])
end)
end)

gamma_rate = 0..(map_size(map) - 1)
|> Enum.map(fn i -> map[i] end)
|> Enum.map(fn list -> if(Enum.count(list, & &1 == 0) > Enum.count(list, & &1 == 1), do: "0", else: "1") end)
|> Enum.join()
|> String.to_integer(2)

require Bitwise

epsilon_rate = List.duplicate("1", map_size(map))
|> Enum.join()
|> String.to_integer(2)
|> Bitwise.bxor(gamma_rate)

gamma_rate * epsilon_rate
``````

## Part 2

``````input = """
00100
11110
10110
10111
10101
01111
00111
11100
10000
11001
00010
01010
"""

list_of_lists = input
|> String.split("\n", trim: true)
|> Enum.map(&String.codepoints/1)
|> Enum.map(fn list -> Enum.map(list, &String.to_integer/1) end)

build_map = fn list_of_lists ->
list_of_lists
|> Enum.map(&Enum.with_index(&1))
|> Enum.reduce(%{}, fn list, acc ->
Enum.reduce(list, acc, fn {number, index}, acc ->
Map.update(acc, index, [number], & &1 ++ [number])
end)
end)
end

oxygen_generator_rating = 0..(map_size(build_map.(list_of_lists)) - 1)
|> Enum.reduce_while({list_of_lists, build_map.(list_of_lists)}, fn key, {list_of_lists, map} ->
zero_count = map[key] |> Enum.count(& &1 == 0)
one_count = map[key] |> Enum.count(& &1 == 1)
list_of_lists = if one_count >= zero_count do
Enum.filter(list_of_lists, fn list -> Enum.at(list, key) == 1 end)
else
Enum.filter(list_of_lists, fn list -> Enum.at(list, key) == 0 end)
end

cont = if Enum.count(list_of_lists) == 1, do: :halt, else: :cont

{cont, {list_of_lists, build_map.(list_of_lists)}}
end)
|> elem(0)
|> Enum.at(0)
|> Enum.map(&Integer.to_string/1)
|> Enum.join()
|> String.to_integer(2)

co2_scrubber_rating = 0..(map_size(build_map.(list_of_lists)) - 1)
|> Enum.reduce_while({list_of_lists, build_map.(list_of_lists)}, fn key, {list_of_lists, map} ->
zero_count = map[key] |> Enum.count(& &1 == 0)
one_count = map[key] |> Enum.count(& &1 == 1)
list_of_lists = if zero_count <= one_count do
Enum.filter(list_of_lists, fn list -> Enum.at(list, key) == 0 end)
else
Enum.filter(list_of_lists, fn list -> Enum.at(list, key) == 1 end)
end

cont = if Enum.count(list_of_lists) == 1, do: :halt, else: :cont

{cont, {list_of_lists, build_map.(list_of_lists)}}
end)
|> elem(0)
|> Enum.at(0)
|> Enum.map(&Integer.to_string/1)
|> Enum.join()
|> String.to_integer(2)

oxygen_generator_rating * co2_scrubber_rating
``````

It works!
Amazing!

お見逃し無く！

# お手本

José ValimさんがLivebook楽しまれている動画があります。
José Valimさんは、Elixirの作者です！

いきなり正解を書くわけではなく、少しずつ試しながら作っていって、リファクタしていくさまがJosé Valimさんの息遣いでみれるのでとても参考になります。

お手本

## Part 1

``````import Bitwise

numbers =
input
|> String.split("\n", trim: true)
|> Enum.map(&(&1 |> String.to_charlist() |> List.to_tuple()))

[sample | _] = numbers
number_length = tuple_size(sample)
half = div(length(numbers), 2)

gamma_as_list =
for pos <- 0..number_length - 1 do
zero_count = Enum.count_until(numbers, &(elem(&1, pos) == ?0), half + 1)
if zero_count > half, do: ?0, else: ?1
end

gamma = List.to_integer(gamma_as_list, 2)
mask = 2**number_length - 1
epsilon = ~~~gamma &&& mask
gamma * epsilon
``````

for/1の使い方がうまい！

## Part 2

``````defmodule Recursion do
defp recur([number], _pos, _fun) do
number
|> Tuple.to_list()
|> List.to_integer(2)
end

defp recur(numbers, pos, fun) do
zero_count = Enum.count(numbers, &elem(&1, pos) == ?0)
one_count = length(numbers) - zero_count
to_keep = fun.(zero_count, one_count)
numbers = Enum.filter(numbers, &elem(&1, pos) == to_keep)
recur(numbers, pos + 1, fun)
end

def o2(numbers) do
recur(numbers, 0, fn zero_count, one_count ->
if one_count >= zero_count, do: ?1, else: ?0
end)
end

def co2(numbers) do
recur(numbers, 0, fn zero_count, one_count ->
if zero_count <= one_count, do: ?0, else: ?1
end)
end
end

numbers =
input
|> String.split("\n", trim: true)
|> Enum.map(&(&1 |> String.to_charlist() |> List.to_tuple()))

o2 = Recursion.o2(numbers) |> IO.inspect()
co2 = Recursion.co2(numbers) |> IO.inspect()
o2 * co2
``````

# Wrapping up

Advent Of Code 2021Day 3: Binary DiagnosticElixirで楽しんでみました。
Day 25まであるので引き続き楽しんでいきたいとおもいます。
だんだん、私には難しくなってきました

It works!
Amazing!

Enjoy Elixir
\$\huge{Enjoy\ Elixir🚀}\$

I organize autoracex.
And I take part in NervesJP, fukuoka.ex, EDI, tokyo.ex, Pelemay.

We Are The Alchemists, my friends!

4
0
0

Register as a new user and use Qiita more conveniently

1. You get articles that match your needs
2. You can efficiently read back useful information
3. You can use dark theme
What you can do with signing up
4
0