明けぬれば暮るるものとは知りながらなほ恨めしき朝ぼらけかな
Advent Calendar 2022 104日目1の記事です。
I'm looking forward to 12/25,2022
私のAdvent Calendar 2022 一覧。
はじめに
この記事は、Advent Of Code 2021 Day 3: Binary DiagnosticをElixirで楽しんでみます。
私はGitHubでログインしました。
私の回答
私の回答です。
私の回答
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さんのお手本はとても勉強になります。
お見逃し無く!
お手本
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 DiagnosticをElixirで楽しんでみました。
Day 25まであるので引き続き楽しんでいきたいとおもいます。
だんだん、私には難しくなってきました
It works!
Amazing!
自分で解いてみて、なんだかイマイチだなあとおもいながら、動画をみることでJosé Valimさんに特別家庭教師をしてもらっている気に勝手になっています 。
海綿が水を吸うように、Elixirのイケている書き方を吸収しています。
伸びしろしかありません。
Enjoy Elixir
$\huge{Enjoy\ Elixir🚀}$
以上です。
I organize autoracex.
And I take part in NervesJP, fukuoka.ex, EDI, tokyo.ex, Pelemay.
I hope someday you'll join us.
We Are The Alchemists, my friends!
We appreciate this shoutout, Torifuku! pic.twitter.com/dThmJg4CYN
— ClickUp (@clickup) April 11, 2022