chiark / gitweb /
routesearch: improve arg parsing
[ypp-sc-tools.main.git] / yarrg / web / query_routesearch
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 generates the core of the `routesearch' query.
33
34
35 </%doc>
36 <%args>
37 $quri
38 $dbh
39 $islandstring => '';
40 $capacitystring => '';
41 $lossperleague => '';
42 $capitalstring => '';
43 $distance => '';
44 $someresults
45 $emsgokorprint
46 </%args>
47
48 <%perl>
49 use BSD::Resource;
50
51 my $emsg;
52 my @warningfs;
53 my @islandids;
54
55 my $qa= \%ARGS;
56 my $routeparams= { EmsgRef => \$emsg, SayRequiredCapacity => 1 };
57 my $maxdist;
58 my $maxcountea=10;
59 my $maxcpu=10;
60
61 </%perl>
62
63 <h1>Find most profitable routes and trades</h1>
64
65 % if ($qa->{Dropdowns}) {
66 This feature is not available from the "drop down menus" interface.
67 % } else {
68
69 <form action="<% $quri->() |h %>" method="get">
70
71 <& enter_route, qa=>$qa, dbh=>$dbh, emsg_r=>\$emsg, warningfs_r=>\@warningfs,
72         enterwhat => 'Enter starting point(s)',
73         islandids_r => \@islandids, archipelagoes_r => undef
74  &>
75
76 <&| enter_advrouteopts, qa=>$qa, dbh=>$dbh, routeparams=>$routeparams &>
77 <td>
78 &nbsp;
79 &nbsp;
80 <td>
81  Maximum distance:
82  <&| qtextstring, qa => $qa, dbh => $dbh, prefix => 'ml',
83     thingstring => 'distance', emsgstore => \$emsg,
84     onresults => sub { ($maxdist)= @_; } &>
85    size=10
86  </&>
87 </&>
88
89 <input type=submit name=submit value="Go">
90 % my $ours= sub { $_[0] =~ m/^lossperleague|^islandstring|^capitalstring|^capacitystring|^distance/; };
91 <& "lookup:formhidden", ours => $ours &>
92
93 % }
94
95 </form>
96 <%perl>
97
98 if (!$emsg && $maxdist > 30) {
99         $emsg= "Searching for routes of more than 30 leagues is not".
100                 " supported, sorry.";
101 }
102
103 $emsgokorprint->($emsg) or return;
104 @islandids or return;
105 defined $routeparams->{MaxMass} or defined $routeparams->{MaxVolume} or return;
106
107 #---------- prepare island names ----------
108
109 my $islandname_stmt= $dbh->prepare(<<END);
110         SELECT islandname, archipelago
111           FROM islands
112          WHERE islandid = ?
113 END
114
115 my $isleinfo = sub {
116         my ($id) = @_;
117         $islandname_stmt->execute($id);
118         my $row= $islandname_stmt->fetchrow_hashref();
119         local $_= $row->{'islandname'};
120         s/ Island$//;
121         return $_, $row->{'archipelago'};
122 };
123
124 #---------- compute the results ----------
125
126 my @rsargs= qw(-DN);
127
128 foreach my $k (qw(MaxMass MaxVolume MaxCapital)) {
129         my $v= $routeparams->{$k};
130         push @rsargs, (defined $v ? $v : -1);
131 }
132 push @rsargs, defined $routeparams->{LossPerLeaguePct}
133         ? $routeparams->{LossPerLeaguePct}*0.01 : 1e-9;
134 push @rsargs, 'search',$maxdist, $maxcountea,$maxcountea, 'any', @islandids;
135
136 m/[^-.0-9a-zA-Z]/ and die "$_ $& ?" foreach @rsargs;
137
138 if ($qa->{'debug'}) {
139 </%perl>
140 [[ <% "@rsargs" |h %> ]]<br><pre>
141 <%perl>
142 }
143
144 unshift @rsargs, sourcebasedir().'/yarrg/routesearch',
145         '-d', dbw_filename($qa->{'Ocean'});
146
147 my %results; # $results{$ap}{"5 6 9 10"} = { stuff }
148
149 my $fh= new IO::File;
150 my $child= $fh->open("-|"); defined $child or die $!;
151 if (!$child) {
152         my $cpu= BSD::Resource::RLIMIT_CPU;
153         my ($soft,$hard)= getrlimit($cpu);
154         setrlimit($cpu,$maxcpu,$hard) or die $! if $soft>$maxcpu;
155         exec @rsargs;
156         die $!;
157 }
158
159 while (<$fh>) {
160         chomp;
161         if ($qa->{'debug'}) {
162 </%perl>
163 <% $_ |h %>
164 <%perl>
165         }
166         next unless
167   m/^ \@ *\d+ ([ap])\# *\d+ \|.*\| *\d+ +(\d+) +(\d+) *\| ([0-9 ]+)$/;
168         my ($ap,$isles) = (uc $1,$4);
169         next if $results{$ap} && %{$results{$ap}} >= $maxcountea;
170         my $item= { A => $2, P => $3 };
171         my (@i, @a);
172         foreach (split / /, $isles) {
173                 my ($name,$arch)= $isleinfo->($_);
174                 push @i, $name;
175                 push @a, $arch unless @a && $a[-1] eq $arch;
176         }
177         $item->{Isles}= [ @i ];
178         $item->{Archs}= [ @a ];
179         $item->{Start}= $i[0];
180         $item->{Finish}= $i[-1];
181         $item->{Vias}= [ ];
182         my $i;
183         for ($i=1; $i < @i-1; $i++) {
184                 push @{ $item->{Vias} }, $i[$i];
185         }
186         $results{$ap}{$isles}= $item;
187 }
188
189 if ($qa->{'debug'}) {
190         print "</pre>\n";
191 }
192
193 </%perl>
194 % foreach my $ap (qw(A P)) {
195 <h2>ap=<% $ap %></h2>
196 <table rules=groups>
197 <colgroup span=2>
198 <colgroup span=1>
199 <colgroup span=3>
200 <tbody>
201 <tr>
202 <th colspan=2>Profit
203 <th>Archipelagoes
204 <th colspan=3>Route
205 <tr>
206 <th>Abs.
207 <th>Per.lg.
208 <th>
209 <th>Start
210 <th>Via
211 <th>Finish
212 <tbody>
213 %       my $datarow=0;
214 %       foreach my $isles (sort {
215 %                       $results{$ap}{$b}{$ap} <=>
216 %                       $results{$ap}{$a}{$ap}
217 %               } keys %{$results{$ap}}) {
218 %               my $item= $results{$ap}{$isles};
219 <tr class="datarow<% $datarow %>">
220 <td align=right><% $item->{A} |h %>
221 <td align=right><% $item->{P} |h %>
222 <td align=left><% join ', ', @{ $item->{Archs} } |h %>
223 <td align=left><% $item->{Start} |h %>,
224 <td align=left><% join ' ', map { $_.',' } @{ $item->{Vias} } |h %>
225 <td align=left><% $item->{Finish} |h %>
226 </td>
227 %               $datarow ^= 1;
228 %       } # $isles
229 </table>
230 % } # $ap
231 <%perl>
232
233
234 </%perl>