149 lines
4.9 KiB
Ada
149 lines
4.9 KiB
Ada
-- Hex Words: find words of 4 or more characters, all characters of which are hex digits
|
|
-- J. Carter 2024 May
|
|
|
|
with Ada.Characters.Handling;
|
|
with Ada.Containers.Vectors;
|
|
with Ada.Strings.Unbounded;
|
|
with Ada.Text_IO;
|
|
|
|
procedure Hex_Words is
|
|
use Ada.Strings.Unbounded;
|
|
|
|
subtype Hex_Digit is Character range 'a' .. 'f';
|
|
subtype Digit_Value is Integer range 0 .. 9;
|
|
|
|
function Hex_Word (Line : in String) return Boolean is
|
|
(Line'Length > 3 and (for all C of Line => C in Hex_Digit) );
|
|
|
|
function Digital_Root (Number : in Natural) return Digit_Value;
|
|
-- Returns the decimal digital root of Number
|
|
|
|
function Four_Distinct (Word : in String) return Boolean with
|
|
Pre => Hex_Word (Word);
|
|
-- Returns True if Word has at least 4 distinct letters; False otherwise
|
|
|
|
function Image (Number : in Natural) return String with
|
|
Post => Image'Result'Length = 9;
|
|
-- Returns the blank-filled decimal image of Number
|
|
|
|
type Word_Info is record
|
|
Word : Unbounded_String;
|
|
Value : Natural;
|
|
Root : Digit_Value;
|
|
end record;
|
|
|
|
function Root_Less (Left : in Word_Info; Right : in Word_Info) return Boolean is
|
|
(if Left.Root /= Right.Root then Left.Root < Right.Root else Left.Word < Right.Word);
|
|
|
|
function Value_Greater (Left : in Word_Info; Right : in Word_Info) return Boolean is
|
|
(if Left.Value /= Right.Value then Left.Value > Right.Value else Left.Word < Right.Word);
|
|
|
|
package Word_Lists is new Ada.Containers.Vectors (Index_Type => Positive, Element_Type => Word_Info);
|
|
|
|
package Root_Sorting is new Word_Lists.Generic_Sorting ("<" => Root_Less);
|
|
package Value_Sorting is new Word_Lists.Generic_Sorting ("<" => Value_Greater);
|
|
|
|
function Digital_Root (Number : in Natural) return Digit_Value is
|
|
function Digit_Sum return Natural;
|
|
-- Sums the digits of the decimal representation of Number
|
|
|
|
function Digit_Sum return Natural is
|
|
Image : constant String := Number'Image;
|
|
|
|
Sum : Natural := 0;
|
|
begin -- Digit_Sum
|
|
All_Digits : for I in 2 .. Image'Last loop
|
|
Sum := Sum + Character'Pos (Image (I) ) - Character'Pos ('0');
|
|
end loop All_Digits;
|
|
|
|
return Sum;
|
|
end Digit_Sum;
|
|
|
|
Sum : Natural := Digit_Sum;
|
|
begin -- Digital_Root
|
|
if Sum in Digit_Value then
|
|
return Sum;
|
|
end if;
|
|
|
|
return Digital_Root (Sum);
|
|
end Digital_Root;
|
|
|
|
function Four_Distinct (Word : in String) return Boolean is
|
|
type Hex_Set is array (Hex_Digit) of Boolean;
|
|
|
|
Set : Hex_Set := (others => False);
|
|
Count : Natural := 0;
|
|
begin -- Four_Distinct
|
|
Check_All : for C of Word loop
|
|
Set (C) := True;
|
|
end loop Check_All;
|
|
|
|
Count_Them : for B of Set loop
|
|
if B then
|
|
Count := Count + 1;
|
|
end if;
|
|
end loop Count_Them;
|
|
|
|
return Count > 3;
|
|
end Four_Distinct;
|
|
|
|
function Image (Number : in Natural) return String is
|
|
Result : constant String := Number'Image;
|
|
begin -- Image
|
|
return (1 .. 9 - Result'Length => ' ') & Result;
|
|
end Image;
|
|
|
|
Input : Ada.Text_IO.File_Type;
|
|
Info : Word_Info;
|
|
Word : Word_Lists.Vector;
|
|
Distinct : Word_Lists.Vector;
|
|
begin -- Hex_Words
|
|
Ada.Text_IO.Open (File => Input, Mode => Ada.Text_IO.In_File, Name => "unixdict.txt");
|
|
|
|
All_Words : loop
|
|
exit All_Words when Ada.Text_IO.End_Of_File (Input);
|
|
|
|
One_Word : declare
|
|
Line : constant String := Ada.Characters.Handling.To_Lower (Ada.Text_IO.Get_Line (Input) );
|
|
begin -- One_Word
|
|
if Hex_Word (Line) then
|
|
Info.Word := To_Unbounded_String (Line);
|
|
Info.Value := Integer'Value ("16#" & Line & '#');
|
|
Info.Root := Digital_Root (Info.Value);
|
|
Word.Append (New_Item => Info);
|
|
|
|
if Four_Distinct (Line) then
|
|
Distinct.Append (New_Item => Info);
|
|
end if;
|
|
end if;
|
|
end One_Word;
|
|
end loop All_Words;
|
|
|
|
Ada.Text_IO.Close (File => Input);
|
|
|
|
Root_Sorting.Sort (Container => Word);
|
|
Value_Sorting.Sort (Container => Distinct);
|
|
|
|
Print_All : for I in 1 .. Word.Last_Index loop
|
|
Print_One : declare
|
|
Info : Word_Info renames Word.Element (I);
|
|
begin -- Print_One
|
|
Ada.Text_IO.Put_Line
|
|
(Item => To_String (Info.Word) & (1 .. 6 - Length (Info.Word) => ' ') & Image (Info.Value) & Info.Root'Image);
|
|
end Print_One;
|
|
end loop Print_All;
|
|
|
|
Ada.Text_IO.Put_Line (Item => Word.Last_Index'Image & " total words");
|
|
Ada.Text_IO.New_Line;
|
|
|
|
Output_Distinct : for I in 1 ..Distinct.Last_Index loop
|
|
One_Distinct : declare
|
|
Info : Word_Info renames Distinct.Element (I);
|
|
begin -- One_Distinct
|
|
Ada.Text_IO.Put_Line
|
|
(Item => To_String (Info.Word) & (1 .. 6 - Length (Info.Word) => ' ') & Image (Info.Value) & Info.Root'Image);
|
|
end One_Distinct;
|
|
end loop Output_Distinct;
|
|
|
|
Ada.Text_IO.Put_Line (Item => Distinct.Last_Index'Image & " words with 4 or more distinct letters");
|
|
end Hex_Words;
|