chiark / gitweb /
Allow %age adjustments to capacity
[ypp-sc-tools.db-live.git] / yarrg / web / check_capacitystring
1 <%doc>
2
3  This is part of the YARRG website.  YARRG is a tool and website
4  for assisting players of Yohoho Puzzle Pirates.
5
6  Copyright (C) 2009 Ian Jackson <ijackson@chiark.greenend.org.uk>
7  Copyright (C) 2009 Clare Boothby
8
9   YARRG's client code etc. is covered by the ordinary GNU GPL (v3 or later).
10   The YARRG website is covered by the GNU Affero GPL v3 or later, which
11    basically means that every installation of the website will let you
12    download the source.
13
14  This program is free software: you can redistribute it and/or modify
15  it under the terms of the GNU Affero General Public License as
16  published by the Free Software Foundation, either version 3 of the
17  License, or (at your option) any later version.
18
19  This program is distributed in the hope that it will be useful,
20  but WITHOUT ANY WARRANTY; without even the implied warranty of
21  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  GNU Affero General Public License for more details.
23
24  You should have received a copy of the GNU Affero General Public License
25  along with this program.  If not, see <http://www.gnu.org/licenses/>.
26
27  Yohoho and Puzzle Pirates are probably trademarks of Three Rings and
28  are used without permission.  This program is not endorsed or
29  sponsored by Three Rings.
30
31
32  This Mason component simply defines how to interpret capacities.
33
34 </%doc>
35
36 <%attr>
37 maxambig => 2
38 </%attr>
39
40 <%method preparse>
41 <%args>
42 $h
43 </%args>
44 <%perl>
45
46 my $parse_numeric= sub {
47         # returns (mass,volume,emsg)
48         my ($string,$default)= @_;
49
50         my @mve= (undef,undef,undef);
51
52         if ($string !~ m/\d/) {
53                 return (undef,undef,
54                         'Adjustments to capacity must contain digits.');
55         }
56
57         my $def= sub {
58                 my ($ix,$what,$val) = @_;
59                 if (defined $h->{$what}) {
60                         $mve[2]= "\`$string' specifies $what more than once.";
61                 }
62                 print STDERR "SET $what $val\n";
63                 $mve[$ix]= $val;
64         };
65
66 print STDERR "PAN \`$string'\n";
67         local $_;
68         foreach $_ (split /\s+/, $string) {
69                 print STDERR "ITEM \`$_'\n";
70                 next unless length;
71                 if (m/^([1-9]\d{0,8})l$/) {
72                         $def->(1, 'volume', $1);
73                 } elsif (m/^([1-9]\d{0,8})kg$/) {
74                         $def->(0, 'mass', $1);
75                 } elsif (m/^([1-9]\d{0,5}(?:\.\d{0,3})?)kl/) {
76                         $def->(1, 'volume', $1 * 1000);
77                 } elsif (m/^([1-9]\d{0,5}(?:\.\d{0,3})?)t/) {
78                         $def->(0, 'mass', $1 * 1000);
79                 } else {
80                         $mve[2]= "Cannot understand item \`$_'".
81                                 " in numeric capacity";
82                 }
83         }
84 #       foreach my $ix (qw(0 1)) {
85 #               $mve[$ix]= $default unless defined $mve[$ix];
86 #       }
87         return @mve;
88 };
89
90 my @mv_names= qw(mass volume);
91 my $canon_numeric= $h->{'canon_numeric'}= sub {
92         print STDERR "CANNUM @_\n";
93         my $sep= '';
94         my $out= '';
95         foreach my $ix (qw(0 1)) {
96                 next unless defined $_[$ix];
97                 $out .= $sep; $sep= ' ';
98                 $out .= sprintf "%g%s", $_[$ix], (qw(kg l))[$ix];
99         }
100         return $out;
101 };
102
103 $h->{'deltas'}= [ ];
104 print STDERR "NDELTA0 $#{ $h->{'deltas'} }\n";
105
106 local ($_)= ${ $h->{String} };
107 while (m/^(.*)(\bminus\b|-|\bplus\b|\+)/) {
108         my ($lhs,$rhs)= ($1,$');
109         print STDERR "TERM L=\`$1' M=\`$2' R=\`$''\n";
110         my ($signum,$signopstr)= 
111                 $2 =~ m/^p|^\+/ ? (+1,'plus') : (-1,'minus');
112         my @mveco;
113         if ($rhs =~ m/^\s*(\d{1,2}(?:\.\d{0,4})?)\%\s*$/) {
114                 my $pct= 100.0 + $signum * $1;
115                 @mveco= ($pct,$pct,undef);
116                 push @mveco, sprintf "%s %g%%", $signopstr, $1;
117                 push @mveco, sub {
118                         return undef unless defined $_[0];
119                         $_[0] * $_[1] / 100.0
120                 };
121         } else {
122                 @mveco= $parse_numeric->($rhs, 0);
123                 if (!defined $mveco[2]) {
124                         push @mveco, $signopstr.' '.$canon_numeric->(@mveco);
125                         push @mveco, sub {
126                                 ${ $h->{Emsg} }= "Cannot add or subtract".
127                                         " mass to/from volume"
128                                         unless defined $_[0];
129                                 $_[0] + $_[1] * $signum
130                         };
131                 }
132         }
133         ${ $h->{Emsg} }= $mveco[2] if defined $mveco[2];
134         unshift @{ $h->{'deltas'} }, [ @mveco ];
135         print STDERR "NDELTA $#{ $h->{'deltas'} }\n";
136         $_= $lhs;
137 }
138
139 s/^\s+//; s/\s+$//;
140
141 if (m/^[a-z ]+$/) {
142         push @{ $h->{Specs} }, $_;
143 } elsif (m/\d/) {
144         my (@mve)= $parse_numeric->($_, undef);
145         if (defined $mve[2]) { ${ $h->{Emsg} }= $mve[2]; return; }
146         $h->{'initial'}= \@mve;
147 } elsif (m/\S/) {
148         ${ $h->{Emsg} }= "Cannot understand capacity specification \`$_'.";
149 } else {
150         $h->{'initial'}= [undef,undef];
151 }
152
153 </%perl>
154 </%method>
155
156 <%method sqlstmt>
157 SELECT name,mass,volume
158         FROM vessels WHERE name LIKE ?
159 </%method>
160
161 <%method nomatch>
162   Did not understand ship name.
163 </%method>
164
165 <%method ambiguous>
166   Ambiguous - could be <% $ARGS{couldbe} |h %>
167 </%method>
168
169 <%method manyambig>
170   Too many matching ship types.
171 </%method>
172
173 <%method postquery>
174 <%args>
175 $h
176 </%args>
177 <%perl>
178
179 my $canon_numeric= $h->{'canon_numeric'};
180
181 return if length ${ $h->{Emsg} };
182
183 my @mv;
184 my @mv_names= qw(mass volume);
185 if (@{ $h->{Specs} }) {
186         @mv= @{ $h->{Results}[0] }[1,2];
187 } else {
188         @mv= @{ $h->{'initial'} };
189         ${ $h->{Canon} }= $canon_numeric->(@mv);
190 }
191 print STDERR "INITIAL @mv\n";
192
193 print STDERR "NDELTAE $#{ $h->{'deltas'} }\n";
194 foreach my $delta (@{ $h->{'deltas'} }) {
195         print STDERR "DELTA @$delta\n";
196         die if defined $delta->[2]; # emsg
197         foreach my $ix (qw(0 1)) {
198                 next unless defined $delta->[$ix];
199                 print STDERR "DELTA I $ix\n";
200                 $mv[$ix] = $delta->[4]->($mv[$ix], $delta->[$ix]);
201                 return if length ${ $h->{Emsg} };
202         }
203         ${ $h->{Canon} }.= ' '.$delta->[3];
204 }
205
206 if (@{ $h->{Specs} } || @{ $h->{'deltas'} }) {
207         ${ $h->{Canon} }.= "  [= ". $canon_numeric->(@mv). "]";
208 }
209
210 foreach my $ix (qw(0 1)) {
211         next unless defined $mv[$ix];
212         next if $mv[$ix] >= 0;
213         ${ $h->{Emsg} }= sprintf "%s limit is negative: %s",
214                 ucfirst($mv_names[$ix]), $canon_numeric->(@mv);
215         return;
216 }
217
218 @{ $h->{Results} }= [ @mv ];
219
220 </%perl>
221 </%method>