[2023][ruby][7.x] refactoring
change xsttponvzqnsxuuqrllmxswylkpsyywu
commit fdaa8eb55737674557d635f54d326a9239b0af20
author Alpha Chen <alpha@kejadlen.dev>
date
parent xktuywmy
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