[2023][ruby][7.x] refactoring
diff --git a/2023/ruby/day_07.rb b/2023/ruby/day_07.rb
index 5894498..ce8eff7 100644
--- a/2023/ruby/day_07.rb
+++ b/2023/ruby/day_07.rb
@@ -1,77 +1,50 @@
-module PartOne
- CARD_ORDER = ((?2..?9).to_a + %w[ T J Q K A ]).each.with_index.to_h
-
- Card = Data.define(:rank) do
- def <=>(other)
- CARD_ORDER.fetch(self.rank) <=> CARD_ORDER.fetch(other.rank)
- end
- end
+HAND_STRENGTH = [
+ [5], # five of a kind
+ [1, 4], # four of a kind
+ [2, 3], # full house
+ [1, 1, 3], # three of a kind
+ [1, 2, 2], # two pair
+ [1, 1, 1, 2], # one pair
+ [1, 1, 1, 1, 1], # high card
+].reverse.each.with_index.to_h { [_1, _2] }
- Hand = Data.define(:cards) do
- def type
- tally = self.cards.tally
- case tally.values.sort
- when [5] then 5 # five of a kind
- when [1, 4] then 4 # four of a kind
- when [2, 3] then 3.5 # full house
- when [1, 1, 3] then 3 # three of a kind
- when [1, 2, 2] then 2.5 # two pair
- when [1, 1, 1, 2] then 2 # one pair
- when [1, 1, 1, 1, 1] then 1 # high card
- else fail "couldn't calculate type: #{self.inspect}"
- end
- end
-
- def <=>(other)
- v = self.type <=> other.type
- v.zero? ? self.cards <=> other.cards : v
- end
+module PartOne
+ CARD_STRENGTH = ((?2..?9).to_a + %w[ T J Q K A ]).each.with_index.to_h
+
+ def self.strength(cards)
+ tally = cards.tally
+ strengths = [
+ HAND_STRENGTH.fetch(tally.values.sort),
+ *cards.map { CARD_STRENGTH.fetch(_1) },
+ ]
+ strengths.map { (?a.ord + _1).chr }.join
end
end
module PartTwo
- CARD_ORDER = ([?J] + (?2..?9).to_a + %w[ T Q K A ]).each.with_index.to_h
-
- Card = Data.define(:rank) do
- def <=>(other)
- CARD_ORDER.fetch(self.rank) <=> CARD_ORDER.fetch(other.rank)
- end
- end
-
- Hand = Data.define(:cards) do
- def type
- tally = self.cards.map(&:rank).tally
- jokers = tally.delete(?J) || 0
- counts = tally.values.sort
- if counts.empty?
- counts = [5]
- else
- counts[-1] += jokers
- end
- case counts
- when [5] then 5 # five of a kind
- when [1, 4] then 4 # four of a kind
- when [2, 3] then 3.5 # full house
- when [1, 1, 3] then 3 # three of a kind
- when [1, 2, 2] then 2.5 # two pair
- when [1, 1, 1, 2] then 2 # one pair
- when [1, 1, 1, 1, 1] then 1 # high card
- else fail "couldn't calculate type: #{self.inspect}"
- end
- end
-
- def <=>(other)
- v = self.type <=> other.type
- v.zero? ? self.cards <=> other.cards : v
+ CARD_STRENGTH = ([?J] + (?2..?9).to_a + %w[ T Q K A ]).each.with_index.to_h
+
+ def self.strength(cards)
+ tally = cards.tally
+ jokers = tally.delete(?J) || 0
+ counts = tally.values.sort
+ if counts.empty?
+ counts = [5]
+ else
+ counts[-1] += jokers
end
+ strengths = [
+ HAND_STRENGTH.fetch(counts),
+ *cards.map { CARD_STRENGTH.fetch(_1) },
+ ]
+ strengths.map { (?a.ord + _1).chr }.join
end
end
-hands = ARGF.read.scan(/(\w+)\s+(\d+)/).to_h {|hand, bid|
- [PartTwo::Hand.new(hand.chars.map { PartTwo::Card.new(_1) }), bid.to_i]
-}
+hands = ARGF.read.scan(/(\w+)\s+(\d+)/).to_h { [_1.chars, _2.to_i ] }
p hands
- .sort_by(&:first)
+ # .sort_by {|(hand,_)| PartOne::strength(hand) }
+ .sort_by {|(hand,_)| PartTwo::strength(hand) }
.map.with_index {|(_,bid),i| bid * (i+1) }
.sum