RosettaCodeData/Task/Roman-numerals-Decode/Ada/roman-numerals-decode.ada

152 lines
4.2 KiB
Ada

Pragma Ada_2012;
Pragma Assertion_Policy( Check );
With
Unchecked_Conversion,
Ada.Text_IO;
Procedure Test_Roman_Numerals is
-- We create an enumeration of valid characters, note that they are
-- character-literals, this is so that we can use literal-strings,
-- and that their size is that of Integer.
Type Roman_Digits is ('I', 'V', 'X', 'L', 'C', 'D', 'M' )
with Size => Integer'Size;
-- We use a representation-clause ensure the proper integral-value
-- of each individual character.
For Roman_Digits use
(
'I' => 1,
'V' => 5,
'X' => 10,
'L' => 50,
'C' => 100,
'D' => 500,
'M' => 1000
);
-- To convert a Roman_Digit to an integer, we now only need to
-- read its value as an integer.
Function Convert is new Unchecked_Conversion
( Source => Roman_Digits, Target => Integer );
-- Romena_Numeral is a string of Roman_Digit.
Type Roman_Numeral is array (Positive range <>) of Roman_Digits;
-- The Numeral_List type is used herein only for testing
-- and verification-data.
Type Numeral_List is array (Positive range <>) of
not null access Roman_Numeral;
-- The Test_Cases subtype ensures that Test_Data and Validation_Data
-- both contain the same number of elements, and that the indecies
-- are the same; essentially the same as:
--
-- pragma Assert( Test_Data'Length = Validation_Data'Length
-- AND Test_Data'First = Validation_Data'First);
subtype Test_Cases is Positive range 1..14;
Test_Data : constant Numeral_List(Test_Cases):=
(
New Roman_Numeral'("III"), -- 3
New Roman_Numeral'("XXX"), -- 30
New Roman_Numeral'("CCC"), -- 300
New Roman_Numeral'("MMM"), -- 3000
New Roman_Numeral'("VII"), -- 7
New Roman_Numeral'("LXVI"), -- 66
New Roman_Numeral'("CL"), -- 150
New Roman_Numeral'("MCC"), -- 1200
New Roman_Numeral'("IV"), -- 4
New Roman_Numeral'("IX"), -- 9
New Roman_Numeral'("XC"), -- 90
New Roman_Numeral'("ICM"), -- 901
New Roman_Numeral'("CIM"), -- 899
New Roman_Numeral'("MDCLXVI") -- 1666
);
Validation_Data : constant array(Test_Cases) of Natural:=
( 3, 30, 300, 3000,
7, 66, 150, 1200,
4, 9, 90,
901, 899,
1666
);
-- In Roman numerals, the subtractive form [IV = 4] was used
-- very infrequently, the most common form was the addidive
-- form [IV = 6]. (Consider military logistics and squads.)
-- SUM returns the Number, read in the additive form.
Function Sum( Number : Roman_Numeral ) return Natural is
begin
Return Result : Natural:= 0 do
For Item of Number loop
Result:= Result + Convert( Item );
end loop;
End Return;
end Sum;
-- EVAL returns Number read in the subtractive form.
Function Eval( Number : Roman_Numeral ) return Natural is
Current : Roman_Digits:= 'I';
begin
Return Result : Natural:= 0 do
For Item of Number loop
if Current < Item then
Result:= Convert(Item) - Result;
Current:= Item;
else
Result:= Result + Convert(Item);
end if;
end loop;
End Return;
end Eval;
-- Display the given Roman_Numeral via Text_IO.
Procedure Put( S: Roman_Numeral ) is
begin
For Ch of S loop
declare
-- The 'Image attribute returns the character inside
-- single-quotes; so we select the character itself.
C : Character renames Roman_Digits'Image(Ch)(2);
begin
Ada.Text_IO.Put( C );
end;
end loop;
end;
-- This displays pass/fail dependant on the parameter.
Function PF ( Value : Boolean ) Return String is
begin
Return Result : String(1..4):= ( if Value then"pass"else"fail" );
End PF;
Begin
Ada.Text_IO.Put_Line("Starting Test:");
for Index in Test_Data'Range loop
declare
Item : Roman_Numeral renames Test_Data(Index).all;
Value : constant Natural := Eval(Item);
begin
Put( Item );
Ada.Text_IO.Put( ASCII.HT & "= ");
Ada.Text_IO.Put( Value'Img );
Ada.Text_IO.Put_Line( ASCII.HT & '[' &
PF( Value = Validation_Data(Index) )& ']');
end;
end loop;
Ada.Text_IO.Put_Line("Testing complete.");
End Test_Roman_Numerals;