const std = @import("std"); const Outcomes = enum(u16) { Lost = 0, Draw = 3, Win = 6, INVALID = 99, pub fn from_guide(value: u8) Outcomes{ return switch(value) { 'X' => Outcomes.Lost, 'Y' => Outcomes.Draw, 'Z' => Outcomes.Win, else => Outcomes.INVALID, }; } }; const RPSStates = enum(i8) { Rock = 0, Paper =1, Scissors = 2, INVALID = 99, _, pub fn from_opponent(value: u8) RPSStates { return switch(value) { 'A' => RPSStates.Rock, 'B' => RPSStates.Paper, 'C' => RPSStates.Scissors, else => RPSStates.INVALID }; } pub fn from_me(value: u8) RPSStates { return switch(value) { 'X' => RPSStates.Rock, 'Y' => RPSStates.Paper, 'Z' => RPSStates.Scissors, else => RPSStates.INVALID }; } pub fn get_move_needed(outcome_needed: Outcomes, opp_choice: RPSStates) RPSStates { return switch(outcome_needed) { .Lost => opp_choice.get_strong_to_move(), .Draw => opp_choice, .Win => opp_choice.get_weak_to_move(), else => unreachable }; } pub fn outcome(self: RPSStates, opp_choice: RPSStates) Outcomes { if (self == opp_choice) { return Outcomes.Draw; } else { if (self.get_strong_to_move() == opp_choice) { return Outcomes.Win; } else { return Outcomes.Lost; } } } pub fn score_round(self: RPSStates, opp_choice: RPSStates) u16 { var score: u16 = switch(self) { .Rock => 1, .Paper => 2, .Scissors => 3, else => unreachable }; score += @enumToInt(self.outcome(opp_choice)); return score; } pub fn get_weak_to_move(self: RPSStates) RPSStates { return @intToEnum(RPSStates, @mod((@enumToInt(self) + 1), 3)); } pub fn get_strong_to_move(self: RPSStates) RPSStates { return @intToEnum(RPSStates, @mod((@enumToInt(self) - 1), 3)); } }; pub fn part1(opp_letter: u8, my_letter: u8) u16 { const opp_choice = RPSStates.from_opponent(opp_letter); const my_choice = RPSStates.from_me(my_letter); return my_choice.score_round(opp_choice); } pub fn part2(opp_letter: u8, my_letter: u8) u16 { const opp_choice = RPSStates.from_opponent(opp_letter); const win_cond = Outcomes.from_guide(my_letter); const my_choice = RPSStates.get_move_needed(win_cond, opp_choice); return my_choice.score_round(opp_choice); } pub fn main() !void { var file = try std.fs.cwd().openFile("inputs/day2.txt", .{}); defer file.close(); var buf_reader = std.io.bufferedReader(file.reader()); var in_stream = buf_reader.reader(); var buf: [1024]u8 = undefined; var score_part1: u16 = 0; var score_part2: u16 = 0; while (try in_stream.readUntilDelimiterOrEof(&buf, '\n')) |line| { const opp_letter: u8 = line[0]; const my_letter: u8 = line[2]; score_part1 += part1(opp_letter, my_letter); score_part2 += part2(opp_letter, my_letter); } std.debug.print("PART1: My total score: {}\n", .{score_part1}); std.debug.print("PART2: My total score: {}\n", .{score_part2}); } test "Win Conditions" { var opp = RPSStates.Paper; var me = RPSStates.Rock; var score = me.score_round(opp); try std.testing.expect(score == 1); opp = RPSStates.Scissors; me = RPSStates.Paper; score = me.score_round(opp); try std.testing.expect(score == 2); opp = RPSStates.Rock; me = RPSStates.Scissors; score = me.score_round(opp); try std.testing.expect(score == 3); opp = RPSStates.Rock; me = RPSStates.Paper; score = me.score_round(opp); try std.testing.expect(me.outcome(opp) == Outcomes.Win); try std.testing.expect(score == 8); opp = RPSStates.Paper; me = RPSStates.Scissors; score = me.score_round(opp); try std.testing.expect(score == 9); opp = RPSStates.Scissors; me = RPSStates.Rock; score = me.score_round(opp); try std.testing.expect(score == 7); }