102 lines
3.0 KiB
Zig
102 lines
3.0 KiB
Zig
|
const std = @import("std");
|
||
|
|
||
|
pub const input = @embedFile("input/day02.txt");
|
||
|
const test_input = @embedFile("input/day02_test1.txt");
|
||
|
|
||
|
var gpa = std.heap.GeneralPurposeAllocator(.{ .safety = true }){};
|
||
|
const allocator = gpa.allocator();
|
||
|
|
||
|
const Choice = enum(usize) {
|
||
|
Rock = 1,
|
||
|
Paper = 2,
|
||
|
Scissors = 3,
|
||
|
fn from_opponent_char(char: u8) Choice {
|
||
|
return switch (char) {
|
||
|
'A' => Choice.Rock,
|
||
|
'B' => Choice.Paper,
|
||
|
'C' => Choice.Scissors,
|
||
|
else => @panic("invalid opponent char!"),
|
||
|
};
|
||
|
}
|
||
|
fn from_me_char(char: u8) Choice {
|
||
|
return switch (char) {
|
||
|
'X' => Choice.Rock,
|
||
|
'Y' => Choice.Paper,
|
||
|
'Z' => Choice.Scissors,
|
||
|
else => @panic("invalid me char!"),
|
||
|
};
|
||
|
}
|
||
|
fn from_outcome(self: Choice, outcome_char: u8) Choice {
|
||
|
return switch (outcome_char) {
|
||
|
'X' => self.lose_choice(),
|
||
|
'Y' => self,
|
||
|
'Z' => self.win_choice(),
|
||
|
else => @panic("invalid outcome char!"),
|
||
|
};
|
||
|
}
|
||
|
fn lose_choice(self: Choice) Choice {
|
||
|
return switch (self) {
|
||
|
Choice.Rock => Choice.Scissors,
|
||
|
Choice.Paper => Choice.Rock,
|
||
|
Choice.Scissors => Choice.Paper,
|
||
|
};
|
||
|
}
|
||
|
fn win_choice(self: Choice) Choice {
|
||
|
return switch (self) {
|
||
|
Choice.Rock => Choice.Paper,
|
||
|
Choice.Paper => Choice.Scissors,
|
||
|
Choice.Scissors => Choice.Rock,
|
||
|
};
|
||
|
}
|
||
|
fn beats(self: Choice, other: Choice) bool {
|
||
|
return if (other.win_choice() == self) true else false;
|
||
|
}
|
||
|
fn ties(self: Choice, other: Choice) bool {
|
||
|
return self == other;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
pub fn solve_part1(data: []const u8) usize {
|
||
|
var lines = std.mem.split(u8, data, "\n");
|
||
|
var score: usize = 0;
|
||
|
while (lines.next()) |line| {
|
||
|
if (std.mem.eql(u8, line, "")) break;
|
||
|
var player_choices = std.mem.split(u8, line, " ");
|
||
|
var opponent = Choice.from_opponent_char(player_choices.next().?[0]);
|
||
|
var me = Choice.from_me_char(player_choices.next().?[0]);
|
||
|
score += @enumToInt(me);
|
||
|
if (me.beats(opponent)) {
|
||
|
score += 6;
|
||
|
} else if (me.ties(opponent)) {
|
||
|
score += 3;
|
||
|
}
|
||
|
}
|
||
|
return score;
|
||
|
}
|
||
|
|
||
|
pub fn solve_part2(data: []const u8) usize {
|
||
|
var lines = std.mem.split(u8, data, "\n");
|
||
|
var score: usize = 0;
|
||
|
while (lines.next()) |line| {
|
||
|
if (std.mem.eql(u8, line, "")) break;
|
||
|
var player_choices = std.mem.split(u8, line, " ");
|
||
|
var opponent = Choice.from_opponent_char(player_choices.next().?[0]);
|
||
|
var me = opponent.from_outcome(player_choices.next().?[0]);
|
||
|
score += @enumToInt(me);
|
||
|
if (me.beats(opponent)) {
|
||
|
score += 6;
|
||
|
} else if (me.ties(opponent)) {
|
||
|
score += 3;
|
||
|
}
|
||
|
}
|
||
|
return score;
|
||
|
}
|
||
|
|
||
|
test "solves part1" {
|
||
|
try std.testing.expectEqual(solve_part1(test_input), 15);
|
||
|
}
|
||
|
|
||
|
test "solves part2" {
|
||
|
try std.testing.expectEqual(solve_part2(test_input), 12);
|
||
|
}
|