diff day7b.rb @ 9:9ec95ff0d33d

Add Day 7 solutions with string sorting Each hand gets a score based on the ranking, then concats the card values to get a sortable string for ranking
author IBBoard <dev@ibboard.co.uk>
date Thu, 07 Dec 2023 21:06:48 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/day7b.rb	Thu Dec 07 21:06:48 2023 +0000
@@ -0,0 +1,61 @@
+#! /usr/bin/env ruby
+
+require 'set'
+
+if ARGV.length != 1
+        abort("Incorrect arguments - needs input file")
+elsif not File.exist? (ARGV[0])
+	abort("File #{ARGV[0]} did not exist")
+end
+
+file = ARGV[0]
+
+Hand = Struct.new(:cards, :score, :bid)
+
+$card_scoring = ["J"].concat(("2".."9").to_a).concat(["T", "J", "Q", "K", "A"])
+
+JOKER_VALUE = $card_scoring.index("J")
+FULL_HOUSE = Set.new([2,3])
+TWO_PAIR = {2 => 2, 1 => 1}
+
+def score_hand(cards)
+	card_vals = cards.each_char.map {|c| $card_scoring.index(c)}
+	card_groups = card_vals.group_by{|v| v}.sort {|a,b|
+		# Push jokers to the start so that we can find the biggest group
+		# to add them to
+		if a[0] == JOKER_VALUE then -1
+		elsif b[0] == JOKER_VALUE then 1
+		# Then order by number of values
+		elsif a[1].length < b[1].length then -1
+		elsif a[1].length > b[1].length then 1
+		# Then order by card score
+		else a[0] <=> b[0]
+		end
+	}
+	jokers = card_vals.count(JOKER_VALUE)
+	joker_replacement = card_groups.last[0]
+	card_counts = card_groups.map {|v|
+		# If it's the joker replacement, add the number of jokers (which may be 0)
+		if v[0] == joker_replacement and v[0] != JOKER_VALUE then v[1].length + jokers
+		# If it's the jokers and we're not a hand of jokers then remove them - they're added elsewhere
+		elsif v[0] == JOKER_VALUE and joker_replacement != JOKER_VALUE then 0
+		# Else just take the count
+		else v[1].length
+		end
+	}.select {|num| num != 0}
+	card_count_counts = card_counts.group_by{|v| v}.map{|k,v| [k, v.length]}.to_h
+	dejokered_card_vals = card_vals.map {|v| v == 0 ? card_vals.max : v}
+	of_a_kind = card_counts.max
+	rank = of_a_kind * 10 # 5, 4 or 3 of a kind or a pair
+	if Set.new(card_counts) == FULL_HOUSE
+		rank = 35
+	elsif card_count_counts == TWO_PAIR
+		rank = 25
+	end
+	card_vals.reduce("#{rank}") {|str, v| "#{str}.#{(v+1).to_s.rjust(2, '0')}"}
+end
+
+hands = File.open(file, "r").each_line(chomp: true).map {|line| cards, bid = line.split(" "); Hand.new(cards, score_hand(cards), bid.to_i)}
+
+puts hands.sort {|a, b| a.score <=> b.score}.map.with_index(1) {|val, i| puts "#{val}"; i * val.bid}.sum
+# Rest of algorithm here
\ No newline at end of file