chiark / gitweb /
7e10a46e2deb82e12ad87f5aca13be316cdcea51
[ypp-sc-tools.web-live.git] / ypp-restock-rum
1 #!/usr/bin/perl -w
2 use strict qw (vars);
3 use IO::Handle;
4 use POSIX;
5
6 our ($ship, %have, %price);
7
8 my $usage = <<END
9 usage:
10   .../ypp-restock-rum [<prices>] [<ship> <stocks>]
11 where
12  <prices> is three arguments: the prices for swill, grog and fine rum
13  <ship> is a ship name or an amount of fine rum
14  <stocks> are amounts on board for swill, grog and fine rum
15 END
16 ;
17
18 sub main () {
19     if (@ARGV==4) {
20         ($ship, $have{Swill}, $have{Grog}, $have{Fine}) = @ARGV;
21         print_inputs();
22         compute_restock_requirements();
23     } elsif (@ARGV==3) {
24         ($price{Swill}, $price{Grog}, $price{Fine}) = @ARGV;
25         print_inputs();
26         compute_cheapest_rum();
27     } elsif (@ARGV==7) {
28         ($price{Swill}, $price{Grog}, $price{Fine},
29          $ship,
30          $have{Swill}, $have{Grog}, $have{Fine}) = @ARGV;
31         print_inputs();
32         compute_cheapest_rum();
33         compute_restock_requirements();
34         compute_restock_cheapest_rum();
35     } else {
36         die $usage;
37     }
38 }
39
40 our @rums= qw(Swill Grog Fine);
41 our %proof= qw(Swill  40
42                Grog   60
43                Fine  100);
44
45 our $ff = '%6.1f';
46
47 sub prvff ($$\%$) {
48     my ($what, $format, $ary, $unit) = @_;
49     printf("%-40s", "$what:");
50     map {
51         my $x= $ary->{$_};
52         my $y= defined $x ? sprintf $format, $x : '   x';
53         printf " %-10s", $y;
54     } @rums;
55     printf "  %s\n", $unit;
56 }
57
58 sub pr ($\%$) {
59     my ($what, $ary, $unit) = @_;
60     prvff($what, '%4d  ', %$ary, $unit);
61 }
62
63 sub prf ($\%$) {
64     my ($what, $ary, $unit) = @_;
65     prvff($what, $ff, %$ary, $unit);
66 }
67
68 sub pr1 ($$) {
69     my ($k,$v) = @_;
70     printf "%-20s %s\n", "$k:", $v;
71 }
72
73 our ($best_kind);
74
75 sub compute_cheapest_rum() {
76     $best_kind= undef;
77     my %norm_price;
78     my $best_norm_price= 1e6;
79     foreach $_ (@rums) {
80         next unless defined $price{$_};
81         $norm_price{$_} = $price{$_} * $proof{Fine} / $proof{$_};
82         if ($norm_price{$_} <= $best_norm_price) {
83             $best_kind= $_;
84             $best_norm_price= $norm_price{$_};
85         }
86     };
87     prf('normalised prices', %norm_price, 'poe/fine');
88     if (defined $best_kind) {
89         printf "best is %s\n\n", $best_kind;
90     } else {
91         die "no rum available ?\n";
92     }
93 }
94
95 our $have_proof;
96
97 sub print_inputs () {
98     printf("%40s",'');
99     map { printf " %5s     ", $_ } @rums;
100     print "\n\n";
101     if (defined $price{Swill}) {
102         map { $price{$_}= undef if $price{$_} eq 'x' } @rums;
103         pr('prices', %price, 'poe ea.');
104     }
105     if (defined $have{Swill}) {
106         $have_proof= 0;
107         map { $have_proof += $have{$_} * $proof{$_} } @rums;
108         pr('stock on board', %have, 'rum');
109     }
110 }
111
112 our ($need_proof, %need, %buy);
113
114 sub compute_restock_requirements () {
115     if ($ship =~ m/^\d+/) {
116         $need{Fine} = $ship;
117     } else {
118         $ship =~ y/_/ /;
119         open F, "/home/ian/private/puzzle-pirates" or die $!;
120         my $this_ship= 0;
121         my $the_ship;
122         while (<F>) {
123             if (!m/\S/ || m/^\s*\#/) {
124                 $this_ship= 0;
125                 next;
126             }
127             if (!m/^\@/) {
128                 next;
129             }
130             if (m/^\@(( [A-Z][-a-z]+){2,})\s*$/) {
131                 $this_ship= (uc $1 eq uc " $ship" or
132                              uc $+ eq uc " $ship");
133                 $the_ship= $1;
134                 next;
135             }
136             next unless $this_ship;
137             if (m/^\@\s+(\d+)\s+fine\s*/) {
138                 $need{Fine} = $1;
139                 last;
140             }
141         }
142         die $! if F->error;
143         die "unknown ship $ship" unless defined $need{Fine};
144         if (defined $ship) {
145             pr1("vessel",$the_ship);
146         }
147     }
148     pr1('desired stock level', sprintf("%4d fine rum", $need{Fine}));
149     $need_proof= $need{Fine} * $proof{Fine} - $have_proof;
150     map {
151         $buy{$_} = $need_proof / $proof{$_};
152     } @rums;
153     pr1("stock equivalent", sprintf "$ff fine rum", $have_proof / $proof{Fine});
154     pr1("restock equivalent", sprintf "$ff fine rum", $need_proof / $proof{Fine});
155     prf('would need', %buy, 'rum');
156 }
157
158 sub compute_restock_cheapest_rum() {
159     my %bill;
160     map {
161         $bill{$_} = $buy{$_} * $price{$_} if defined $price{$_};
162     } @rums;
163     prf('nominal bill', %bill, 'poe');
164     print "\n";
165     if ($need_proof < 0) {
166         printf "stocks are sufficient";
167     } else {
168         my $buy= ceil($buy{$best_kind});
169         printf "buy %d %s at %d poe each for %d poe",
170             $buy, $best_kind, $price{$best_kind}, $buy * $price{$best_kind};
171     }
172     print "\n\n";
173 }
174
175 main();