Day 18 – Santa and the Magic Tree (M-Tree)

It was Christmas Eve in the Workhouse and Santa was getting worried about how the weight of all those presents would reduce the height of his sled’s flighpath. Would he be able to clear the height of the tallest Christmas trees on his worldwide journey?

He asked one of his helpers to whip up a quick script to see how much danger he would be in and in stepped p6elf to do the job.

Naturally p6elf (pronounced “Physics Elf”) wanted to show off his raku skills to grow his reputation with Santa, the reindeer and all the other elves (knowing how much Santa is into the whole raku thing). So he started by picking up two modules and mixing them together. To share with the others so that they could see how they could easily make their own models so he used Brian Duggan’s cool Jupyter notebook module.

#This setup cell inherits from the Math::Polygons classes such as Point and Triangle provided by Math::Polygons and overrides their plain Numeric variables with Physics::Measure classes of Length and Area.
use Math::Polygons;
use Physics::Measure :ALL;
$Physics::Measure::round-val = 1;
class M-Point is Point {
has Length $.x;
has Length $.y;
}
class M-Polygon is Polygon {
has M-Point @.points;
}
class M-Rectangle is Rectangle {
has M-Point $.origin;
has Length $.width;
has Length $.height;
method area( --> Area ) {
$!height * $!width
}
}
class M-Triangle is Triangle {
has M-Point $.apex is required;
has Length $.side is required;
method height( --> Length ) {
sqrt($!side**2 - ($!side/2)**2)
}
method area( --> Area ) {
( $.height * $!side ) / 2
}
}

That was quick, he thought, the raku OO approach really is cool and concise and just seamlessly applies my classes as types to check the correctness of my work.

p6elf then went back on the keys to use his new classes and get to a model tree…

my $tri1 = M-Triangle.new(stroke => "green", fill => "green",
apex => M-Point.new(100m, 50m),
side => 50m,
);
my $tri2 = M-Triangle.new(stroke => "green", fill => "green",
apex => M-Point.new(100m, 75m),
side => 75m,
);
my $tri3 = M-Triangle.new(stroke => "green", fill => "green",
apex => M-Point.new(100m, 100m),
side => 100m,
);
my $rect = M-Rectangle.new(stroke => "brown", fill => "brown",
origin => M-Point.new(90m, 185m),
width => 20m,
height => 40m,
);
my @elements = [ $tri1, $tri2, $tri3, $rect ];
say "Tree Height is ", [+] @elements.map(*.height);
say "Tree Area is ", [+] @elements.map(*.area);
my $tree = Group.new( :@elements );
my $drawing = Drawing.new( elements => $tree );
$drawing.serialize.say;

Wowee, look how I can just type in 100m and the Physics::Measure postfix<m> operator magically makes a Length object … no need to repetitively type in my Length $d = Length.new(value => 100, units => ‘m’); every time (provided I have an SI unit / SI prefix such as cm, kg, ml and so on). And, like magic, a beautiful Xmas tree appeared on the screen.

Then p6elf realised his mistake. While Santa would need to fly over the towering trees that surround the North Pole – where sizes are measured in metric units, he would also need to deliver many, many presents to the kids in America – and their tree are purchased by the foot. Of course, raku to the rescue – since p6elf was too lazy to retype all the embedded unit values in his first model, he created a Magic Tree (M-Tree) class and parameterized the dimensions of the elements like this:

class M-Tree {
has M-Point $.apex;
has Length $.size;
has M-Triangle $!top;
has M-Triangle $!middle;
has M-Triangle $!bottom;
has M-Rectangle $!base;
method elements {
[ $!top, $!middle, $!bottom, $!base ]
}
method height( --> Length ) {
[+] $.elements.map(*.height)
}
method area( --> Area ) {
[+] $.elements.map(*.area)
}
method TWEAK {
my $stroke := my $fill;
$fill = "green";
#calculate x co-ords relative to top of drawing, according to height
my \x := $!apex.x;
my \s := $!size;
my \p = [ (s / 4) , ( s * 3/8), (s / 2) ];
$!top = M-Triangle.new( :$stroke, :$fill,
apex => M-Point.new(x, p[0]),
side => p[0] );
$!middle = M-Triangle.new( :$stroke, :$fill,
apex => M-Point.new(x, p[1]),
side => p[1] );
$!bottom = M-Triangle.new( :$stroke, :$fill,
apex => M-Point.new(x, p[2]),
side => p[2] );
$fill = "brown";
$!base = M-Rectangle.new( :$stroke, :$fill,
origin => M-Point.new(( 0.9 * x ), (([+] p) - (0.2 * s))),
width => 0.1 * s,
height => 0.2 * s );
}
}
#my $size = 200m;
my $size = ♎️'50 ft';
my M-Point $apex .= new(($size / 2), ($size / 4));
my M-Tree $us-tree .= new(:$apex, :$size);
say "Tree Height is {$us-tree.height} (including the base)";
say "Tree Area is {$us-tree.area}";
my $drawing = Drawing.new( elements => $us-tree.elements );
$drawing.serialize.say;

Look how cool programming is, I can capture the shape of my object and just need to set the control dimension $size in one place. Instead of 200m via the postfix syntax,I can use the libra emoji prefix<♎️> that uses powerful raku Grammars to read the units and automatically convert. Let’s take a look at the result:

Phew, no need to worry, Santa can easily get over these smaller forests even when the reindeer are tired and low on energy…

… energy – hmmm maybe I can use raku Physics::Measure to work out how much energy we need to load up in terajoules(TJ) and then convert that to calories to work out how much feed Rudy and the team will need … mused p6elf in a minced pie induced dream.

~p6steve.com

With inspiration from: Jonathan Stowe’s perl6 advent calendar Christmas Tree and Codesections’ Learn Raku With: HTML Balls

4 thoughts on “Day 18 – Santa and the Magic Tree (M-Tree)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: