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.
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.
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.