chiark / gitweb /
routesearch: permit approxiation by disregarding trivial trades
[ypp-sc-tools.db-test.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, '0';
135 push @rsargs, 'search',$maxdist, $maxcountea,$maxcountea, 'any', @islandids;
136
137 m/[^-.0-9a-zA-Z]/ and die "$_ $& ?" foreach @rsargs;
138
139 if ($qa->{'debug'}) {
140 </%perl>
141 [[ <% "@rsargs" |h %> ]]<br><pre>
142 <%perl>
143 }
144
145 unshift @rsargs, sourcebasedir().'/yarrg/routesearch',
146         '-d', dbw_filename($qa->{'Ocean'});
147
148 my %results; # $results{$ap}{"5 6 9 10"} = { stuff }
149
150 my $fh= new IO::File;
151 my $child= $fh->open("-|"); defined $child or die $!;
152 if (!$child) {
153         my $cpu= BSD::Resource::RLIMIT_CPU;
154         my ($soft,$hard)= getrlimit($cpu);
155         setrlimit($cpu,$maxcpu,$hard) or die $! if $soft>$maxcpu;
156         exec @rsargs;
157         die $!;
158 }
159
160 while (<$fh>) {
161         chomp;
162         if ($qa->{'debug'}) {
163 </%perl>
164 <% $_ |h %>
165 <%perl>
166         }
167         next unless
168   m/^ \@ *\d+ ([ap])\# *\d+ \|.*\| *\d+ +(\d+) +(\d+) *\| ([0-9 ]+)$/;
169         my ($ap,$isles) = (uc $1,$4);
170         next if $results{$ap} && %{$results{$ap}} >= $maxcountea;
171         my $item= { A => $2, P => $3 };
172         my (@i, @a);
173         foreach (split / /, $isles) {
174                 my ($name,$arch)= $isleinfo->($_);
175                 push @i, $name;
176                 push @a, $arch unless @a && $a[-1] eq $arch;
177         }
178         $item->{Isles}= [ @i ];
179         $item->{Archs}= [ @a ];
180         $item->{Start}= $i[0];
181         $item->{Finish}= $i[-1];
182         $item->{Vias}= [ ];
183         my $i;
184         for ($i=1; $i < @i-1; $i++) {
185                 push @{ $item->{Vias} }, $i[$i];
186         }
187         $results{$ap}{$isles}= $item;
188 }
189
190 if ($qa->{'debug'}) {
191         print "</pre>\n";
192 }
193
194 </%perl>
195 % foreach my $ap (qw(A P)) {
196 <h2>ap=<% $ap %></h2>
197 <table rules=groups>
198 <colgroup span=2>
199 <colgroup span=1>
200 <colgroup span=3>
201 <tbody>
202 <tr>
203 <th colspan=2>Profit
204 <th>Archipelagoes
205 <th colspan=3>Route
206 <tr>
207 <th>Abs.
208 <th>Per.lg.
209 <th>
210 <th>Start
211 <th>Via
212 <th>Finish
213 <tbody>
214 %       my $datarow=0;
215 %       foreach my $isles (sort {
216 %                       $results{$ap}{$b}{$ap} <=>
217 %                       $results{$ap}{$a}{$ap}
218 %               } keys %{$results{$ap}}) {
219 %               my $item= $results{$ap}{$isles};
220 <tr class="datarow<% $datarow %>">
221 <td align=right><% $item->{A} |h %>
222 <td align=right><% $item->{P} |h %>
223 <td align=left><% join ', ', @{ $item->{Archs} } |h %>
224 <td align=left><% $item->{Start} |h %>,
225 <td align=left><% join ' ', map { $_.',' } @{ $item->{Vias} } |h %>
226 <td align=left><% $item->{Finish} |h %>
227 </td>
228 %               $datarow ^= 1;
229 %       } # $isles
230 </table>
231 % } # $ap
232 <%perl>
233
234
235 </%perl>