Mercurial > repos > other > adventofcode2023
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