-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathd7_part_two.rb
128 lines (108 loc) · 3.06 KB
/
d7_part_two.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# frozen_string_literal: true
def day7_part_one(input)
joker = "J"
# Map letters to its strength in number
strengths = {
"A" => 14,
"K" => 13,
"Q" => 12,
"T" => 11,
joker => 1 # weakest individually
}
# Parse the input
hands = input.map(&:split)
# Classify the hands in Five of a Kind, Four of a Kind, ...
hands.each do |hand|
# hand can include one or more jokers
cards =
if hand[0].include?(joker) && hand[0] != joker * 5
with_no_joker =
hand[0]
.chars
.tally
.except(joker)
ordered_by_repeats = with_no_joker.sort_by { |_, r| -r } # sort by repeats
max_number = with_no_joker.values.max # max number of cards that are no joker
subst_card =
case max_number
when 4, 3
ordered_by_repeats[0][0] # card that repeats 3 or 4 times
when 2
if ordered_by_repeats.map(&:last).uniq.size == 1
ordered_by_repeats
.map(&:first) # get the cards
.max_by { |c| strengths.fetch(c, c).to_i } # with more value
else
ordered_by_repeats[0][0] # the card with more incidences
end
else
with_no_joker
.map(&:first) # get the cards
.max_by { |c| strengths.fetch(c, c).to_i } # with more value
end
hand[0].gsub(joker, subst_card)
else
hand[0]
end
cards_tally = cards.chars.tally
# Change them for the strongest card in the hand
equal_cards, *rest = cards_tally.sort_by { |_, v| -v }.map(&:last)
hand_type =
case equal_cards
when 5
50 # Five of a Kind
when 4
40 # Four of a kind
when 3
rest.include?(2) ? 35 : 30 # "Full house" or "Three of a kind"
when 2
rest.include?(2) ? 25 : 20 # "Two pair" or "One pair"
else
10 # "High card"
end
hand << hand_type
hand << cards
end
# Let's play the cards
# First order by hand type desc and group them
hands_group =
hands
.sort_by! { |_, _, type| -type }
.group_by { |_, _, type| type }
# Second order, pick winner for each hand on each group
hands_group.each do |_, cards|
cards.sort! do |(ca, _, _), (cb, _, _)|
wins = 0
# Compare card by card until found a winner, tie otherwise (wins is zero)
5.times do |idx|
next if ca[idx] == cb[idx]
a = strengths.fetch(ca[idx], ca[idx]).to_i
b = strengths.fetch(cb[idx], cb[idx]).to_i
wins = a > b ? -1 : 1
break
end
wins
end
end
# Finally reverse the order (weakest to stronger) and return the sum of bid * rank
hands_group
.values
.flatten(1)
.reverse
.each_with_index
.map { |card, rank| card[1].to_i * (rank + 1) }
.sum
end
test = <<~INPUT
32T3K 765
T55J5 684
KK677 28
KTJJT 220
QQQJA 483
INPUT
.split(/\n/)
puts day7_part_one(test)
file = File.open("d7.txt")
file_data = file.readlines.map(&:chomp)
file.close
puts day7_part_one(file_data)