chiark / gitweb /
WIP rum calculations rework
authorIan Jackson <ian@liberator.relativity.greenend.org.uk>
Sun, 17 May 2009 22:25:03 +0000 (23:25 +0100)
committerIan Jackson <ian@liberator.relativity.greenend.org.uk>
Sun, 17 May 2009 22:25:03 +0000 (23:25 +0100)
ypp-restock-rum

index 7e10a46..7587a3c 100755 (executable)
 #!/usr/bin/perl -w
-use strict qw (vars);
+use strict qw(vars);
 use IO::Handle;
 use POSIX;
 
-our ($ship, %have, %price);
-
 my $usage = <<END
 usage:
-  .../ypp-restock-rum [<prices>] [<ship> <stocks>]
-where
- <prices> is three arguments: the prices for swill, grog and fine rum
- <ship> is a ship name or an amount of fine rum
- <stocks> are amounts on board for swill, grog and fine rum
+  .../ypp-restock-rum [<information> ...]
+
+where <information> is
+
+  have  [<swill> <grog>] <fine> [<hold_shot>+<loaded_shot>]
+  want  [<swill> <grog>] <fine> [<shot>]
+  price  <swill> <grog>  <fine> [<shot>]
+
+Each of which may appear only once, except \`have' which may appear
+more than once which case we calculate the differences and the profit
+for each one.
+
+If /<shot> is not specified at all, relevant information about shot is
+not reported.  For have and want, specifying an empty string means
+zero.  Entirely Missing <swill>/<grog>/ is taken as if both were
+specified and zero.
+
+In price, missing entries mean the commodity is unavailable.
 END
 ;
 
-sub main () {
-    if (@ARGV==4) {
-       ($ship, $have{Swill}, $have{Grog}, $have{Fine}) = @ARGV;
-       print_inputs();
-       compute_restock_requirements();
-    } elsif (@ARGV==3) {
-       ($price{Swill}, $price{Grog}, $price{Fine}) = @ARGV;
-       print_inputs();
-       compute_cheapest_rum();
-    } elsif (@ARGV==7) {
-       ($price{Swill}, $price{Grog}, $price{Fine},
-        $ship,
-        $have{Swill}, $have{Grog}, $have{Fine}) = @ARGV;
-       print_inputs();
-       compute_cheapest_rum();
-       compute_restock_requirements();
-       compute_restock_cheapest_rum();
+our (@vals) = qw(swill grog fine shot);
+our (@proofs) = qw(40 60 100);
+
+sub parse_info ($$$\@$) {
+    my ($omitswgok,$default,$multishot, $storeary, $what) = @_;
+    @ARGV or badusage("missing value for information argument \`$_'");
+    badusage("$what: specified more than once")
+       if defined $storeary->[2];
+    my (@v) = ();
+    while (@ARGV and $ARGV[0] =~ m/^\d/) {
+       $_ = shift @ARGV;
+       push @v, $_;
+    }
+    if (@v==1 or @v==2) {
+       badusage("$what: swill and grog amounts must be specified")
+           unless $omitswgok;
+       @v=($default,$default,@v);
+    }
+    if ($multishot and @v==4 and length $v[3]) {
+       $v[3] =~ m/^0*(\d+)\+0*(\d+)$/ or
+           badusage("$what: shot must be specified as <hold>+<loaded>");
+       $v[3] = $1 + $2;
+    }
+    if (@v==3) {
+       push @v, $default;
+    }
+    if (@v != 4) {
+       badusage("$what: invalid syntax (wrong number of /s)");
+    }
+    my $i=0;
+    foreach $_ (@v) {
+       $_ = $default if !length;
+       m/^0*(\d+)$/ or badusage("$what: $vals[$i] \`$_': bad syntax");
+       $_= $1;
+       $i++;
+    }
+    @$storeary = @v;
+}
+
+our (@haves,@want,@price);
+
+sub parse_args () {
+    @ARGV or badusage("need some information to go on");
+    while (@ARGV) {
+       $_ = shift @ARGV;
+       if (m/^have$/) {
+           parse_info(1,0,1, @{ $haves[@haves] }, 'BUG');
+       } elsif (m/^want$/) {
+           parse_info(1,0,0, @want, 'want');
+       } elsif (m/^price$/) {
+           parse_info(0,1e6,0, @price, 'price');
+       } else {
+           badusage("unknown information argument \`$_'");
+       }
+    }
+}
+
+sub badusage ($) {
+    my ($m) = @_;
+    print STDERR "bad usage: $m\n\n$usage\n";
+    exit 16;
+}
+
+parse_args();
+use Data::Dumper;
+print Dumper({ Have => \@haves, Want => \@want, Price => \@price });
+
+our @norm_price;
+our $best;
+
+sub compute_cheapest_rum() {
+    return unless @price;
+
+    $best= undef;
+    my $best_norm_price= 1e5;
+    for my $i (qw(0 1 2)) {
+       next unless $price[$i];
+       $norm_price[$i] = $price[$i] * $proof[$i] / $proof[$i];
+       if ($norm_price[$i] <= $best_norm_price) {
+           $best= $i;
+       }
+    };
+    prf('normalised prices', @norm_price, 'poe/fine');
+    if (defined $best) {
+       printf "best is %s\n\n", $best;
     } else {
-       die $usage;
+       die "no rum available ?\n";
     }
 }
 
-our @rums= qw(Swill Grog Fine);
-our %proof= qw(Swill  40
-              Grog   60
-              Fine  100);
+
+
+__DATA__
 
 our $ff = '%6.1f';
 
@@ -70,27 +148,7 @@ sub pr1 ($$) {
     printf "%-20s %s\n", "$k:", $v;
 }
 
-our ($best_kind);
-
-sub compute_cheapest_rum() {
-    $best_kind= undef;
-    my %norm_price;
-    my $best_norm_price= 1e6;
-    foreach $_ (@rums) {
-       next unless defined $price{$_};
-       $norm_price{$_} = $price{$_} * $proof{Fine} / $proof{$_};
-       if ($norm_price{$_} <= $best_norm_price) {
-           $best_kind= $_;
-           $best_norm_price= $norm_price{$_};
-       }
-    };
-    prf('normalised prices', %norm_price, 'poe/fine');
-    if (defined $best_kind) {
-       printf "best is %s\n\n", $best_kind;
-    } else {
-       die "no rum available ?\n";
-    }
-}
+our ($best);
 
 our $have_proof;
 
@@ -165,9 +223,9 @@ sub compute_restock_cheapest_rum() {
     if ($need_proof < 0) {
        printf "stocks are sufficient";
     } else {
-       my $buy= ceil($buy{$best_kind});
+       my $buy= ceil($buy{$best});
        printf "buy %d %s at %d poe each for %d poe",
-           $buy, $best_kind, $price{$best_kind}, $buy * $price{$best_kind};
+           $buy, $best, $price{$best}, $buy * $price{$best};
     }
     print "\n\n";
 }