t1/az5112-2

Download the raw code.

#!/usr/bin/env perl6

# This is perl6 version 2011.12-18-ga7fd89e built on parrot 3.11.0 revision RELEASE_3_11_0

sub parens( $s ) {
    return $s eq '9' ?? $s !! '(' ~ $s ~ ')';
};

sub operate( $num1, $exp1, $num2, $exp2 ) {
    my @result;

    push @result, $num1 + $num2;
    push @result, parens( $exp1 ) ~ " + " ~ parens( $exp2 );

    push @result, $num1 - $num2;
    push @result, parens( $exp1 ) ~ " - " ~ parens( $exp2 );

    push @result, $num1 * $num2;
    push @result, parens( $exp1 ) ~ " * " ~ parens( $exp2 );

    if $num2 != 0 {
        push @result, $num1.Int div $num2.Int;
        push @result, parens( $exp1 ) ~ " / " ~ parens( $exp2 );

        push @result, $num1 % $num2;
        push @result, parens( $exp1 ) ~ " % " ~ parens( $exp2 );
    };

    return @result;
}

sub mate-levels( %numexp1, %numexp2 ) {
    my @result;

    for %numexp1.kv -> $num1, $exp1 {
        for %numexp2.kv -> $num2, $exp2 {
            push @result, operate $num1, $exp1, $num2, $exp2;
            push @result, operate $num2, $exp2, $num1, $exp1;
        }
    }
    return @result;
}

sub insert-num-exp-pairs( %dst, @new ) {
    for @new -> $num, $exp {
        # Select the most readable (=shortest) expression.
        if not %dst.exists( $num ) or %dst{$num}.chars > $exp.chars {
            %dst{$num} = $exp;
        }
    }
}

sub MAIN ( Int $N ) {
    # @all[1] holds numbers and expressions built with 1 nine.
    # @all[2..4] will hold numbers and expressions built with 2..4 nines.
    #
    # There are very few of those (<40) at @all[4] so one could just as
    # well predeclare value => expression hash with all the entries.
    my @all = ( 
        {},
        { 9 => "9", -9 => "-9" },
        {},
        {},
        {}
    );

    insert-num-exp-pairs( @all[2], mate-levels( @all[1], @all[1] ));

    insert-num-exp-pairs( @all[3], mate-levels( @all[1], @all[2] ));

    insert-num-exp-pairs( @all[4], mate-levels( @all[1], @all[3] ));
    insert-num-exp-pairs( @all[4], mate-levels( @all[2], @all[2] ));

    for 0 .. $N -> $n {
        say $n ~ ( @all[4].exists( $n ) ?? ' = ' ~ @all[4]{$n} !! '' );
    };
}

Correctness

The only significant change to the previous version seems to be this:

@@ -17,12 +19,12 @@
    push @result, parens( $exp1 ) ~ " * " ~ parens( $exp2 );

    if $num2 != 0 {
-       push @result, $num1 / $num2;
+       push @result, $num1.Int div $num2.Int;
        push @result, parens( $exp1 ) ~ " / " ~ parens( $exp2 );

Which unfortunately leads to incorrect output. It now produces

4 = 9 / ((9 + 9) / 9)

Where the right-hand side produces 4.5 in proper arithemtic, not 4.