SO MANY ENUMS
1 Like
Here is a HAC solution…
My Solution for Day 2:
Day_02.ads
with Ada.Containers.Vectors;
-- Top Level package
package Day_02 is
-- Chosen hand shape
type Shape is (Rock, Paper, Scissors);
-- How the game concluded
type Outcome is (Loss, Draw, Win);
-- Overall score is any natural value
type Score is new Natural;
-- Determines the outcome of the round
function Round_Outcome(You, Opponent : Shape) return Outcome;
-- Scores a round based on the shapes you and your opponent chose
function Score_Round(You, Opponent : Shape) return Score;
-- Scores a round based on the shape you chose and the round outcome
function Score_Round
(Shape : Day_02.Shape;
Outcome : Day_02.Outcome)
return Score;
-- Holds information about each round
type Round is record
Your_Shape : Shape := Rock;
Opponents_Shape : Shape := Rock;
Total_Score : Score := 0;
end record;
-- Using vectors for simplicity
package Round_Vectors is new Ada.Containers.Vectors
(Index_Type => Positive,
Element_Type => Round);
-- List of rounds
subtype Rounds is Round_Vectors.Vector;
-- Parses the supplied file and returns a list of rounds
function Parse_File(Filename : String) return Rounds;
-- Takes in a rounds lists and adds them all together
function Score_All_Rounds(Rounds : Day_02.Rounds) return Score;
end Day_02;
Day_02.adb
with Ada.Text_IO;
with Ada.Strings.Fixed;
with Ada.Exceptions;
with Ada.Command_Line;
package body Day_02 is
-- Enables checking Static_Predicate, Pre, Post, etc.
pragma Assertion_Policy (Check);
-- Score Constants
Used_Rock : constant := 1;
Used_Paper : constant := 2;
Used_Scissors : constant := 3;
Game_Lost : constant := 0;
Game_Tied : constant := 3;
Game_Won : constant := 6;
-- Individual score for each shape used in the game
subtype Shape_Score is Score range Used_Rock..Used_Scissors;
-- Individual score for each game
subtype Outcome_Score is Score
with Static_Predicate => Outcome_Score in Game_Lost | Game_Tied | Game_Won;
-- Returns the assigned score based on the shape
function Get_Score(Shape : Day_02.Shape) return Shape_Score
with Inline;
-- Returns the assigned score based on how the game concluded
function Get_Score(Outcome : Day_02.Outcome) return Outcome_Score
with Inline;
-- Array used to convert a shape to its corresponding score
To_Shape_Score : constant array(Day_02.Shape) of Shape_Score :=
[Rock => Used_Rock,
Paper => Used_Paper,
Scissors => Used_Scissors];
-- Array used to convert an outcome to its corresponding score
To_Outcome_Score : constant array(Day_02.Outcome) of Outcome_Score :=
[Loss => Game_Lost,
Draw => Game_Tied,
Win => Game_Won];
function Get_Score(Shape : Day_02.Shape) return Shape_Score is
(To_Shape_Score(Shape));
function Get_Score(Outcome : Day_02.Outcome) return Outcome_Score is
(To_Outcome_Score(Outcome));
-- Maps <your_shape>,<opponents_shape> to an outcome
To_Outcome : constant array (Shape,Shape) of Outcome :=
[Rock =>
[Rock => Draw,
Paper => Loss,
Scissors => Win],
Paper =>
[Rock => Win,
Paper => Draw,
Scissors => Loss],
Scissors =>
[Rock => Loss,
Paper => Win,
Scissors => Draw]];
function Round_Outcome(You, Opponent : Shape) return Outcome is
(To_Outcome(You,Opponent));
function Score_Round(You, Opponent : Shape) return Score is
( Score_Round
(Shape => You,
Outcome => Round_Outcome
(You => You,
Opponent => Opponent)));
function Score_Round
(Shape : Day_02.Shape;
Outcome : Day_02.Outcome)
return Score
is (To_Shape_Score(Shape) + To_Outcome_Score(Outcome));
-- Encryption of round info
subtype Opponents_Character is Character range 'A'..'C';
subtype Delimiter_Character is Character range ' '..' ';
subtype Your_Character is Character range 'X'..'Z';
-- Decrypts opponent shape info
To_Opponents_Shape : constant array(Opponents_Character) of Shape :=
['A' => Rock,
'B' => Paper,
'C' => Scissors];
-- Decrypts your shape info
To_Your_Shape : constant array(Your_Character) of Shape :=
['X' => Rock,
'Y' => Paper,
'Z' => Scissors];
function Parse_File(Filename : String) return Rounds is
File : Ada.Text_IO.File_Type;
Round : Day_02.Round;
Result : Rounds;
Opponent : Opponents_Character;
Dummy_Delimiter : Delimiter_Character; -- Named dummy to avoid GNAT warning
You : Your_Character;
begin
Ada.Text_IO.Open
(File => File,
Name => Filename,
Mode => Ada.Text_IO.In_File);
while not Ada.Text_IO.End_Of_File(File) loop
declare
Line : constant String
:= Ada.Strings.Fixed.Trim
(Source => Ada.Text_IO.Get_Line(File),
Side => Ada.Strings.Both);
begin
-- Only look at lines that could have the correct format.
-- Ignore empty lines
if Line'Length = 3 then
Opponent := Line(Line'First + 0);
Dummy_Delimiter := Line(Line'First + 1);
You := Line(Line'First + 2);
Round.Your_Shape := To_Your_Shape(You);
Round.Opponents_Shape := To_Opponents_Shape(Opponent);
Round.Total_Score := Score_Round
(You => Round.Your_Shape,
Opponent => Round.Opponents_Shape);
Result.Append(Round);
-- Lines not exactly 3 characters or not empty are ill formatted
elsif Line'Length /= 0 then
raise Ada.Text_IO.Data_Error with "Line longer than expected: " & Line;
end if;
end;
end loop;
Ada.Text_IO.Close(File);
return Result;
exception
-- If an exception was raised, it means there is an
-- input file error. Print out some debug and return
-- an empty list
when e : others =>
Ada.Text_IO.Put_Line("Input File Error");
Ada.Text_IO.Put_Line(Ada.Exceptions.Exception_Information(e));
if Ada.Text_IO.Is_Open(File) then
Ada.Text_IO.Close(File);
end if;
return Round_Vectors.Empty_Vector;
end Parse_File;
function Score_All_Rounds(Rounds : Day_02.Rounds) return Score is
Result : Score := 0;
begin
for Round of Rounds loop
Result := @ + Round.Total_Score;
end loop;
return Result;
end Score_All_Rounds;
-- Program variables
Filename : constant String :=
(if Ada.Command_Line.Argument_Count = 0 then
"input.txt"
else
Ada.Command_Line.Argument(1));
Round_List : constant Rounds := Parse_File(Filename);
Total_Score : constant Score := Score_All_Rounds(Round_List);
Total_Rounds : constant Ada.Containers.Count_Type := Round_List.Length;
use type Ada.Containers.Count_Type;
begin
if Total_Rounds = 0 then
Ada.Text_IO.Put_Line("No rounds in file");
else
Ada.Text_IO.Put_Line("Total # of rounds:" & Total_Rounds'Image);
Ada.Text_IO.Put_Line("Total Score:" & Total_Score'Image);
end if;
end Day_02;
I just withed Day_02 in a blank main file.
Indeed enums were very helpful. They did all the work for me!
4 Likes
Yep! I like pairing enums with arrays indexed by those enums to make it do all the logic work too, which is nice.
Wow, that is nice! This is very short solution!
1 Like
I ended up using enums as well, with a multidimensional array as a lookup table (kind of). I love the solutions with 'Val, I keep forgetting that I can do that!
Here’s my solution: adventofcode/day2.adb at 9683a101a7532e2deaf632354091dae421287dce · AJ-Ianozi/adventofcode · GitHub
1 Like