LoginSignup
8
0

闘魂Elixir ── Advent of code 2023 Day 7をElixirで楽しむ

Last updated at Posted at 2023-12-07

$\huge{元氣ですかーーーーッ!!!}$
$\huge{元氣があればなんでもできる!}$

$\huge{闘魂とは己に打ち克つこと。}$
$\huge{そして闘いを通じて己の魂を磨いていく}$
$\huge{ことだと思います}$

はじめに

今年もいよいよやってまいりました! :santa::santa_tone1::santa_tone2::santa_tone3::santa_tone4::santa_tone5:
Elixirで、Advent of code 2023の問題を解いてみます。

1日1題ずつ問題が出題されます。
実行時間は問われません。

What is Elixir ?

Elixirという素敵なプログラミング言語があるのですね。
その素敵具合は「Elixir Saves Pinterest $2 Million a Year In Server Costs」によく現れています。開発者も経営者もこの事実に瞠目することでしょう。 $2 Million/年の節約ですってよ!、奥さん。

Day 7: Camel Cards

Day 7: Camel Cardsを解いてみます。
問題はリンク先をご参照ください。

Google翻訳を使って問題を理解しました。
英文が(私にとって長く)なかなか意味がわかりませんでした。

ポーカーみたいな問題でした。

私の答え Part 1

私の答えです。
折りたたんでおきます。
▶を押して開いてください。


私の答え

強い手、弱い手、強いカード、弱いカードの大小比較があるので適当に数字を割り振ったほうが比較がしやすいとおもいます。
このへんが解法のヒントだとおもいます。

input = """
32T3K 765
T55J5 684
KK677 28
KTJJT 220
QQQJA 483
"""


defmodule Awesome do
  def run(input) do
    parse(input)
    |> Enum.map(fn {hand, bid} ->
      {type(hand), hand, bid}
    end)
    |> Enum.sort(fn {type1, hand1, _}, {type2, hand2, _} ->
      sorter({type1, hand1}, {type2, hand2})
    end)
    |> Enum.with_index(1)
    |> Enum.map(fn {{_, _, bid}, rank} -> bid * rank end)
    |> Enum.sum()
  end

  defp sorter({type1, _hand1}, {type2, _hand2}) when type1 > type2, do: false
  defp sorter({type1, hand1}, {type2, hand2}) when type1 == type2, do: do_sorter(hand1, hand2)
  defp sorter({type1, _hand1}, {type2, _hand2}) when type1 < type2, do: true

  defp do_sorter(hand1, hand2) do
    [
      Enum.map(hand1, fn c -> Map.get(map(), c) end),
      Enum.map(hand2, fn c -> Map.get(map(), c) end)
    ]
    |> Enum.zip()
    |> Enum.reduce_while(nil, fn
      {a, a}, nil -> {:cont, nil}
      {a, b}, nil when a > b -> {:halt, false}
      {a, b}, nil when a < b -> {:halt, true}
    end)
  end

  defp map do
    %{
      ?A => 12,
      ?K => 11,
      ?Q => 10,
      ?J => 9,
      ?T => 8,
      ?9 => 7,
      ?8 => 6,
      ?7 => 5,
      ?6 => 4,
      ?5 => 3,
      ?4 => 2,
      ?3 => 1,
      ?2 => 0
    }
  end

  defp type(list) do
    list
    |> Enum.frequencies()
    |> Map.values()
    |> Enum.sort(&>/2)
    |> do_type()
  end

  def do_type([5]), do: 10
  def do_type([4, 1]), do: 9
  def do_type([3, 2]), do: 8
  def do_type([3, 1, 1]), do: 7
  def do_type([2, 2, 1]), do: 6
  def do_type([2, 1, 1, 1]), do: 5
  def do_type([1, 1, 1, 1, 1]), do: 4

  defp parse(input) do
    input
    |> String.split("\n", trim: true)
    |> Enum.map(fn s ->
      [hand, bid] = String.split(s, " ")
      {String.to_charlist(hand), String.to_integer(bid)}
    end)
  end
end

Awesome.run(input)

私の答え Part 2

私の答えです。
折りたたんでおきます。
▶を押して開いてください。


私の答え
defmodule Awesome2 do
  def run(input) do
    parse(input)
    |> Enum.map(fn {hand, bid} ->
      {type(hand), hand, bid}
    end)
    |> Enum.sort(fn {type1, hand1, _}, {type2, hand2, _} ->
      sorter({type1, hand1}, {type2, hand2})
    end)
    |> Enum.with_index(1)
    |> Enum.map(fn {{_, _, bid}, rank} -> bid * rank end)
    |> Enum.sum()
  end

  defp sorter({type1, _hand1}, {type2, _hand2}) when type1 > type2, do: false
  defp sorter({type1, hand1}, {type2, hand2}) when type1 == type2, do: do_sorter(hand1, hand2)
  defp sorter({type1, _hand1}, {type2, _hand2}) when type1 < type2, do: true

  defp do_sorter(hand1, hand2) do
    [
      Enum.map(hand1, fn c -> Map.get(map(), c) end),
      Enum.map(hand2, fn c -> Map.get(map(), c) end)
    ]
    |> Enum.zip()
    |> Enum.reduce_while(nil, fn
      {a, a}, nil -> {:cont, nil}
      {a, b}, nil when a > b -> {:halt, false}
      {a, b}, nil when a < b -> {:halt, true}
    end)
  end

  defp map do
    %{
      ?A => 12,
      ?K => 11,
      ?Q => 10,
      ?T => 8,
      ?9 => 7,
      ?8 => 6,
      ?7 => 5,
      ?6 => 4,
      ?5 => 3,
      ?4 => 2,
      ?3 => 1,
      ?2 => 0,
      ?J => -1
    }
  end

  defp type(list) do
    frequencies = list |> Enum.frequencies()
    j_cards = Map.get(frequencies, ?J, 0)

    case j_cards do
      5 ->
        [5]

      4 ->
        [5]

      3 ->
        case frequencies |> Map.values() |> Enum.sort(&>/2) do
          [3, 2] -> [5]
          [3, 1, 1] -> [4, 1]
        end

      2 ->
        case frequencies |> Map.values() |> Enum.sort(&>/2) do
          [3, 2] -> [5]
          [2, 2, 1] -> [4, 1]
          [2, 1, 1, 1] -> [3, 1, 1]
        end

      1 ->
        case frequencies |> Map.values() |> Enum.sort(&>/2) do
          [4, 1] -> [5]
          [3, 1, 1] -> [4, 1]
          [2, 2, 1] -> [3, 2]
          [2, 1, 1, 1] -> [3, 1, 1]
          [1, 1, 1, 1, 1] -> [2, 1, 1, 1]
        end

      0 ->
        frequencies
        |> Map.values()
        |> Enum.sort(&>/2)
    end
    |> do_type()
  end

  def do_type([5]), do: 10
  def do_type([4, 1]), do: 9
  def do_type([3, 2]), do: 8
  def do_type([3, 1, 1]), do: 7
  def do_type([2, 2, 1]), do: 6
  def do_type([2, 1, 1, 1]), do: 5
  def do_type([1, 1, 1, 1, 1]), do: 4

  defp parse(input) do
    input
    |> String.split("\n", trim: true)
    |> Enum.map(fn s ->
      [hand, bid] = String.split(s, " ")
      {String.to_charlist(hand), String.to_integer(bid)}
    end)
  end
end

Awesome2.run(input)

解けました :tada::tada::tada:

さいごに

Advent of code 2023Day 7: Camel CardsElixirで解きました。
Advent of code 2023は己との闘い、まさに闘魂です。

リポジトリにあげておきます。

人類は不老不死の霊薬を意味する素敵なプログラミング言語Elixirを手に入れました。並行処理を他のプログラミング言語よりも比較的容易に書くことができます。それはきっとコンピュータ資源を有効活用できることにつながるでしょう。巡り巡って世界平和に貢献できることでしょう。

さあ、そこのあなたもElixirの世界へようこそ。
手始めにエリクサーチなんていかがでしょうか。私のオススメです。


闘魂とは、 「己に打ち克つこと。そして闘いを通じて己の魂を磨いていくことである」 との猪木さんの言葉をそのまま胸に刻み込んでいます。
知っているだけで終わらせることなく、実行する、断行する、一歩を踏み出すことを自らの行動で示していきたいとおもいます。
アントニオ猪木さんのメッセージから元氣をもらったものとして、それを次代に語り継ぎ、自分自身が「闘魂」を体現するものでありたいとおもいます。


$\huge{元氣ですかーーーーッ!!!}$
$\huge{元氣があればなんでもできる!}$
$\huge{1、2、3 ぁっダァー!}$

8
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
8
0