Day 7. Took a bit longer, but nothing too challenging. Running into some Zig stuff, like trying to figure out how to copy an array so I can mutate it..
parent
c40831a68b
commit
f6cb14a5cf
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,155 @@
|
||||
const std = @import("std");
|
||||
|
||||
const Score = enum { FiveOfAKind, FourOfAKind, FullHouse, ThreeOfAKind, TwoPair, OnePair, HighCard };
|
||||
const Hand = struct { cards: std.ArrayList(u8), score: Score, bid: u16 };
|
||||
|
||||
pub fn main() !void {
|
||||
const content = @embedFile("data.txt");
|
||||
var lines = std.mem.split(u8, content, "\n");
|
||||
|
||||
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||
const allocator = gpa.allocator();
|
||||
|
||||
var hands = std.ArrayList(Hand).init(allocator);
|
||||
defer hands.deinit();
|
||||
|
||||
while (lines.next()) |l| {
|
||||
if (l.len == 0) { // TODO: really gotta figure this out
|
||||
break;
|
||||
}
|
||||
|
||||
var cards = std.ArrayList(u8).init(allocator);
|
||||
for (0..5) |i| {
|
||||
try cards.append(cardValue(l[i]));
|
||||
}
|
||||
|
||||
const bid = try std.fmt.parseInt(u16, l[6..], 10);
|
||||
const hand = Hand{ .cards = cards, .score = try findScore(cards), .bid = bid };
|
||||
|
||||
try hands.append(hand);
|
||||
}
|
||||
|
||||
// sort hands by score
|
||||
var sortedHands = try hands.toOwnedSlice();
|
||||
std.sort.insertion(Hand, sortedHands, {}, compareHands);
|
||||
|
||||
// sum up winnings
|
||||
var winnings: u32 = 0;
|
||||
for (sortedHands, 1..) |hand, i| {
|
||||
winnings += hand.bid * @as(u32, @intCast(i));
|
||||
}
|
||||
|
||||
std.debug.print("Part 1 {?d}\n", .{winnings});
|
||||
|
||||
// Part 2
|
||||
var hands2 = std.ArrayList(Hand).init(allocator);
|
||||
defer hands2.deinit();
|
||||
|
||||
// Augment the scores
|
||||
for (sortedHands) |hand| {
|
||||
try hands2.append(try augmentHand(hand, allocator));
|
||||
}
|
||||
|
||||
// sort hands by score
|
||||
var sortedHands2 = try hands2.toOwnedSlice();
|
||||
std.sort.insertion(Hand, sortedHands2, {}, compareHands);
|
||||
|
||||
// sum up winnings
|
||||
var winnings2: u32 = 0;
|
||||
for (sortedHands2, 1..) |hand, i| {
|
||||
winnings2 += hand.bid * @as(u32, @intCast(i));
|
||||
}
|
||||
|
||||
std.debug.print("Part 2 {?d}\n", .{winnings2});
|
||||
}
|
||||
|
||||
// for part 2, update the score now that J is wild
|
||||
fn augmentHand(hand: Hand, allocator: std.mem.Allocator) !Hand {
|
||||
var numJokers: u8 = 0;
|
||||
for (hand.cards.items) |c| {
|
||||
if (c == 11) {
|
||||
numJokers += 1;
|
||||
}
|
||||
}
|
||||
|
||||
var cards = std.ArrayList(u8).init(allocator);
|
||||
for (hand.cards.items) |card| {
|
||||
const newCard = if (card == 11) 1 else card;
|
||||
try cards.append(newCard);
|
||||
}
|
||||
|
||||
if (numJokers == 0) {
|
||||
return Hand{ .cards = hand.cards, .score = hand.score, .bid = hand.bid };
|
||||
}
|
||||
|
||||
var score = switch (hand.score) {
|
||||
Score.FiveOfAKind => Score.FiveOfAKind,
|
||||
Score.FourOfAKind => Score.FiveOfAKind,
|
||||
Score.FullHouse => Score.FiveOfAKind,
|
||||
Score.ThreeOfAKind => Score.FourOfAKind,
|
||||
Score.TwoPair => switch (numJokers) {
|
||||
2 => Score.FourOfAKind,
|
||||
else => Score.FullHouse,
|
||||
},
|
||||
Score.OnePair => Score.ThreeOfAKind,
|
||||
Score.HighCard => Score.OnePair,
|
||||
};
|
||||
|
||||
return Hand{ .cards = cards, .score = score, .bid = hand.bid };
|
||||
}
|
||||
|
||||
fn compareHands(_: void, a: Hand, b: Hand) bool {
|
||||
const aScore = @intFromEnum(a.score);
|
||||
const bScore = @intFromEnum(b.score);
|
||||
if (aScore > bScore) {
|
||||
return true;
|
||||
} else if (aScore < bScore) {
|
||||
return false;
|
||||
} else {
|
||||
for (0..5) |i| {
|
||||
const aVal = a.cards.items[i];
|
||||
const bVal = b.cards.items[i];
|
||||
if (aVal == bVal) {
|
||||
continue;
|
||||
}
|
||||
return aVal < bVal;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Convert A, K, Q, etc. to 14, 13, 12, etc.
|
||||
fn cardValue(c: u8) u8 {
|
||||
return switch (c) {
|
||||
'A' => 14,
|
||||
'K' => 13,
|
||||
'Q' => 12,
|
||||
'J' => 11,
|
||||
'T' => 10,
|
||||
else => c - 48,
|
||||
};
|
||||
}
|
||||
|
||||
fn findScore(cards: std.ArrayList(u8)) !Score {
|
||||
// make a copy and sort it
|
||||
var copy = try cards.clone();
|
||||
std.sort.insertion(u8, copy.items, {}, comptime std.sort.asc(u8));
|
||||
var c = copy.items; // so much typing
|
||||
|
||||
// I thought about using a map of some kind to count pairs.. but this isn't too bad
|
||||
if (std.mem.eql(u8, c[0..4], c[1..5])) {
|
||||
return Score.FiveOfAKind;
|
||||
} else if ((c[0] == c[1] and c[1] == c[2] and c[2] == c[3]) or (c[1] == c[2] and c[2] == c[3] and c[3] == c[4])) {
|
||||
return Score.FourOfAKind;
|
||||
} else if ((c[0] == c[1] and c[1] == c[2] and c[3] == c[4]) or (c[2] == c[3] and c[3] == c[4] and c[0] == c[1])) {
|
||||
return Score.FullHouse;
|
||||
} else if ((c[0] == c[1] and c[1] == c[2]) or (c[1] == c[2] and c[2] == c[3]) or (c[2] == c[3] and c[3] == c[4])) {
|
||||
return Score.ThreeOfAKind;
|
||||
} else if ((c[0] == c[1] and c[2] == c[3]) or (c[0] == c[1] and c[3] == c[4]) or (c[1] == c[2] and c[3] == c[4])) {
|
||||
return Score.TwoPair;
|
||||
} else if (c[0] == c[1] or c[1] == c[2] or c[2] == c[3] or c[3] == c[4]) {
|
||||
return Score.OnePair;
|
||||
} else {
|
||||
return Score.HighCard;
|
||||
}
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
32T3K 765
|
||||
T55J5 684
|
||||
KK677 28
|
||||
KTJJT 220
|
||||
QQQJA 483
|
Loading…
Reference in New Issue