chiark / gitweb /
ypp-restock-rum as found on liberator
[ypp-sc-tools.web-live.git] / ypp-restock-rum
diff --git a/ypp-restock-rum b/ypp-restock-rum
new file mode 100755 (executable)
index 0000000..7e10a46
--- /dev/null
@@ -0,0 +1,175 @@
+#!/usr/bin/perl -w
+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
+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();
+    } else {
+       die $usage;
+    }
+}
+
+our @rums= qw(Swill Grog Fine);
+our %proof= qw(Swill  40
+              Grog   60
+              Fine  100);
+
+our $ff = '%6.1f';
+
+sub prvff ($$\%$) {
+    my ($what, $format, $ary, $unit) = @_;
+    printf("%-40s", "$what:");
+    map {
+       my $x= $ary->{$_};
+       my $y= defined $x ? sprintf $format, $x : '   x';
+       printf " %-10s", $y;
+    } @rums;
+    printf "  %s\n", $unit;
+}
+
+sub pr ($\%$) {
+    my ($what, $ary, $unit) = @_;
+    prvff($what, '%4d  ', %$ary, $unit);
+}
+
+sub prf ($\%$) {
+    my ($what, $ary, $unit) = @_;
+    prvff($what, $ff, %$ary, $unit);
+}
+
+sub pr1 ($$) {
+    my ($k,$v) = @_;
+    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 $have_proof;
+
+sub print_inputs () {
+    printf("%40s",'');
+    map { printf " %5s     ", $_ } @rums;
+    print "\n\n";
+    if (defined $price{Swill}) {
+       map { $price{$_}= undef if $price{$_} eq 'x' } @rums;
+       pr('prices', %price, 'poe ea.');
+    }
+    if (defined $have{Swill}) {
+       $have_proof= 0;
+       map { $have_proof += $have{$_} * $proof{$_} } @rums;
+       pr('stock on board', %have, 'rum');
+    }
+}
+
+our ($need_proof, %need, %buy);
+
+sub compute_restock_requirements () {
+    if ($ship =~ m/^\d+/) {
+       $need{Fine} = $ship;
+    } else {
+       $ship =~ y/_/ /;
+       open F, "/home/ian/private/puzzle-pirates" or die $!;
+       my $this_ship= 0;
+       my $the_ship;
+       while (<F>) {
+           if (!m/\S/ || m/^\s*\#/) {
+               $this_ship= 0;
+               next;
+           }
+           if (!m/^\@/) {
+               next;
+           }
+           if (m/^\@(( [A-Z][-a-z]+){2,})\s*$/) {
+               $this_ship= (uc $1 eq uc " $ship" or
+                            uc $+ eq uc " $ship");
+               $the_ship= $1;
+               next;
+           }
+           next unless $this_ship;
+           if (m/^\@\s+(\d+)\s+fine\s*/) {
+               $need{Fine} = $1;
+               last;
+           }
+       }
+       die $! if F->error;
+       die "unknown ship $ship" unless defined $need{Fine};
+       if (defined $ship) {
+           pr1("vessel",$the_ship);
+       }
+    }
+    pr1('desired stock level', sprintf("%4d fine rum", $need{Fine}));
+    $need_proof= $need{Fine} * $proof{Fine} - $have_proof;
+    map {
+       $buy{$_} = $need_proof / $proof{$_};
+    } @rums;
+    pr1("stock equivalent", sprintf "$ff fine rum", $have_proof / $proof{Fine});
+    pr1("restock equivalent", sprintf "$ff fine rum", $need_proof / $proof{Fine});
+    prf('would need', %buy, 'rum');
+}
+
+sub compute_restock_cheapest_rum() {
+    my %bill;
+    map {
+       $bill{$_} = $buy{$_} * $price{$_} if defined $price{$_};
+    } @rums;
+    prf('nominal bill', %bill, 'poe');
+    print "\n";
+    if ($need_proof < 0) {
+       printf "stocks are sufficient";
+    } else {
+       my $buy= ceil($buy{$best_kind});
+       printf "buy %d %s at %d poe each for %d poe",
+           $buy, $best_kind, $price{$best_kind}, $buy * $price{$best_kind};
+    }
+    print "\n\n";
+}
+
+main();