Rosetta Code task/Find unimplemented tasks

For Is_Power, it would suggest to compute the GCD of the powers of the prime decomposition and return False If GCD = 1.

Since we started this thread its changed to:

Numbers of tasks not implemented := 403

Good job there!

Ok, I’ll give that a try. Thanks.

I just added Abelian Sandpile Model - pretty things!
Surprisingly easy to produce a graphics file without resorting to external packages.

2 Likes

I just added the Visitor Pattern. That was… painful, and my implementation may be highly suboptimal, so suggestions are welcome.

Thanks to @jere for the help with tagged types. No defects to that implementation should be blamed on him.

1 Like

I’ve been having more fun with library-less graphics: added Color Wheel and Sierpinski Square Curve examples.

Glad to help out.

If you are interested in alternate implementations, here is another way to go about it. I would package the general visitor and car part together:

private with Ada.Strings.Unbounded; 

package Car_Elements is

   -- Forward declaration for visitor operation parameter
   type Element is tagged;

   -- Generic visitor interface
   type Element_Visitor is interface;

   -- Interface visiting procedure
   procedure Visit(Self : Element_Visitor; Part : in out Car_Elements.Element'Class) is abstract;

   -- Base class type for all car things
   type Element is abstract tagged private;

   -- Using 'Class here so I can provide a generic base class constructor
   --    Name - Name of the part: "Body", "Engine", "Wheel"
   -- NOTE:  When using to make an aggregate, type convert the result of this
   --    operation to the Element type
   function Make(Name : String) return Element'Class;
   
   -- To get the supplied name
   function Name(Self : Element'Class) return String;

   -- This procedure calls Visitor.Visit(Self) by default
   procedure Accept_Visitor(Self : in out Element; Visitor : Element_Visitor'Class);

private

   use Ada.Strings.Unbounded;

   type Element is abstract tagged record
      Name : Unbounded_String;
   end record;

end Car_Elements;
package body Car_Elements is

   -- Need a non abstract type to actually work in the Make function
   type Factory is new Element with null record;

   function Make(Name : String) return Element'Class is
      (Factory'(Name => To_Unbounded_String(Name)));

   function Name(Self : Element'Class) return String is
      (To_String(Self.Name));

   procedure Accept_Visitor(Self : in out Element; Visitor : Element_Visitor'Class) is
   begin
      Visitor.Visit(Self);
   end Accept_Visitor;

end Car_Elements;

Then make the parts this way:

with Car_Elements;

package Engines is 

   type Engine is new Car_Elements.Element with null record;
   function Make return Engine is
      (Car_Elements.Element(Car_Elements.Make("Engine")) with null record);

end Engines;
with Car_Elements;

package Bodies is 

   type Car_Body is new Car_Elements.Element with null record;
   function Make return Car_Body is 
      (Car_Elements.Element(Car_Elements.Make("Body")) with null record);

end Bodies;
with Car_Elements;

package Wheels is

   type Wheel is new Car_Elements.Element with null record;
   function Make(Name : String) return Wheel is
      (Car_Elements.Element(Car_Elements.Make(Name & " Wheel")) with null record);

end Wheels;

After that you can combine them into the car like this:

private with Bodies;
private with Engines;
private with Wheels;

with Car_Elements;

package Cars is

   type Car is new Car_Elements.Element with private;

   overriding 
   procedure Accept_Visitor(Self : in out Car; Visitor : Car_Elements.Element_Visitor'Class);

   function Make return Car;

private

   type Wheel_Array is array(1..4) of Wheels.Wheel;

   type Car is new Car_Elements.Element with record
      Car_Body   : Bodies.Car_Body;
      Engine     : Engines.Engine;
      All_Wheels : Wheel_Array;
   end record;

end Cars;
package body Cars is

   function Make return Car is 
      (Car_Elements.Element(Car_Elements.Make("Car")) with
         Car_Body   => Bodies.Make,
         Engine     => Engines.Make,
         All_Wheels =>
            (1 => Wheels.Make("Front Left"),
             2 => Wheels.Make("Front Right"),
             3 => Wheels.Make("Back Left"),
             4 => Wheels.Make("Back Right")));

   procedure Accept_Visitor(Self : in out Car; Visitor : Car_Elements.Element_Visitor'Class) is 
   begin
      Car_Elements.Element(Self).Accept_Visitor(Visitor);
      Self.Car_Body.Accept_Visitor(Visitor);
      Self.Engine.Accept_Visitor(Visitor);
      For Wheel of Self.All_Wheels loop
         Wheel.Accept_Visitor(Visitor);
      end Loop;
   end Accept_Visitor;

end Cars;

Then making the visitors can be more generic:

with Car_Elements;

package Visitors is

   type Print_Visitor is new Car_Elements.Element_Visitor with null record;
   overriding
   procedure Visit(Self : Print_Visitor; Part : in out Car_Elements.Element'Class);

   type Perform_Visitor is new Car_Elements.Element_Visitor with null record;
   overriding
   procedure Visit(Self : Perform_Visitor; Part : in out Car_Elements.Element'Class);

end Visitors;
with Ada.Text_IO; use Ada.Text_IO;
with Bodies;
with Engines;
with Wheels;
with Cars;

package body Visitors is

   procedure Visit(Self : Print_Visitor; Part : in out Car_Elements.Element'Class) is
   begin
      Put_Line("Visiting " & Part.Name);
   end Visit;

   procedure Visit(Self : Perform_Visitor; Part : in out Car_Elements.Element'Class) is
   begin
      if Part in Cars.Car then
         Put_Line("Starting the " & Part.Name);
      elsif Part in Bodies.Car_Body then
         Put_Line("Moving the " & Part.Name);
      elsif Part in Engines.Engine then
         Put_Line("Revving the "& Part.Name);
      elsif Part in Wheels.Wheel then
         Put_Line("Rolling the " & Part.Name);
      else 
         raise Constraint_Error with "Peform_Visitor does not support part type";
      end if;
   end Visit;
   
end Visitors;

Finally you can wrap it all up in the following main:

with Cars;
with Visitors;

procedure Main is
   Car       : Cars.Car := Cars.Make;
   Printer   : Visitors.Print_Visitor;
   Performer : Visitors.Perform_Visitor;
begin
   Car.Accept_Visitor(Printer);
   Car.Accept_Visitor(Performer);
end Main;
Visiting Car
Visiting Body
Visiting Engine
Visiting Front Left Wheel
Visiting Front Right Wheel
Visiting Back Left Wheel
Visiting Back Right Wheel
Starting the Car
Moving the Body
Revving the Engine
Rolling the Front Left Wheel
Rolling the Front Right Wheel
Rolling the Back Left Wheel
Rolling the Back Right Wheel

Also for the Car type, you can use an Indefinite_Vector to keep all the internal car parts:

   use type Car_Elements.Element;
   package Part_Vectors is new Ada.Containers.Indefinite_Vectors
      (Index_Type   => Positive,
       Element_Type => Car_Elements.Element'Class);

   type Car is new Car_Elements.Element with record
      Parts : Part_Vectors.Vector;
   end record;

   use type Part_Vectors.Vector;
   function Make return Car is
      (Car_Elements.Element(Car_Elements.Make("Car")) with 
         Part_Vectors.Empty_Vector 
         & Bodies.Make
         & Engines.Make
         & Wheels.Make("Front Left")
         & Wheels.Make("Front Right")
         & Wheels.Make("Back Left")
         & Wheels.Make("Back Right"));

Though you would to modify Accept_Visitor to loop through the vector of course.

Vibrating rectangles is done.

1 Like