chiark / gitweb /
Document the master-info files in README.files
[ypp-sc-tools.db-live.git] / yarrg / db-idempotent-populate
1 #!/usr/bin/perl -w
2 #
3 # Normally run from
4 #  update-master-info
5 #
6 # usage: ./db-idempotent-populate <Oceanname>
7 #  creates or updates OCEAN-Oceanname.db
8 #  from master-master.txt
9
10 # This is part of ypp-sc-tools, a set of third-party tools for assisting
11 # players of Yohoho Puzzle Pirates.
12 #
13 # Copyright (C) 2009 Ian Jackson <ijackson@chiark.greenend.org.uk>
14 #
15 # This program is free software: you can redistribute it and/or modify
16 # it under the terms of the GNU General Public License as published by
17 # the Free Software Foundation, either version 3 of the License, or
18 # (at your option) any later version.
19 #
20 # This program is distributed in the hope that it will be useful,
21 # but WITHOUT ANY WARRANTY; without even the implied warranty of
22 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23 # GNU General Public License for more details.
24 #
25 # You should have received a copy of the GNU General Public License
26 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
27 #
28 # Yohoho and Puzzle Pirates are probably trademarks of Three Rings and
29 # are used without permission.  This program is not endorsed or
30 # sponsored by Three Rings.
31
32 use strict (qw(vars));
33
34 use DBI;
35
36 use Commods;
37 use CommodsDatabase;
38
39 @ARGV==1 or die;
40 my ($oceanname) = @ARGV;
41
42 #---------- setup ----------
43
44 parse_info_serverside();
45 parse_info_serverside_ocean($oceanname);
46 our $ocean= $oceans{$oceanname};
47
48 db_setocean($oceanname);
49 db_writer();
50 db_connect();
51
52 #---------- schema ----------
53
54 foreach my $bs (qw(buy sell)) {
55     db_doall(<<END)
56  CREATE TABLE IF NOT EXISTS $bs (
57         commodid        INTEGER                 NOT NULL,
58         islandid        INTEGER                 NOT NULL,
59         stallid         INTEGER                 NOT NULL,
60         price           INTEGER                 NOT NULL,
61         qty             INTEGER                 NOT NULL,
62         PRIMARY KEY (commodid, islandid, stallid)
63  );
64  CREATE INDEX IF NOT EXISTS ${bs}_by_island ON $bs (commodid, islandid, price);
65  CREATE INDEX IF NOT EXISTS ${bs}_by_price  ON $bs (commodid, price, islandid);
66 END
67     ;
68 }
69
70 db_doall(<<END)
71  CREATE TABLE IF NOT EXISTS commods (
72         commodid        INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
73         commodname      TEXT    UNIQUE          NOT NULL,
74         unitmass        INTEGER,
75         unitvolume      INTEGER
76  );
77  CREATE TABLE IF NOT EXISTS islands (
78         islandid        INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
79         islandname      TEXT    UNIQUE          NOT NULL,
80         archipelago     TEXT                    NOT NULL
81  );
82  CREATE TABLE IF NOT EXISTS stalls (
83         stallid         INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
84         islandid        INTEGER                 NOT NULL,
85         stallname       TEXT                    NOT NULL,
86         UNIQUE (islandid, stallname)
87  );
88  CREATE TABLE IF NOT EXISTS uploads (
89         islandid        INTEGER PRIMARY KEY     NOT NULL,
90         timestamp       INTEGER                 NOT NULL,
91         message         TEXT                    NOT NULL,
92         clientspec      TEXT                    NOT NULL,
93         serverspec      TEXT                    NOT NULL
94  );
95  CREATE TABLE IF NOT EXISTS dists (
96         aiid            INTEGER                 NOT NULL,
97         biid            INTEGER                 NOT NULL,
98         dist            INTEGER                 NOT NULL,
99         PRIMARY KEY (aiid, biid)
100  );
101 END
102     ;
103
104 $dbh->commit;
105
106 #---------- commodity list ----------
107
108 {
109     my $insert= $dbh->prepare(<<'END')
110  INSERT OR IGNORE INTO commods
111      (unitmass,
112       unitvolume,
113       commodname)
114      VALUES (?,?,?);
115 END
116     ;
117     my $update= $dbh->prepare(<<'END')
118  UPDATE commods
119      SET unitmass = ?,
120          unitvolume = ?
121      WHERE commodname = ?
122 END
123     ;
124     foreach my $commod (sort keys %commods) {
125         my $c= $commods{$commod};
126         die "no mass for $commod" unless defined $c->{Mass};
127         die "no colume for $commod" unless defined $c->{Volume};
128         my @qa= ($c->{Mass}, $c->{Volume}, $commod);
129         $insert->execute(@qa);
130         $update->execute(@qa);
131     }
132     $dbh->commit;
133 }
134
135 #---------- island list ----------
136
137 {
138     my $sth= $dbh->prepare(<<'END')
139  INSERT OR IGNORE INTO islands (islandname, archipelago) VALUES (?, ?);
140 END
141     ;
142     foreach my $archname (sort keys %$ocean) {
143         my $arch= $ocean->{$archname};
144         foreach my $islandname (sort keys %$arch) {
145             $sth->execute($islandname, $archname);
146         }
147     }
148     $dbh->commit;
149 }
150
151 #---------- routes ----------
152
153 {
154     foreach my $islandname (sort keys %{ $route_mysteries{$oceanname} }) {
155         warn "$route_mysteries{$oceanname}{$islandname} routes".
156             " for unknown island $islandname\n";
157     }
158
159     my $allroutes= $routes{$oceanname};
160
161     my @propqueue= ();
162
163     sub distance_set_propagate ($$$$) {
164         my ($lev, $start, $upto, $start2upto) = @_;
165         $allroutes->{$start}{$upto}= $start2upto;
166         push @propqueue, [ $lev, $start, $upto ];
167     }
168
169     sub distance_propagate_now {
170         my ($lev, $start, $upto) = @_;
171         my $startref= $allroutes->{$start};
172         my $start2upto= $startref->{$upto};
173         my $uptoref=  $allroutes->{$upto};
174
175         for my $next (keys %$uptoref) {
176             next if $next eq $upto;
177             my $unext= $uptoref->{$next};
178             next unless defined $unext;
179             distance_update("${lev}p", $start, $next, $start2upto + $unext);
180         }
181     }
182
183     sub distance_update ($$$$) {
184         my ($lev, $x, $y, $newdist) = @_;
185         distance_update_one("${lev}x",$x,$y,$newdist);
186         distance_update_one("${lev}y",$y,$x,$newdist);
187     }
188
189     sub distance_update_one ($$$$) {
190         my ($lev, $x, $y, $newdist) = @_;
191         my $xref= $allroutes->{$x};
192         my $currently= $xref->{$y};
193         return if defined($currently) and $currently <= $newdist;
194         distance_set_propagate("${lev}o",$x,$y,$newdist);
195     }
196
197     foreach my $xn (keys %$allroutes) {
198         my $routes= $allroutes->{$xn};
199         distance_set_propagate('0', $xn, $xn, 0);
200         foreach my $yn (keys %$routes) {
201             distance_set_propagate('0', $yn, $yn, 0);
202             distance_set_propagate('X', $xn, $yn, $routes->{$yn});
203             distance_set_propagate('Y', $yn, $xn, $routes->{$yn});
204         }
205     }
206     my $ref;
207     while ($ref= shift @propqueue) {
208         distance_propagate_now(@$ref);
209     }
210
211     db_doall(<<END)
212  DELETE FROM dists;
213 END
214     ;
215     my $sth= $dbh->prepare(<<'END')
216  INSERT INTO dists VALUES
217         ((SELECT islandid FROM islands WHERE islandname == ?),
218          (SELECT islandid FROM islands WHERE islandname == ?),
219          ?);
220 END
221     ;
222     foreach my $xn (keys %$allroutes) {
223         my $routes= $allroutes->{$xn};
224         foreach my $yn (keys %$routes) {
225             $sth->execute($xn, $yn, $routes->{$yn});
226         }
227     }
228     $dbh->commit();
229
230     # select ia.islandname, ib.islandname,dists.dist from dists, islands as ia on dists.aiid = ia.islandid, islands as ib on dists.biid = ib.islandid order by ia.islandname, ib.islandname;
231 }
232
233 __DATA__