95 lines
2.6 KiB
D
95 lines
2.6 KiB
D
|
import std.stdio;
|
||
|
import std.algorithm;
|
||
|
import std.conv;
|
||
|
import std.array;
|
||
|
import std.string;
|
||
|
import std.ascii;
|
||
|
|
||
|
enum HandType : ubyte {
|
||
|
FiveOfAKind = 7,
|
||
|
FourOfAKind = 6,
|
||
|
FullHouse = 5,
|
||
|
ThreeOfAKind = 4,
|
||
|
TwoPair = 3,
|
||
|
OnePair = 2,
|
||
|
HighCard = 1
|
||
|
}
|
||
|
|
||
|
struct Hand {
|
||
|
ubyte[5] cards;
|
||
|
long bid;
|
||
|
HandType type;
|
||
|
}
|
||
|
|
||
|
HandType getType(ubyte[5] cards) {
|
||
|
ubyte[15] freq;
|
||
|
ubyte maxFreq = 0;
|
||
|
foreach (ubyte c; cards) {
|
||
|
freq[c]++;
|
||
|
if (freq[c] > maxFreq) maxFreq = freq[c];
|
||
|
}
|
||
|
ubyte jokerFreq = freq[1];
|
||
|
ubyte maxNonJokerFreq = freq[2..$].maxElement;
|
||
|
ubyte nonJokerCardTypes = cast(ubyte) freq[2..$].count!(n => n != 0);
|
||
|
if (maxNonJokerFreq + jokerFreq == 5) return HandType.FiveOfAKind;
|
||
|
if (maxNonJokerFreq + jokerFreq == 4) return HandType.FourOfAKind;
|
||
|
if (maxNonJokerFreq + jokerFreq == 3 && nonJokerCardTypes == 2) return HandType.FullHouse;
|
||
|
if (maxNonJokerFreq + jokerFreq == 3) return HandType.ThreeOfAKind;
|
||
|
if (maxNonJokerFreq + jokerFreq == 2 && nonJokerCardTypes == 3) return HandType.TwoPair;
|
||
|
if (maxNonJokerFreq + jokerFreq == 2) return HandType.OnePair;
|
||
|
return HandType.HighCard;
|
||
|
}
|
||
|
|
||
|
bool compareHands(Hand a, Hand b) {
|
||
|
if (a.type > b.type) return false;
|
||
|
if (b.type > a.type) return true;
|
||
|
for (size_t i = 0; i < 5; i++) {
|
||
|
if (a.cards[i] > b.cards[i]) return false;
|
||
|
if (b.cards[i] > a.cards[i]) return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
Hand[] parseHands(string filename, bool weakJoker) {
|
||
|
Hand[] hands;
|
||
|
foreach (string line; File(filename).byLineCopy()) {
|
||
|
string[] parts = line.split();
|
||
|
Hand h;
|
||
|
h.bid = parts[1].to!long;
|
||
|
foreach (size_t i, char c; parts[0]) {
|
||
|
if (isDigit(c)) h.cards[i] = cast(ubyte) (c - '0');
|
||
|
else if (c == 'T') h.cards[i] = 10;
|
||
|
else if (c == 'J') h.cards[i] = weakJoker ? 1 : 11;
|
||
|
else if (c == 'Q') h.cards[i] = 12;
|
||
|
else if (c == 'K') h.cards[i] = 13;
|
||
|
else if (c == 'A') h.cards[i] = 14;
|
||
|
}
|
||
|
h.type = getType(h.cards);
|
||
|
hands ~= h;
|
||
|
}
|
||
|
return hands;
|
||
|
}
|
||
|
|
||
|
void computeRankedBidSum(string filename, bool weakJoker) {
|
||
|
Hand[] hands = parseHands(filename, weakJoker);
|
||
|
long[] bidsRanked = hands.sort!compareHands.map!(h => h.bid).array;
|
||
|
long sum = 0;
|
||
|
for (long i = 0; i < bidsRanked.length; i++) {
|
||
|
sum += (i + 1) * bidsRanked[i];
|
||
|
}
|
||
|
writeln(sum);
|
||
|
}
|
||
|
|
||
|
void part1() {
|
||
|
computeRankedBidSum("input.txt", false);
|
||
|
}
|
||
|
|
||
|
void part2() {
|
||
|
computeRankedBidSum("input.txt", true);
|
||
|
}
|
||
|
|
||
|
void main() {
|
||
|
part1();
|
||
|
part2();
|
||
|
}
|