X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~yarrgweb/git?p=ypp-sc-tools.db-test.git;a=blobdiff_plain;f=ypp-restock-rum;h=1b0a11f48cfaee7ad58c46def2192031cebcbf2e;hp=7587a3c79bf1d0ec7c062219c26126d617c19129;hb=9b746cc0a0512dd570aa5d4b6185bc1007f74b03;hpb=b6ecb7d63adfddaa239120d6e99f35de211a93e8;ds=sidebyside diff --git a/ypp-restock-rum b/ypp-restock-rum index 7587a3c..1b0a11f 100755 --- a/ypp-restock-rum +++ b/ypp-restock-rum @@ -1,4 +1,26 @@ #!/usr/bin/perl -w +# This is part of ypp-sc-tools, a set of third-party tools for assisting +# players of Yohoho Puzzle Pirates. +# +# Copyright (C) 2009 Ian Jackson +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# Yohoho and Puzzle Pirates are probably trademarks of Three Rings and +# are used without permission. This program is not endorsed or +# sponsored by Three Rings. + use strict qw(vars); use IO::Handle; use POSIX; @@ -14,19 +36,24 @@ where is 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. +more than once which case we calculate the financial implications +at each stage. -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. +Missing entries count as zero (and zeroes are not displayed in the output). +In price, \`x' means the commodity is unavailable. -In price, missing entries mean the commodity is unavailable. +The intended use is that at the start of the pillage you run: + ypp-restock-rum have ... want ... +to check that stocks are sufficient, or perhaps: + ypp-restock-rum have ... want ... price ... +if you want to stock up some more. At the end of the pillage, +run the same thing again with some extra parameters: + ypp-restock-rum have .. want ... have ... price ... +and it will tell you how you did and what the restock should be like. END ; -our (@vals) = qw(swill grog fine shot); +our (@kinds) = qw(Swill Grog Fine Shot); our (@proofs) = qw(40 60 100); sub parse_info ($$$\@$) { @@ -35,7 +62,7 @@ sub parse_info ($$$\@$) { badusage("$what: specified more than once") if defined $storeary->[2]; my (@v) = (); - while (@ARGV and $ARGV[0] =~ m/^\d/) { + while (@ARGV and $ARGV[0] =~ m/^\d|^x$/) { $_ = shift @ARGV; push @v, $_; } @@ -53,30 +80,43 @@ sub parse_info ($$$\@$) { push @v, $default; } if (@v != 4) { - badusage("$what: invalid syntax (wrong number of /s)"); + badusage("$what: invalid syntax (wrong number of parameters)"); } my $i=0; foreach $_ (@v) { - $_ = $default if !length; - m/^0*(\d+)$/ or badusage("$what: $vals[$i] \`$_': bad syntax"); - $_= $1; + if ($default>0 and m/^x$/) { + $_ = $default; + } elsif (m/^0*(\d+)$/) { + $_= $1; + } else { + badusage("$what: $kinds[$i] \`$_': bad syntax"); + } $i++; } @$storeary = @v; } -our (@haves,@want,@price); +our (@have,@want,@price); sub parse_args () { - @ARGV or badusage("need some information to go on"); + if (!@ARGV) { + print STDERR < \@haves, Want => \@want, Price => \@price }); +our $ff = '%6.1f'; + +sub valid ($) { + my ($x) = @_; + defined $x and $x and $x<1e5; +} + +sub prvff ($$\@$) { + my ($what, $format, $ary, $unit) = @_; + 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 ($\@$) { + 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; +} +sub fmt_stock_index ($) { + my ($si) = @_; + @have==1 ? '' : ' #'.$si; +} + +sub rum_total (\@) { + my ($rums) = @_; + my $total= 0; + foreach my $i (qw(0 1 2)) { + $total += $rums->[$i] * $proofs[$i] / 100; + } + return $total; +} our @norm_price; -our $best; +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() { return unless @price; + my (@perorder) = map { $_*10 } @price; + prf('equiv. ordering price', @perorder, 'poe/order'); + $best= undef; - my $best_norm_price= 1e5; + $best_norm_price= 1e6; for my $i (qw(0 1 2)) { next unless $price[$i]; - $norm_price[$i] = $price[$i] * $proof[$i] / $proof[$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) { - printf "best is %s\n\n", $best; - } else { - die "no rum available ?\n"; + 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 (valid($x)) { + printf ' %9.1f', $x; + } else { + printf " "; + } +} +sub compute_stock_values() { + return unless @have; + print @have>1 ? <[3] * $price[3] : 0; + my $total_value= $rum_value + $shot_value; -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; + printf "%-10s ", 'stocks'.fmt_stock_index(++$si).':'; + print ' ' if @have==1; + pr1s($stock_rum); + pr1s($rum_value); + print ' ' if @have==1; + printf "%6s", $stocks->[3] ? $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 "\n" if @have>1; + print "\n"; } -sub pr ($\%$) { - my ($what, $ary, $unit) = @_; - prvff($what, '%4d ', %$ary, $unit); +sub pr2 ($$$) { + my ($k,$v1,$v2) = @_; + printf "%-25s %-23s %s\n", "$k:", $v1, $v2; } -sub prf ($\%$) { - my ($what, $ary, $unit) = @_; - prvff($what, $ff, %$ary, $unit); +sub pr2rs ($$$) { + my ($k,$rum,$shot) = @_; + pr2($k, + valid($rum) ? sprintf("%12.1f fine equiv", $rum) : '', + valid($shot) ? sprintf("%10d shot", $shot) : ''); } -sub pr1 ($$) { - my ($k,$v) = @_; - printf "%-20s %s\n", "$k:", $v; -} +sub compute_restock_requirements () { + return unless @want; + + my $rum_want= rum_total(@want); -our ($best); + my $stocks= @have ? $have[-1] : [qw(0 0 0 0)]; + my $rum_have= rum_total(@$stocks); + + pr2rs('desired stock level', $rum_want, $want[3]); -our $have_proof; + my $rum_need = $rum_want - $rum_have; + my $shot_need = $want[3] - $stocks->[3]; -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 (@have) { + pr2rs('current stock', $rum_have, $stocks->[3]); + pr2rs('restock requirement', $rum_need, $shot_need); + print "\n"; } - 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 (@price) { + my ($rum_buy,$shot_buy) = ('',''); + my ($rum_bill,$shot_bill) = qw(0 0); + my $ok=1; + if ($rum_need > 0) { + if (defined $best) { + my $rum_qty= $rum_need * 100 / $proofs[$best]; + $rum_qty= ceil($rum_qty); + $rum_buy= sprintf('%12s %-11s ', + "** $rum_qty","$kinds[$best] **"); + $rum_bill= $rum_qty * $price[$best]; + } else { + $rum_buy= ' (rum unavailable)'; + $ok= 0; } - 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; + } + if ($shot_need > 0) { + if (valid($price[3])) { + $shot_buy= sprintf('%7s shot **', "** $shot_need"); + $shot_bill= $shot_need * $price[3]; + } else { + $shot_buy= ' (shot unavailable)'; + $ok= 0; } } - die $! if F->error; - die "unknown ship $ship" unless defined $need{Fine}; - if (defined $ship) { - pr1("vessel",$the_ship); + if (length($rum_buy) or length($shot_buy)) { + pr2($ok + ? sprintf('for a total of %d poe', $rum_bill + $shot_bill) + : 'for', + $rum_bill ? sprintf("%12d poe ", $rum_bill) : '', + $shot_bill ? sprintf("%10d poe", $shot_bill) : ''); + pr2('BUY', $rum_buy, $shot_buy); + } else { + print "stocks are sufficient.\n"; } + print "\n"; } - 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(); +parse_args(); +print_inputs(); +compute_cheapest_rum(); +compute_stock_values(); +compute_restock_requirements(); + +STDOUT->error and die $!; +close STDOUT or die $!;