X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~yarrgweb/git?a=blobdiff_plain;ds=sidebyside;f=ypp-restock-rum;h=a8791508840295b8e3700fa849d3df5be6413335;hb=52a268380c60676abe8960c7f6f0659c59eb71ea;hp=7e10a46e2deb82e12ad87f5aca13be316cdcea51;hpb=4fe752be5883e1b781c1e73f81eb30e3df0a23d1;p=ypp-sc-tools.web-live.git diff --git a/ypp-restock-rum b/ypp-restock-rum index 7e10a46..a879150 100755 --- a/ypp-restock-rum +++ b/ypp-restock-rum @@ -1,150 +1,256 @@ #!/usr/bin/perl -w -use strict qw (vars); +use strict qw(vars); use IO::Handle; use POSIX; -our ($ship, %have, %price); - my $usage = <] [ ] -where - is three arguments: the prices for swill, grog and fine rum - is a ship name or an amount of fine rum - are amounts on board for swill, grog and fine rum + .../ypp-restock-rum [ ...] + +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 ; -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 (@kinds) = 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: $kinds[$i] \`$_': bad syntax"); + $_= $1; + $i++; + } + @$storeary = @v; } -our @rums= qw(Swill Grog Fine); -our %proof= qw(Swill 40 - Grog 60 - Fine 100); +our (@have,@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, @{ $have[@have] }, 'have'); + } 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 "\nbad usage: $m\n\n$usage\n"; + exit 16; +} our $ff = '%6.1f'; -sub prvff ($$\%$) { +sub valid ($) { + my ($x) = @_; + defined $x and $x>0 and $x<1e4; +} + +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("%-25s", "$what:"); + for my $i (qw(0 1 2 3)) { + my $x= $ary->[$i]; + my $y= valid($x) ? sprintf $format, $x : ' '; + printf " %-9s", $y; + } printf " %s\n", $unit; } -sub pr ($\%$) { +sub pr ($\@$) { my ($what, $ary, $unit) = @_; - prvff($what, '%4d ', %$ary, $unit); + prvff($what, '%4d ', @$ary, $unit); } -sub prf ($\%$) { +sub prf ($\@$) { my ($what, $ary, $unit) = @_; - prvff($what, $ff, %$ary, $unit); + prvff($what, $ff, @$ary, $unit); } sub pr1 ($$) { my ($k,$v) = @_; printf "%-20s %s\n", "$k:", $v; } +sub fmt_stock_index ($) { + my ($si) = @_; + @have==1 ? '' : ' #'.$si; +} -our ($best_kind); +our @norm_price; +our ($best, $best_norm_price); + +sub print_inputs () { + printf("%25s",''); + map { printf " %5s ", $_ } @kinds; + print "\n\n"; + pr('prices', @price, 'poe ea.') if valid(@price); + pr('target stocks', @want, 'units') if valid(@want); + my $si=0; for my $stocks (@have) { + pr('actual stocks'.fmt_stock_index(++$si), + @$stocks, 'units'); + } + print "\n"; +} 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{$_}; + return unless @price; + + my (@perorder) = map { $_*10 } @price; + prf('equiv. ordering price', @perorder, 'poe/order'); + + $best= undef; + $best_norm_price= 1e5; + for my $i (qw(0 1 2)) { + next unless $price[$i]; + $norm_price[$i] = $price[$i] * 100 / $proofs[$i]; + if ($norm_price[$i] <= $best_norm_price) { + $best= $i; + $best_norm_price= $norm_price[$i]; } }; - prf('normalised prices', %norm_price, 'poe/fine'); - if (defined $best_kind) { - printf "best is %s\n\n", $best_kind; + prf('normalised prices', @norm_price, 'poe/fine'); + + if (defined $best) { + printf "best is %-10s%*s^^\n", + $kinds[$best], + $best*10+10, ''; + my (@bestperorder) = map { + $best_norm_price * $proofs[$_] / 100 * 10; + } qw(0 1 2); + #push @bestperorder, $perorder[3]; + prf('best is equiv. ordering', @bestperorder, 'poe/order'); + } + print "\n"; +} + +sub pr1s ($) { + my ($x) = @_; + if (defined $x and $x) { + printf ' %9.1f', $x; } else { - die "no rum available ?\n"; + printf " "; } } -our $have_proof; +sub compute_stock_values() { + return unless @have; + print <[$i] * $proofs[$i] / 100; + } + my $rum_value= defined($best) ? $stock_rum * $best_norm_price : 0; + my $shot_value= valid($price[3]) ? $stocks->[3] * $price[3] : 0; + my $total_value= $rum_value + $shot_value; + + printf "%-10s ", 'stocks'.fmt_stock_index(++$si).':'; + pr1s($stock_rum); + pr1s($rum_value); + printf "%6d", $stocks->[3]; + pr1s($shot_value); + pr1s($total_value); + + if (defined $last_value) { + printf(" %10.1f %10.1f", + $total_value - $last_value, + $total_value - $initial_value); + } + $initial_value= $total_value unless defined $initial_value; + $last_value= $total_value; + print "\n"; } + print <) { - 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 { @@ -165,9 +271,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"; }