Download the raw code.
# -*- mode: cperl6; -*-
# 2011 Perl 6 Coding Contest
# Edgar Gonzàlez i Pellicer
use v6;
# A term
class Term {
has $.value;
has $.expression;
}
# Sum two terms
sub sum-terms(Term $t1, Term $t2) {
# Include lowest term first in the expression
my $expr = $t1.value < $t2.value ??
sprintf('%s + %s', $t1.expression, $t2.expression) !!
sprintf('%s + %s', $t2.expression, $t1.expression);
# Return the sum
return Term.new(value => $t1.value + $t2.value,
expression => $expr);
}
# Merge two streams
sub merge($s1, $s2) {
return gather {
# Clone the streams
my $ws1 = $s1.clone;
my $ws2 = $s2.clone;
# While both remain
while $ws1 && $ws2 {
# Compare heads, and advance the lowest
if $ws1[0].value < $ws2[0].value {
take $ws1.shift();
}
else {
take $ws2.shift();
}
}
# Finish streams
take $ws1.shift() while $ws1;
take $ws2.shift() while $ws2;
}
}
# Merge the sums of two streams
sub merge-sums($s1, $s2) {
return gather {
# Clone the streams
my $ws1 = $s1.clone;
my $ws2 = $s2.clone;
# While both remain
while $ws1 && $ws2 {
# Take heads
my $h1 = $ws1.shift();
my $h2 = $ws2.shift();
# Sum of heads
take sum-terms($h1, $h2);
# Rest of merge-sums
take $_
for merge(merge($ws2.map({ sum-terms($h1, $_) }),
$ws1.map({ sum-terms($_, $h2) })),
merge-sums($ws1, $ws2));
}
}
}
# Main
multi sub MAIN(Str $n-str) {
# Cubes
my $cubes = (1 .. *).map({ Term.new(value => $_ ** 3,
expression => sprintf("%d ** 3", $_)) });
# Merge them
my $merged = merge-sums($cubes, $cubes);
# How many
my $n = $n-str.Int;
# Iterate
my $prev = $merged.shift();
while $n > 0 && $merged {
# Store the first
my @terms = $prev;
# Next
my $next = $merged.shift();
while $next.value == $prev.value {
# Different expression?
@terms.push($next) if $next.expression ne $prev.expression;
# Next
$prev = $next;
$next = shift($merged);
}
# How many?
if @terms > 1 {
say(($prev.value, @terms>>.expression).join(' = '));
--$n;
}
# Last
$prev = $next;
}
}
# Call main
MAIN(|@*ARGS);
This code finds all sums of cubes.
It also seems to handle the case of more than two ways to write a sum of cubes, even though excessive resource usage prevented us from testing it.
Tabs and spaces are used more or less interchangeably, without any fixed
rule, and assuming a tabstop
of 8.
The code is easy to follow, and the comments sometimes clarify but mostly just repeat what the code already says.
The code is one of the slower solutions to task 2, mostly due to enqueuing so many objects that later turn out to be uninteresting.
Elegant use of infinite streams and gather
/take
.
The code has a "thin" feel: it's made up of quite a few parts, but each part is simple.