shritesh

shritesh

I mapped both the cards and every possible hand to numeric values and sorted them. In part 2 I could only think of replacing the jokers with all unique values in the hand. There’s probably a better way.

https://github.com/shritesh/advent/blob/main/2023/07.livemd

Showing Posts 1 to 10

Aetherus

Aetherus

I did almost the same thing. My code is still messy, so I’ll clean it up and post it later.

By the way, I’m sorting things like [1, 1, 1, 1, 1] and [3, 2] directly instead of converting them to a number then sort.

bjorng

bjorng

Erlang Core Team
Aetherus

Aetherus

I accidentally removed my code, so I wrote it again and didn’t bother to refactor it.

Prep

{:ok, puzzle_input} =
  KinoAOC.download_puzzle("2023", "7", System.fetch_env!("LB_AOC_SESSION"))

strengths =
  ?2..?9
  |> Map.new(&{&1, &1 - ?0})
  |> Map.merge(%{
    ?T => 10,
    ?J => 11,
    ?Q => 12,
    ?K => 13,
    ?A => 14
  })

Part 1

puzzle_input
|> String.split()
|> Stream.chunk_every(2)
|> Stream.map(fn [hand, bid] ->
  cards = String.to_charlist(hand)
  freqs = cards |> Enum.frequencies() |> Map.values() |> Enum.sort(:desc)
  scores = Enum.map(cards, &strengths[&1])
  {freqs, scores, String.to_integer(bid)}
end)
|> Enum.sort()
|> Stream.map(&elem(&1, 2))
|> Stream.with_index(1)
|> Stream.map(fn {bid, rank} -> bid * rank end)
|> Enum.sum()

Part 2

strengths = %{strengths | ?J => 1}

puzzle_input
|> String.split()
|> Stream.chunk_every(2)
|> Stream.map(fn [hand, bid] ->
  cards = String.to_charlist(hand)
  freqs = cards |> Enum.frequencies()
  {jokers, freqs} = Map.pop(freqs, ?J, 0)
  freqs = freqs |> Map.values() |> Enum.sort(:desc)
  freqs = (freqs == []) && [5] || [hd(freqs) + jokers | tl(freqs)]
  scores = Enum.map(cards, &strengths[&1])
  {freqs, scores, String.to_integer(bid)}
end)
|> Enum.sort()
|> Stream.map(&elem(&1, 2))
|> Stream.with_index(1)
|> Stream.map(fn {bid, rank} -> bid * rank end)
|> Enum.sum()
code-shoily

code-shoily

I loved doing this. The way I decided to calculate rank through pattern matching ended up being visual cue to compute the J assisted ranking.

advent_of_code/lib/2023/day_07.ex at master · code-shoily/advent_of_code (github.com)

This felt so natural!

One valuable lesson learned though.

My smaller? function had @card_rank_1 as default parameter. And it is recursive, so when I called it with @card_rank_2 during part 2, I forgot to provide the second parameter on the recursive calls, so subsequent matches were lies! And to make it worse, sample data were immune to this ranking algorithm and kept giving me right answer so I spent some time in frustration.

lud

lud

I was struggling on part 1 and I don’t know why. I finally made it work with this

|> Enum.sort_by(fn {htype, cards, _} -> {htype, cards} end)

But (for whatever reason) I started by doing a custom sort and I don’t understand why it does not work:

    |> Enum.sort(fn
      {htype_a, _, _}, {htype_b, _, _} when htype_a < htype_b -> true
      {htype_a, _, _}, {htype_b, _, _} when htype_a > htype_b -> false
      {same, [x, x, x, x, x], _}, {same, [x, x, x, x, x], _} -> raise "same"
      {same, [x, x, x, x, a], _}, {same, [x, x, x, x, b], _} -> a < b
      {same, [x, x, x, a | _], _}, {same, [x, x, x, b | _], _} -> a < b
      {same, [x, x, a | _], _}, {same, [x, x, b | _], _} -> a < b
      {same, [x, a | _], _}, {same, [x, b | _], _} -> a < b
      {same, [a | _], _}, {same, [b | _], _} -> a < b
    end)

It should be the same no ? The result I had with that was just -1 from the actual answer.

Same result if I move the {same clauses on top, and it works with the example.
Please help mee see what is wrong with that function :slight_smile:

EDIT: Ah ! Found it. It was so obvious. all the x, x, x are trying to match the same value. I am stupid :smiley:

Going for part 2 now

seeplusplus

seeplusplus

In part 2 I could only think of replacing the jokers with all unique values in the hand

Heh, better than I did, I just brute forced and tried every card possible

/shrug
https://github.com/seeplusplus/aoc-elixir/blob/main/lib/2023/day7.ex

lud

lud

Part 2 was easier than I thought at first, thanks to the rule of “first card wins” we do not have to compute which figure the joker should be, just the hand type.

So here is my solution, a bit ugly because of the big matching cases, but otherwise straightforward.

defmodule AdventOfCode.Y23.Day7 do
  alias AoC.Input, warn: false

  def read_file(file, _part) do
    Input.stream!(file, trim: true)
  end

  def parse_input(input, part) do
    Enum.map(input, &parse_line(&1, part))
  end

  defp parse_line(<<a, b, c, d, e, 32, bid::binary>>, part) do
    cards = [parse_card(a, part), parse_card(b, part), parse_card(c, part), parse_card(d, part), parse_card(e, part)]
    bid = String.to_integer(bid)
    {cards, bid}
  end

  @joker 0
  defp parse_card(?2, _), do: 2
  defp parse_card(?3, _), do: 3
  defp parse_card(?4, _), do: 4
  defp parse_card(?5, _), do: 5
  defp parse_card(?6, _), do: 6
  defp parse_card(?7, _), do: 7
  defp parse_card(?8, _), do: 8
  defp parse_card(?9, _), do: 9
  defp parse_card(?T, _), do: 10
  defp parse_card(?J, :part_one), do: 11
  defp parse_card(?J, :part_two), do: @joker
  defp parse_card(?Q, _), do: 12
  defp parse_card(?K, _), do: 13
  defp parse_card(?A, _), do: 14

  def part_one(problem), do: solve(problem, :part_one)
  def part_two(problem), do: solve(problem, :part_two)

  defp solve(problem, part) do
    problem
    |> Enum.map(fn {cards, bid} -> {htype(cards, part), cards, bid} end)
    |> Enum.sort_by(fn {htype, cards, _} -> {htype, cards} end)
    |> Enum.with_index(1)
    |> Enum.reduce(0, fn {{_, _, bid}, rank}, acc -> acc + bid * rank end)
  end

  defp htype(cards, part) do
    cards
    |> Enum.sort()
    |> Enum.group_by(& &1)
    |> Map.values()
    |> Enum.sort_by(&length/1, :desc)
    |> classed_htype(part)
  end

  @five_of 9999
  @four_of 8888
  @full_house 7777
  @three_of 6666
  @two_pairs 5555
  @one_pair 4444
  @nothing 3333

  defp classed_htype(cards, :part_one) do
    case cards do
      [[_, _, _, _, _]] -> @five_of
      [[_, _, _, _], [_]] -> @four_of
      [[_, _, _], [_, _]] -> @full_house
      [[_, _, _], [_], [_]] -> @three_of
      [[_, _], [_, _], [_]] -> @two_pairs
      [[_, _], [_], [_], [_]] -> @one_pair
      _ -> @nothing
    end
  end

  defp classed_htype(cards, :part_two) do
    case cards do
      [[_, _, _, _, _]] -> @five_of
      #
      [[@joker, _, _, _], [_]] -> @five_of
      [[_, _, _, _], [@joker]] -> @five_of
      [[_, _, _, _], [_]] -> @four_of
      #
      [[@joker, _, _], [_, _]] -> @five_of
      [[_, _, _], [@joker, _]] -> @five_of
      [[_, _, _], [_, _]] -> @full_house
      #
      [[@joker, _, _], [_], [_]] -> @four_of
      [[_, _, _], [@joker], [_]] -> @four_of
      [[_, _, _], [_], [@joker]] -> @four_of
      [[_, _, _], [_], [_]] -> @three_of
      #
      [[@joker, _], [_, _], [_]] -> @four_of
      [[_, _], [@joker, _], [_]] -> @four_of
      [[_, _], [_, _], [@joker]] -> @full_house
      [[_, _], [_, _], [_]] -> @two_pairs
      #
      [[@joker, _], [_], [_], [_]] -> @three_of
      [[_, _], [@joker], [_], [_]] -> @three_of
      [[_, _], [_], [@joker], [_]] -> @three_of
      [[_, _], [_], [_], [@joker]] -> @three_of
      [[_, _], [_], [_], [_]] -> @one_pair
      #
      [[@joker], [_], [_], [_], [_]] -> @one_pair
      [[_], [@joker], [_], [_], [_]] -> @one_pair
      [[_], [_], [@joker], [_], [_]] -> @one_pair
      [[_], [_], [_], [@joker], [_]] -> @one_pair
      [[_], [_], [_], [_], [@joker]] -> @one_pair
      [[_], [_], [_], [_], [_]] -> @nothing
    end
  end
end

hauleth

hauleth

Day 07

Setup:

defmodule Day07 do
  def rate({hand, _}) do
    {jokers, rest} = Map.pop(Enum.frequencies(hand), -1, 0)

    pos =
      rest
      |> Map.values()
      |> Enum.sort(:desc)
      |> case do
        [] -> [jokers]
        [v | rest] -> [v + jokers | rest]
      end

    {pos, hand}
  end

  @cards ~C[TJQKA] |> Enum.with_index(10) |> Map.new()

  def card_values(hand) do
    for <<card <- hand>> do
      Map.get(@cards, card, card - ?0)
    end
  end

  def rate_bids(hands) do
    hands
    |> Enum.with_index(1)
    |> Enum.reduce(0, fn {{_, bid}, idx}, acc ->
      acc + bid * idx
    end)
  end
end

Parse:

hands =
  puzzle_input
  |> String.split("\n")
  |> Enum.map(fn <<hand::binary-5>> <> " " <> bid ->
    {Day07.card_values(hand), String.to_integer(bid)}
  end)

Part 1:

hands
|> Enum.sort_by(&Day07.rate/1)
|> Day07.rate_bids()

Part 2:

hands
|> Enum.map(fn {hand, bid} -> {Enum.map(hand, &if(&1 == 11, do: -1, else: &1)), bid} end)
|> Enum.sort_by(&Day07.rate/1)
|> Day07.rate_bids()

Part 2 is simple when you notice that you need to add jokers only to the most frequent card, so no need for testing all combinations and result is blazing fast.

pehbehbeh

pehbehbeh

I used DataFrames with Explorer for the first time today. May be overkill, but I learned a lot.

https://github.com/pehbehbeh/adventofcode/blob/main/2023/07.livemd

It was nice to be able to tinker directly in the results via LiveBook:

rugyoga

rugyoga

I got Enum.frequencies and Enum.sort to do all the heavy lifting:

import AOC

aoc 2023, 7 do
  def p1(input) do
    compute(input, &(&1), &map/1)
  end

  def p2(input) do
    compute(input, &go_wild/1, &map2/1)
  end

  def compute(input, f, g) do
    input
    |> String.split("\n")
    |> Enum.map(&(parse(&1, f, g)))
    |> Enum.sort()
    |> Enum.with_index(1)
    |> Enum.map(fn {{_,bid}, value} -> bid * value end)
    |> Enum.sum
  end

  def map("A"), do: 14
  def map("K"), do: 13
  def map("Q"), do: 12
  def map("J"), do: 11
  def map("T"), do: 10
  def map(s), do: String.to_integer(s)

  def map2("J"), do: 0
  def map2(other), do: map(other)

  def parse(line, f, g) do
    line
    |> String.split()
    |> then(fn [hand, bid] ->

      {{
        hand
        |> String.split("", trim: true)
        |> Enum.frequencies()
        |> then(f)
        |> Map.values()
        |> Enum.sort(:desc),
        hand |> String.split("", trim: true) |> Enum.map(g)
        },
       String.to_integer(bid)}
      end)
  end

  def go_wild(freqs) do
      {wild, freqs} = Map.pop(freqs, "J")
     cond do
       is_nil(wild)  -> freqs
       Enum.count(freqs) == 0 -> %{"A" => 5}
       true ->
          best = freqs |> Map.values |> Enum.max
          {card, _} = freqs |> Enum.filter(fn {_, v} -> v == best end) |> Enum.sort() |> hd
          Map.update!(freqs, card, &(&1 + wild))
      end
  end
end

Where Next? Top

Trending in Challenges Top

Other Trending Topics Top

mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Dmk
Xamal is a deployment tool for Elixir apps that deploys native releases to bare metal servers over SSH. It’s a port of GitHub - basecamp/...
New
netoum
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
webofbits
With AI doing more of the implementation work, I’ve been wondering how much coding I should deliberately keep doing myself. My main conc...
#ai
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews