diff options
| author | Orfeas <38209077+0xfea5@users.noreply.github.com> | 2023-12-08 04:29:48 +0200 |
|---|---|---|
| committer | Orfeas <38209077+0xfea5@users.noreply.github.com> | 2025-10-28 23:20:45 +0200 |
| commit | 6afcea0fe495112cfbad92ff54833ba94ced23f9 (patch) | |
| tree | fed9a77402ae21afadf05a4d09fed62aa36d1133 | |
| parent | day7 (diff) | |
| download | aoc23-6afcea0fe495112cfbad92ff54833ba94ced23f9.tar.gz aoc23-6afcea0fe495112cfbad92ff54833ba94ced23f9.zip | |
improving day7 solution
| -rw-r--r-- | day07/solution.zig | 160 |
1 files changed, 55 insertions, 105 deletions
diff --git a/day07/solution.zig b/day07/solution.zig index b452dfb..05224bf 100644 --- a/day07/solution.zig +++ b/day07/solution.zig | |||
| @@ -24,144 +24,91 @@ const Player = struct { | |||
| 24 | hand: [5]u8, | 24 | hand: [5]u8, |
| 25 | combo: Combo, | 25 | combo: Combo, |
| 26 | 26 | ||
| 27 | fn evalHand(hand: []const u8) Combo { | 27 | fn evalHand(self: *@This(), withJoker: bool) void { |
| 28 | var cardF = [_]u32{0} ** 256; | ||
| 29 | |||
| 30 | for (hand) |c| { | ||
| 31 | cardF[c] += 1; | ||
| 32 | } | ||
| 33 | |||
| 34 | var combo = Combo.high; | ||
| 35 | for (cardF) |f| { | ||
| 36 | switch (f) { | ||
| 37 | 0, 1 => {}, | ||
| 38 | 2 => { | ||
| 39 | combo = switch (combo) { | ||
| 40 | .pair1 => .pair2, | ||
| 41 | .triple => .full, | ||
| 42 | else => .pair1, | ||
| 43 | }; | ||
| 44 | }, | ||
| 45 | 3 => combo = if (combo == Combo.pair1) .full else .triple, | ||
| 46 | 4 => combo = .quad, | ||
| 47 | 5 => combo = .quint, | ||
| 48 | else => unreachable, | ||
| 49 | } | ||
| 50 | } | ||
| 51 | |||
| 52 | return combo; | ||
| 53 | } | ||
| 54 | |||
| 55 | fn evalHandWithJoker(hand: []const u8) Combo { | ||
| 56 | var cardF = [_]u32{0} ** 256; | 28 | var cardF = [_]u32{0} ** 256; |
| 57 | var cmax: usize = 0; | 29 | var cmax: usize = 0; |
| 58 | 30 | ||
| 59 | for (hand) |c| { | 31 | for (self.hand) |c| { |
| 60 | cardF[c] += 1; | 32 | cardF[c] += 1; |
| 61 | if (c != 'J' and cardF[c] > cardF[cmax]) { | 33 | if (withJoker and c != 'J' and cardF[c] > cardF[cmax]) { |
| 62 | cmax = c; | 34 | cmax = c; |
| 63 | } | 35 | } |
| 64 | } | 36 | } |
| 65 | 37 | ||
| 66 | cardF[cmax] += cardF['J']; | 38 | if (withJoker) { |
| 39 | cardF[cmax] += cardF['J']; | ||
| 40 | cardF['J'] = 0; | ||
| 41 | } | ||
| 67 | 42 | ||
| 68 | var combo = Combo.high; | 43 | var combo = Combo.high; |
| 69 | for (cardF, 0..) |f, c| { | 44 | for (cardF) |f| { |
| 70 | if (c == 'J') { | 45 | combo = switch (f) { |
| 71 | continue; | 46 | 0, 1 => continue, |
| 72 | } | 47 | 2 => switch (combo) { |
| 73 | switch (f) { | 48 | .pair1 => .pair2, |
| 74 | 0, 1 => {}, | 49 | .triple => .full, |
| 75 | 2 => { | 50 | else => .pair1, |
| 76 | combo = switch (combo) { | ||
| 77 | .pair1 => .pair2, | ||
| 78 | .triple => .full, | ||
| 79 | else => .pair1, | ||
| 80 | }; | ||
| 81 | }, | 51 | }, |
| 82 | 3 => combo = if (combo == Combo.pair1) .full else .triple, | 52 | 3 => if (combo == Combo.pair1) .full else .triple, |
| 83 | 4 => combo = .quad, | 53 | 4 => .quad, |
| 84 | 5 => combo = .quint, | 54 | 5 => .quint, |
| 85 | else => unreachable, | 55 | else => unreachable, |
| 86 | } | 56 | }; |
| 87 | } | 57 | } |
| 88 | 58 | ||
| 89 | return combo; | 59 | self.combo = combo; |
| 90 | } | 60 | } |
| 91 | 61 | ||
| 92 | pub fn init(hand: []const u8, bid: u64) Player { | 62 | pub fn init(hand: []const u8, bid: u64) Player { |
| 93 | var res: Player = undefined; | 63 | var res: Player = undefined; |
| 64 | |||
| 94 | res.bid = bid; | 65 | res.bid = bid; |
| 95 | res.combo = Player.evalHand(hand); | ||
| 96 | mem.copy(u8, &res.hand, hand); | 66 | mem.copy(u8, &res.hand, hand); |
| 97 | 67 | ||
| 98 | return res; | 68 | return res; |
| 99 | } | 69 | } |
| 100 | 70 | ||
| 101 | pub fn initWithJoker(hand: []const u8, bid: u64) Player { | 71 | pub fn deinit(self: @This()) void { |
| 102 | var res: Player = undefined; | 72 | allocator.free(self.hand); |
| 103 | res.bid = bid; | ||
| 104 | res.combo = Player.evalHandWithJoker(hand); | ||
| 105 | mem.copy(u8, &res.hand, hand); | ||
| 106 | |||
| 107 | return res; | ||
| 108 | } | 73 | } |
| 109 | }; | 74 | }; |
| 110 | 75 | ||
| 111 | fn cardValue(c: u8) u64 { | 76 | fn cardValue(c: u8) u64 { |
| 112 | switch (c) { | 77 | return switch (c) { |
| 113 | '2'...'9' => return c - '0', | 78 | '2'...'9' => c - '0', |
| 114 | 'T' => return 10, | 79 | 'T' => 10, |
| 115 | 'J' => return 11, | 80 | 'J' => 11, |
| 116 | 'Q' => return 12, | 81 | 'Q' => 12, |
| 117 | 'K' => return 13, | 82 | 'K' => 13, |
| 118 | 'A' => return 14, | 83 | 'A' => 14, |
| 119 | else => unreachable, | 84 | else => unreachable, |
| 120 | } | 85 | }; |
| 121 | } | ||
| 122 | |||
| 123 | fn cmpCard(_: void, lhs: u8, rhs: u8) bool { | ||
| 124 | return cardValue(lhs) < cardValue(rhs); | ||
| 125 | } | ||
| 126 | |||
| 127 | fn playerCmp(_: void, lhs: Player, rhs: Player) bool { | ||
| 128 | if (lhs.combo != rhs.combo) { | ||
| 129 | return @intFromEnum(lhs.combo) < @intFromEnum(rhs.combo); | ||
| 130 | } | ||
| 131 | |||
| 132 | for (lhs.hand, rhs.hand) |l, r| { | ||
| 133 | if (l != r) { | ||
| 134 | return cmpCard(undefined, l, r); | ||
| 135 | } | ||
| 136 | } | ||
| 137 | |||
| 138 | return false; | ||
| 139 | } | 86 | } |
| 140 | 87 | ||
| 141 | fn cardValueWithJoker(c: u8) u64 { | 88 | fn cardValueWithJoker(c: u8) u64 { |
| 142 | switch (c) { | 89 | return switch (c) { |
| 143 | '2'...'9' => return c - '0', | 90 | '2'...'9' => c - '0', |
| 144 | 'T' => return 10, | 91 | 'T' => 10, |
| 145 | 'J' => return 0, | 92 | 'J' => 0, |
| 146 | 'Q' => return 12, | 93 | 'Q' => 12, |
| 147 | 'K' => return 13, | 94 | 'K' => 13, |
| 148 | 'A' => return 14, | 95 | 'A' => 14, |
| 149 | else => unreachable, | 96 | else => unreachable, |
| 150 | } | 97 | }; |
| 151 | } | 98 | } |
| 152 | 99 | ||
| 153 | fn cmpCardWithJoker(_: void, lhs: u8, rhs: u8) bool { | 100 | fn cmpCard(valueFunc: *const fn (u8) u64, lhs: u8, rhs: u8) bool { |
| 154 | return cardValueWithJoker(lhs) < cardValueWithJoker(rhs); | 101 | return valueFunc(lhs) < valueFunc(rhs); |
| 155 | } | 102 | } |
| 156 | 103 | ||
| 157 | fn playerCmpWithJoker(_: void, lhs: Player, rhs: Player) bool { | 104 | fn playerCmp(valueFunc: *const fn (u8) u64, lhs: Player, rhs: Player) bool { |
| 158 | if (lhs.combo != rhs.combo) { | 105 | if (lhs.combo != rhs.combo) { |
| 159 | return @intFromEnum(lhs.combo) < @intFromEnum(rhs.combo); | 106 | return @intFromEnum(lhs.combo) < @intFromEnum(rhs.combo); |
| 160 | } | 107 | } |
| 161 | 108 | ||
| 162 | for (lhs.hand, rhs.hand) |l, r| { | 109 | for (lhs.hand, rhs.hand) |l, r| { |
| 163 | if (l != r) { | 110 | if (l != r) { |
| 164 | return cmpCardWithJoker(undefined, l, r); | 111 | return cmpCard(valueFunc, l, r); |
| 165 | } | 112 | } |
| 166 | } | 113 | } |
| 167 | 114 | ||
| @@ -171,7 +118,10 @@ fn playerCmpWithJoker(_: void, lhs: Player, rhs: Player) bool { | |||
| 171 | pub fn part1(players: []Player) void { | 118 | pub fn part1(players: []Player) void { |
| 172 | var ans: u64 = 0; | 119 | var ans: u64 = 0; |
| 173 | 120 | ||
| 174 | mem.sort(Player, players, {}, playerCmp); | 121 | for (players) |*p| { |
| 122 | p.evalHand(false); | ||
| 123 | } | ||
| 124 | mem.sort(Player, players, &cardValue, playerCmp); | ||
| 175 | 125 | ||
| 176 | for (players, 1..) |p, rank| { | 126 | for (players, 1..) |p, rank| { |
| 177 | ans += p.bid * rank; | 127 | ans += p.bid * rank; |
| @@ -183,7 +133,10 @@ pub fn part1(players: []Player) void { | |||
| 183 | pub fn part2(players: []Player) void { | 133 | pub fn part2(players: []Player) void { |
| 184 | var ans: u64 = 0; | 134 | var ans: u64 = 0; |
| 185 | 135 | ||
| 186 | mem.sort(Player, players, {}, playerCmpWithJoker); | 136 | for (players) |*p| { |
| 137 | p.evalHand(true); | ||
| 138 | } | ||
| 139 | mem.sort(Player, players, &cardValueWithJoker, playerCmp); | ||
| 187 | 140 | ||
| 188 | for (players, 1..) |p, rank| { | 141 | for (players, 1..) |p, rank| { |
| 189 | ans += p.bid * rank; | 142 | ans += p.bid * rank; |
| @@ -194,11 +147,9 @@ pub fn part2(players: []Player) void { | |||
| 194 | 147 | ||
| 195 | pub fn main() !void { | 148 | pub fn main() !void { |
| 196 | var splitLines = mem.splitScalar(u8, fin, '\n'); | 149 | var splitLines = mem.splitScalar(u8, fin, '\n'); |
| 197 | var players_pt1 = ArrayList(Player).init(allocator); | 150 | var players = ArrayList(Player).init(allocator); |
| 198 | var players_pt2 = ArrayList(Player).init(allocator); | ||
| 199 | defer { | 151 | defer { |
| 200 | players_pt1.deinit(); | 152 | players.deinit(); |
| 201 | players_pt2.deinit(); | ||
| 202 | } | 153 | } |
| 203 | 154 | ||
| 204 | while (splitLines.next()) |line| { | 155 | while (splitLines.next()) |line| { |
| @@ -206,10 +157,9 @@ pub fn main() !void { | |||
| 206 | const hand = splitElem.next().?; | 157 | const hand = splitElem.next().?; |
| 207 | const bid = try std.fmt.parseInt(u64, splitElem.next().?, 10); | 158 | const bid = try std.fmt.parseInt(u64, splitElem.next().?, 10); |
| 208 | 159 | ||
| 209 | try players_pt1.append(Player.init(hand, bid)); | 160 | try players.append(Player.init(hand, bid)); |
| 210 | try players_pt2.append(Player.initWithJoker(hand, bid)); | ||
| 211 | } | 161 | } |
| 212 | 162 | ||
| 213 | part1(players_pt1.items); | 163 | part1(players.items); |
| 214 | part2(players_pt2.items); | 164 | part2(players.items); |
| 215 | } | 165 | } |
