t2/edgar

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);

Correctness

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.

Consistency

Tabs and spaces are used more or less interchangeably, without any fixed rule, and assuming a tabstop of 8.

Clarity of intent

The code is easy to follow, and the comments sometimes clarify but mostly just repeat what the code already says.

Algorithmic efficiency

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.

Idiomatic use of Perl 6

Elegant use of infinite streams and gather/take.

Brevity

The code has a "thin" feel: it's made up of quite a few parts, but each part is simple.