Saturday, February 20, 2010

E03 Second Stab

As usual, masak++ has some brilliant stuff in his take on the E03 challenge, which I am shamelessly borrowing for my second version. On the other hand, I think he has done himself a disservice by not making sure his code actually works in Rakudo, as I see several dodgy spots and an entire missing function in his version.

So, some notes on masak's code:
1) His default value for @dirpath is wonky. First, he seems to be assigning @std_dirpath to @last_dirpath if the former is undefined. Second, neither of those variables is actually declared. Third, he's left off the '.' case, which is the one that actually works.

2) On the plus side, he has a working regular expression for the subst, and includes the assignment operator I forgot (in my comment version). On the minus side, the right hand side of the substitution is bad -- it works in theory, but does not work in practice in Rakudo alpha (nor master, so far as I know).

3) I'm amused that he used comb instead of the original's split. Both lines have the exact same effect, so far as I know. Arguably his has a little more style than mine.

4) I'm interested that he didn't notice that %data{$filepath}{"filepath"} = $filepath is kind of redundant.

5) Kudos for remembering how to declare a constant. But without the seek method, @StartOfFile is never actually used in the code.

6) His save_data is kind of drastically more complicated than mine, because he didn't just read the rest of the file in load_data and store it. He also uses lines instead of slurp, which makes writing out the data a bit more complicated as well. (Are those .list statements really necessary?)

7) He relies on the E03's explanation that a Str converted to Num will return NaN if it is not a valid number. That's certainly not true of Rakudo alpha. I'm not clear if it's true in the Perl 6 spec or not. (Of course, I skipped that bit altogether...)

So here's my second version. I cribbed a few things from masak's version, and added an arbitrary second default directory so I could make sure that it handled having more than one file.

sub load_data($filename, $version = 1, *@dirpath is copy) {
@dirpath = './', 'peter/' unless +@dirpath;
@dirpath>>.=subst(/(<-[/]>)$/, {"$1/"}); # doesn't actually work in Rakudo alpha
say @dirpath.join("\n");

my %data;
for @dirpath -> $prefix {
my $filepath = $prefix ~ $filename;

if ($filepath ~~ :e and 100 < ($filepath ~~ :s) <= 1e6) {
say "Trying to open $filepath";
my $fh = open($filepath, :r)
or die "Something screwy with $filepath: $!";
my ($name, $vers, $status, $costs) = $fh.lines(4);
next if $vers < $version;
$costs = [split /\s+/, $costs];
%data{$filepath} = {};
%data{$filepath}<name vers stat costs rest> =
($name, $vers, $status, $costs, $fh.slurp);
say "$filepath done";
$fh.close;
}
}
return %data;
}

sub save_data(%data) {
for %data.kv -> $filepath, $data {
say "saving $filepath";
my $fh = open($filepath, :w)
or die "Something screwy with $filepath: $!";
$fh.print: ($data.<name vers stat>, ~($data.<costs>), $data.<rest>).join("\n");
$fh.close;
}
}

# I've no idea what this sub was supposed to do, so let's stick with something really
# simple for the moment.
sub amortize($a) {
$a;
}

my %data = load_data(filename=>'weblog', version=>1);
constant $is_active_bit = 0x0080;
for %data.kv -> $file, $data {
say "$file contains data on { $data<name> }";
$data<stat> +^= $is_active_bit;

my @costs := $data<costs>;
my $inflation = 0;
$inflation = prompt 'Inflation rate: '
until $inflation > 0;

@costs = (@costs >>*>> $inflation).sort({ amortize($_) });

say "Total expenditure: { [+] @costs }";
say "Major expenditure: { [+] @costs.grep({$_ >= 1000}) }";
say "Minor expenditure: { [+] @costs.grep({$_ < 1000}) }";
say "Odd expenditures: { @costs.map(-> $a, $b { $a }) }";
}

# save_data(%data, log => {name=>'metalog', vers=>1, costs=>[], stat=>0});
save_data(%data);

No comments:

Post a Comment