--- /dev/null
+#!/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();