Skip to content

Instantly share code, notes, and snippets.

@carlwiedemann
Created December 11, 2023 16:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save carlwiedemann/d94b667b15478e53cc29b8035dfdc2dd to your computer and use it in GitHub Desktop.
Save carlwiedemann/d94b667b15478e53cc29b8035dfdc2dd to your computer and use it in GitHub Desktop.
Advent of Code 2023 day007.rb
require_relative "main"
module Day007
INPUT = File.read('INPUT.txt')
DATA = INPUT.to_lines.map do |line|
cards, bid = line.split_strip(" ")
{
cards: cards,
bid: bid.to_i
}
end
HAND_ORDER = [
:fiveoak,
:fouroak,
:fullhouse,
:threeoak,
:twopair,
:pair,
:highcard
]
sorter = ->(cards_a, cards_b, card_rank, type_predicate) do
result_hand = HAND_ORDER.index(type_predicate.call(cards_a)) <=> HAND_ORDER.index(type_predicate.call(cards_b))
if result_hand == 0
i = 0
result_order = nil
while i < cards_a.length
result_order = card_rank.index(cards_a[i]) <=> card_rank.index(cards_b[i])
break if result_order != 0
i += 1
end
result_order
else
result_hand
end
end
##########
# Part 1 #
##########
get_type1 = memoize ->(cards) do
groups = cards.chars.group_by { _1 }
twos = groups.filter { |_k, v| v.count == 2 }
threes = groups.filter { |_k, v| v.count == 3 }
if groups.any? { |_k, v| v.count == 5 }
:fiveoak
elsif groups.any? { |_k, v| v.count == 4 }
:fouroak
elsif twos.count == 1 && threes.count == 1
:fullhouse
elsif threes.count == 1
:threeoak
elsif twos.count == 2
:twopair
elsif twos.count == 1
:pair
else
:highcard
end
end
checksum = ->(card_rank, type_predicate) do
sorted_hands = DATA.sort do |a, b|
sorter.call(a[:cards], b[:cards], card_rank, type_predicate)
end
sorted_hands.reverse.each_with_index.reduce(0) do |memo, (item, i)|
memo + item[:bid] * (i + 1)
end
end
answer1 = checksum.call(%w[A K Q J T 9 8 7 6 5 4 3 2], get_type1)
pp answer1
##########
# Part 2 #
##########
get_type2 = memoize ->(cards) do
groups = cards.chars.group_by { _1 }
j_count = groups["J"] ? groups["J"].count : 0
j1 = j_count == 1
j2 = j_count == 2
j3 = j_count == 3
j4 = j_count == 4
twos = groups.filter { |_k, v| v.count == 2 }
threes = groups.filter { |_k, v| v.count == 3 }
if groups.any? { |_k, v| v.count == 5 }
:fiveoak
elsif groups.any? { |_k, v| v.count == 4 }
if j4
:fiveoak
elsif j1
:fiveoak
else
:fouroak
end
elsif twos.count == 1 && threes.count == 1
if j2 || j3
:fiveoak
else
:fullhouse
end
elsif threes.count == 1
if j3
:fouroak
elsif j1
:fouroak
elsif j2
:fiveoak
else
:threeoak
end
elsif twos.count == 2
if j2
:fouroak
elsif j1
:fullhouse
else
:twopair
end
elsif twos.count == 1
if j2
:threeoak
elsif j1
:threeoak
else
:pair
end
elsif j1
:pair
else
:highcard
end
end
answer2 = checksum.call(%w[A K Q T 9 8 7 6 5 4 3 2 J], get_type2)
pp answer2
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment