#!/usr/bin/perl -w use strict qw(vars); use IO::Handle; use POSIX; my $usage = < ...] where is have [ ] [+] want [ ] [] price [] 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 / is not specified at all, relevant information about shot is not reported. For have and want, specifying an empty string means zero. Entirely Missing // is taken as if both were specified and zero. In price, missing entries mean the commodity is unavailable. END ; 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 +"); $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 "no rum available ?\n"; } } __DATA__ 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); 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 () { 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}); printf "buy %d %s at %d poe each for %d poe", $buy, $best, $price{$best}, $buy * $price{$best}; } print "\n\n"; } main();