Stories
Slash Boxes
Comments
NOTE: use Perl; is on undef hiatus. You can read content, but you can't post it. More info will be forthcoming forthcomingly.

All the Perl that's Practical to Extract and Report

use Perl Log In

Log In

[ Create a new account ]

colomon (8994)

colomon
  (email not shown publicly)

Journal of colomon (8994)

Wednesday December 24, 2008
08:51 PM

Phone Number Script, Improved Version

I just realized that my problem with trans was that I had that extra space between the function call and the paren. With that removed, trans works perfectly, and makes a more elegant version of my script:

my $wordlist_filename = "wordlist.txt";
my $test_numbers_filename = "numbers.txt";

sub Number (Str $s)
{
    my $result = lc($s);
    $result.=trans('abc' => '2', 'def' => '3', 'ghi' => '4',
                   'jkl' => '5', 'mno' => '6', 'prs' => '7',
                   'tuv' => '8', 'wxy' => '9');
    return $result;
}

my $wordlist = open($wordlist_filename);
    # err die "Could not open $wordlist: $!\n";

my %numbers;

for (=$wordlist) -> $word
{
    if ($word ~~ /^\w\w\w\w\w\w\w$/)
    {
        my $number = Number($word);
        say "$word ==> $number";
        %numbers{$number} = $word;
    }
}
close ($wordlist);

my $test_numbers = open($test_numbers_filename);
for (=$test_numbers) -> $number
{
    my $word = %numbers{$number};
    say "$number ==> $word";
}
close ($test_numbers);

Note that in a comment jj suggests a much more spiffy and Perlish way of doing this, which I may try translating to Perl 6 if I get ambitious....

10:56 AM

Second Script Game: Finished Script

Quibbles in my last post aside, this one pretty much just worked beautifully:

my $file = "skaters.txt";

my @names;
my %scores;

my $skaters = open ($file);
for (=$skaters) -> $skater
{
    my @scores = split ",", $skater;
    my $name = shift @scores;
    push @names, $name;
    my $score = (([+] @scores) - (@scores.min() + @scores.max())) / 5.0;
    %scores{$name} = $score;
    say "$name => $score";
}
close $skaters;

my @sorted_names = sort { %scores{$^b} <=> %scores{$^a} }, @names;
say "Gold medal: {@sorted_names[0]}, {%scores{@sorted_names[0]}}";
say "Silver medal: {@sorted_names[1]}, {%scores{@sorted_names[1]}}";
say "Bronze medal: {@sorted_names[2]}, {%scores{@sorted_names[2]}}";

I was a little surprised the extra braces were required in the say statements, but it still is pretty darned elegant.

10:28 AM

Second Script Game: Skating Scores

This one is simple: take a list of skating scores, drop the highest and lowest, and take the average of the remaining to get the actual score. Perl 6 shines here, with split and the reduction meta operator making for elegant code. But I've hit on a weird snag:

$score = $score - (@scores.min () + @scores.max ());

doesn't compile. Err... but

$score = $score - (@scores.min() + @scores.max());

does. Is space before function parameters no longer allowed?

09:35 AM

"Finished" script

I don't think this code is going to win any converts to Perl 6, but here's what I've got:

my $wordlist_filename = "wordlist.txt";
my $test_numbers_filename = "numbers.txt";

sub Number (Str $s)
{
    # $s.=trans ('abc' => '2', 'def' => '3', 'ghi' => '4');
    # $s ~~ tr/abcdefghijklmnopqrstuvwxyz/222333444555666777888999/;

    my $result;
    for (0..6) -> $i
    {
        my $c = lc($s.substr($i,1));
        given $c
        {
            when $c eq "a" || $c eq "b" || $c eq "c" { $c = '2'; }
            when $c eq "d" || $c eq "e" || $c eq "f" { $c = '3'; }
            when $c eq "g" || $c eq "h" || $c eq "i" { $c = '4'; }
            when $c eq "j" || $c eq "k" || $c eq "l" { $c = '5'; }
            when $c eq "m" || $c eq "n" || $c eq "o" { $c = '6'; }
            when $c eq "p" || $c eq "r" || $c eq "s" { $c = '7'; }
            when $c eq "t" || $c eq "u" || $c eq "v" { $c = '8'; }
            when $c eq "w" || $c eq "x" || $c eq "y" { $c = '9'; }
            # when $c ~~ /defDEF/ { $c = '3'; }
        }
        $result = $result ~ $c;
    }

    return $result;
}

my $wordlist = open($wordlist_filename);
    # err die "Could not open $wordlist: $!\n";

my %numbers;

for (=$wordlist) -> $word
{
    if ($word ~~ /^\w\w\w\w\w\w\w$/)
    {
        my $number = Number($word);
        say "$word ==> $number";
        %numbers{$number} = $word;
    }
}
close ($wordlist);

my $test_numbers = open($test_numbers_filename);
for (=$test_numbers) -> $number
{
    my $word = %numbers{$number};
    say "$number ==> $word";
}
close ($test_numbers);

Notes: The Number function works okay, but it is an awful hack -- what should be one line of code somehow becomes fifteen. err die error checking sadly does not work. I couldn't find a sane way to get the number of letters in a word. I couldn't figure out how to read from standard input.

On the plus side, the new for syntax is appealing. I love having named parameters for subroutines. The given statement is nice, though I wish I hadn't had to use it in this example. And hashes work correctly.

08:52 AM

switch statement versus ~~

I would have thought

        given $c
        {
            when $c ~~ /defDEF/ { $c = '3'; }
        }

would have worked? This isn't a big deal, it's easy enough to work around, but it does lose elegance points.

PS Looks like $s.substr($i,1) = $c; doesn't work yet, either? Or is there something wrong with the syntax of that?

05:04 AM

Messing Around With Scripting Games

So, I dived straight in with "Advanced Event 1: Could I Get Your Phone Number?" I messed around with Pugs a bit a few years back, but this is my first real attempt to do something with Raduko.

The problem is to convert a seven digit phone number to a seven letter word from the dictionary they provide. Trying to generate all the possible words from a given number seems too much like work to me, so I'm looking at the problem the other way around -- each seven letter word in the dictionary generates a unique number. I'll put those in a hash, and then looking up a word for a number will be easy. At least, that's my plan.

I didn't think of creating this journal until I'd worked on the problem a bit, so I don't have my earliest missteps handy. My first effort was just to read the wordlist file and find all the seven letter words. (BTW, this is with Parrot fetched from Subversion last night, and I suppose it's possible I borked my install because I had a previous version of Parrot (from tarball) installed on my machine.) It took a bit of playing around to figure out the new syntax for this sort of thing. The first big roadblock I hit was that I couldn't get the readline function to work for me. =$filehandle works instead, so that wasn't a show stopper.

My next attempt was to figure out a way to check if a string had exactly seven letters. It looked to me like .elems was the way to do that in P6, but it always seemed to return 1. (Possibly it was treating it as an array with one string in it, rather than a string with N characters in it?) .bytes and .codes didn't seem to be recognized at all.

I finally solved this with a clumsy but working regex: if ($word ~~ /^\w\w\w\w\w\w\w$/).

Then I worked on a sub to convert the input word to a number. New sub parameter syntax, yay! Laziness kicking in again, I figured good old tr was the easiest way to do the conversion. So far this one has me stumped, however. I haven't found a syntax for tr that Raduko likes yet.

Here's my current code:

my $wordlist_filename = "wordlist.txt";

sub Number (Str $s)
{
    $s.=trans ('abc' => '2', 'def' => '3');
    # $s ~~ tr/abcdefghijklmnopqrstuvwxyz/222333444555666777888999/;
    return $s;
}

my $wordlist = open($wordlist_filename);
    # err die "Could not open $wordlist: $!\n";

for (=$wordlist) -> $word
{
    if ($word ~~ /^\w\w\w\w\w\w\w$/)
    {
        my $number = Number($word);
        say "$word ==> $number";
    }
}

close ($wordlist);

(Also note that err die failed to compile, which is why it is commented out.)