chiark / gitweb /
break out yppedia_chart_parse into CommodsScrape.pm; fix up bad call to db_check_refe... 6.2
authorIan Jackson <ian@liberator.(none)>
Wed, 9 Dec 2009 18:38:10 +0000 (18:38 +0000)
committerIan Jackson <ian@liberator.relativity.greenend.org.uk>
Thu, 10 Dec 2009 00:35:06 +0000 (00:35 +0000)
yarrg/CommodsScrape.pm [new file with mode: 0644]
yarrg/yppedia-chart-parser
yarrg/yppedia-ocean-scraper

diff --git a/yarrg/CommodsScrape.pm b/yarrg/CommodsScrape.pm
new file mode 100644 (file)
index 0000000..3e6f1c6
--- /dev/null
@@ -0,0 +1,104 @@
+# This is part of ypp-sc-tools, a set of third-party tools for assisting
+# players of Yohoho Puzzle Pirates.
+#
+# Copyright (C) 2009 Ian Jackson <ijackson@chiark.greenend.org.uk>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Yohoho and Puzzle Pirates are probably trademarks of Three Rings and
+# are used without permission.  This program is not endorsed or
+# sponsored by Three Rings.
+
+package CommodsScrape;
+
+use strict qw(vars);
+use warnings;
+
+use DBI;
+use POSIX;
+
+use Commods;
+
+BEGIN {
+    use Exporter ();
+    our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS);
+    $VERSION     = 1.00;
+    @ISA         = qw(Exporter);
+    @EXPORT      = qw(yppedia_chart_parse);
+    %EXPORT_TAGS = ( );
+
+    @EXPORT_OK   = qw();
+}
+
+sub yppedia_chart_parse ($$ $$$$ $) {
+    my ($fh, $debugfh,
+       $conv_nxy, $on_archlabel, $on_island, $on_league,
+       $on_incomprehensible) = @_;
+
+    my ($x,$y, $arch,$island,$solid,$dirn);
+    my $nn= sub { return $conv_nxy->($x,$y) };
+    
+    # We don't even bother with tag soup; instead we do line-oriented parsing.
+    while (<$fh>) {
+       s/\<--.*--\>//g;
+       s/^\s*//; chomp; s/\s+$//; s/\s+/ /g;
+       s/\<\/?(?:b|em)\>//g;
+       s/\{\{chart\ style\|[^{}]*\}\}//gi;
+       next unless m/\{\{/; # only interested in chart template stuff
+
+       if (($x,$y,$arch) =
+           m/^\{\{ chart\ label \|(\d+)\|(\d+)\| .*
+                   (?: \<(?: big|center )\>)* \'+
+                   (?: \[\[ | \{\{ )
+                   [^][\']* \| ([^][\'|]+)\ archipelago
+                   (?: \]\] | \}\} )
+                   \'+ (?: \<\/(?: big|center )\>)* \}\}$/xi) {
+           printf $debugfh "%2d,%-2d arch %s\n", $x,$y,$arch;
+           $on_archlabel->($x,$y,$arch);
+       } elsif (m/^\{\{ chart\ label \|\d+\|\d+\|
+                \<big\> \'+ \[\[ .* \b ocean \]\]/xi) {
+       } elsif (($x,$y,$island) =
+           m/^\{\{ chart\ island\ icon \|(\d+)\|(\d+)\|
+                   ([^| ][^|]*[^| ]) \| .*\}\}$/xi) {
+           my $n= $nn->();
+           printf $debugfh "%2d,%-2d island %s\n", $x,$y,$island;
+           $on_island->($n, $island);
+       } elsif (($solid,$x,$y,$dirn) =
+           m/^\{\{ chart\ league((?:\ solid)?) \|(\d+)\|(\d+)\|
+                   ([-\/\\o]) \| .*\}\}$/xi) {
+           next if $dirn eq 'o';
+
+           printf $debugfh "%2d,%-2d league %-6s %s\n", $x,$y,
+               $solid?'solid':'dotted', $dirn;
+
+           my ($bx,$by) = ($x,$y);
+           if ($dirn eq '-') { $bx+=2; }
+           elsif ($dirn eq '\\') { $bx++; $by++; }
+           elsif ($dirn eq '/') { $x++; $by++; }
+           else { die; }
+
+           my $na= $nn->();
+           my $nb= $conv_nxy->($bx,$by);
+           $on_league->($na,$nb,$solid);
+       } elsif (
+           m/^\{\{ chart\ head \}\}$/xi
+                ) {
+           next;
+       } else {
+           $on_incomprehensible->($.,$_);
+       }
+    }
+}
+
+1;
index e6e22b5..414f182 100755 (executable)
@@ -35,6 +35,7 @@ use warnings;
 use Graph::Undirected;
 use Commods;
 use CommodsDatabase;
+use CommodsScrape;
 
 my $widists= Graph::Undirected->new();
 my $wiarchs= Graph::Undirected->new();
@@ -51,13 +52,15 @@ my %wtisland2arch;
 my $dbdists;
 my %dbisland2arch;
 
+my $debugfh;
+
 my @msgkinds= qw(change warning error);
 my %msgs;
 my %msgprinted;
 my %msgkindprinted;
 sub pmsg ($$) {
     my $m= "$_[0]: $_[1]\n";
-    print DEBUG "D $m";
+    print $debugfh "D $m";
     push @{ $msgs{$_[0]} }, $m;
 }
 sub warning ($) { pmsg("warning",$_[0]); }
@@ -79,15 +82,15 @@ sub progress ($) { print "($_[0])\n"; }
 
 my $stdin_chart=0;
 
-open DEBUG, ">/dev/null" or die $!;
+$debugfh= new IO::File ">/dev/null" or die $!;
 
 while (@ARGV) {
     last unless $ARGV[0] =~ m/^-/;
     $_= shift @ARGV;
     last if m/^--$/;
     if ($_ eq '--debug') {
-       open DEBUG, ">&STDOUT" or die $!;
-       select(DEBUG); $|=1; select(STDOUT);
+       $debugfh= new IO::File ">&STDOUT" or die $!;
+       select($debugfh); $|=1; select(STDOUT);
     } elsif ($_ eq '--stdin-chart') {
        $stdin_chart=1;
     } else {
@@ -111,65 +114,31 @@ sub nn_xy ($$) {
     return $n;
 }
 
-sub yppedia_chart_parse () {
-    # We don't even bother with tag soup; instead we do line-oriented parsing.
-
-    while (<OCEAN>) {
-       s/\<--.*--\>//g;
-       s/^\s*//; chomp; s/\s+$//; s/\s+/ /g;
-       s/\<\/?(?:b|em)\>//g;
-       s/\{\{chart\ style\|[^{}]*\}\}//gi;
-       next unless m/\{\{/; # only interested in chart template stuff
-
-       my ($x,$y, $arch,$island,$solid,$dirn);
-       my $nn= sub { return nn_xy($x,$y) };
-    
-       if (($x,$y,$arch) =
-           m/^\{\{ chart\ label \|(\d+)\|(\d+)\| .*
-                   (?: \<(?: big|center )\>)* \'+
-                   (?: \[\[ | \{\{ )
-                   [^][\']* \| ([^][\'|]+)\ archipelago
-                   (?: \]\] | \}\} )
-                   \'+ (?: \<\/(?: big|center )\>)* \}\}$/xi) {
-           printf DEBUG "%2d,%-2d arch %s\n", $x,$y,$arch;
-           push @wiarchlabels, [ $x,$y,$arch ];
-       } elsif (m/^\{\{ chart\ label \|\d+\|\d+\|
-                \<big\> \'+ \[\[ .* \b ocean \]\]/xi) {
-       } elsif (($x,$y,$island) =
-           m/^\{\{ chart\ island\ icon \|(\d+)\|(\d+)\|
-                   ([^| ][^|]*[^| ]) \| .*\}\}$/xi) {
-           my $n= $nn->();
-           $wiisland2node{$island}= $n;
-           $winode2island{$n}= $island;
-           $widists->add_vertex($n);
-           $wiarchs->add_vertex($n);
-           printf DEBUG "%2d,%-2d island %s\n", $x,$y,$island;
-       } elsif (($solid,$x,$y,$dirn) =
-           m/^\{\{ chart\ league((?:\ solid)?) \|(\d+)\|(\d+)\|
-                   ([-\/\\o]) \| .*\}\}$/xi) {
-           next if $dirn eq 'o';
-
-           my ($bx,$by) = ($x,$y);
-           if ($dirn eq '-') { $bx+=2; }
-           elsif ($dirn eq '\\') { $bx++; $by++; }
-           elsif ($dirn eq '/') { $x++; $by++; }
-           else { die; }
-
-           my $nb= nn_xy($bx,$by);
-           $widists->add_weighted_edge($nn->(), $nb, 1);
-           $wiarchs->add_edge($nn->(), $nb) if $solid;
-           $wiarchs->add_edge($nn->(), $nb) if $solid;
-
-           printf DEBUG "%2d,%-2d league %-6s %s %s\n", $x,$y,
-               $solid?'solid':'dotted', $dirn, $nb;
-       } elsif (
-           m/^\{\{ chart\ head \}\}$/xi
-                ) {
-           next;
-       } else {
-           warning("line $.: ignoring incomprehensible: $_");
-       }
-    }
+sub run_yppedia_chart_parse ($) {
+    my ($oceanfh) = @_;
+    yppedia_chart_parse($oceanfh, $debugfh,
+                       \&nn_xy,
+                       sub {
+                            my ($x,$y,$arch) = @_;
+                           push @wiarchlabels, [ $x,$y,$arch ];
+                       },
+                       sub {
+                           my ($n, $island) = @_;
+                           $wiisland2node{$island}= $n;
+                           $winode2island{$n}= $island;
+                           $widists->add_vertex($n);
+                           $wiarchs->add_vertex($n);
+                       },
+                       sub {
+                           my ($na, $nb, $solid) = @_;
+                           $widists->add_weighted_edge($na, $nb, 1);
+                           $wiarchs->add_edge($na, $nb) if $solid;
+                           $wiarchs->add_edge($na, $nb) if $solid;
+                       },
+                       sub {
+                           my ($lno,$l) = @_;
+                           warning("line $l: ignoring incomprehensible: $l");
+                       });
 }
 
 sub yppedia_graphs_add_shortcuts () {
@@ -182,7 +151,7 @@ sub yppedia_graphs_add_shortcuts () {
            my $q= sprintf "%d,%d", $ax+$_[0], $ay+$_[1];
            return unless $widists->has_vertex($q);
            return if $widists->has_edge($p,$q);
-           printf DEBUG "%-5s league-shortcut %-5s\n", $p, $q;
+           printf $debugfh "%-5s league-shortcut %-5s\n", $p, $q;
            $widists->add_weighted_edge($p,$q,1);
        };
        $add_shortcut->( 2,0);
@@ -201,7 +170,7 @@ sub yppedia_graphs_prune_boring () {
        map { $weight += $widists->get_edge_weight($delete, $_) } @neigh;
        $widists->add_weighted_edge(@neigh, $weight);
        $widists->delete_vertex($delete);
-       printf DEBUG "%-5s elide %5s %-5s %2d\n", $delete, @neigh, $weight;
+       printf $debugfh "%-5s elide %5s %-5s %2d\n", $delete, @neigh, $weight;
     }
 }
 
@@ -232,7 +201,7 @@ sub yppedia_archs_sourceinfo () {
            error("island in $arch in source-info".
                  " connected to $oldarch as well: $islename")
                if defined $oldarch && $oldarch ne $arch;
-           printf DEBUG "%-5s force-island-arch cc%-2d %-10s %s\n",
+           printf $debugfh "%-5s force-island-arch cc%-2d %-10s %s\n",
                $islenode, $ccix, $arch, $islename;
            $wiccix2arch{$ccix}= $arch;
        }
@@ -246,7 +215,7 @@ sub yppedia_archs_chart_labels () {
        my ($ax,$ay,$arch) = @$label;
        my $best_d2= 9999999;
        my $best_n;
-#      print DEBUG "$ax,$ay arch-island-search $arch\n";
+#      print $debugfh "$ax,$ay arch-island-search $arch\n";
        $ay += 1;  $ax += 2;  # coords are rather to the top left of label
        foreach my $vertex ($wiarchs->vertices()) {
            next unless exists $winode2island{$vertex};
@@ -255,7 +224,7 @@ sub yppedia_archs_chart_labels () {
            my ($vx,$vy) = split /,/, $vertex;
            my $d2= ($vx-$ax)*($vx-$ax) + ($vy-$ay)*($vy-$ay);
            my $cmp= $best_d2 <=> $d2;
-           printf DEBUG "%2d,%-2d arch-island-search %5s d2=%4d cc%-2d".
+           printf $debugfh "%2d,%-2d arch-island-search %5s d2=%4d cc%-2d".
                         " #cc=%2d cmp=%2d %s\n",
                $ax,$ay, $vertex, $d2, $ccix, scalar(@cc), $cmp,
                $winode2island{$vertex};
@@ -265,7 +234,7 @@ sub yppedia_archs_chart_labels () {
        }
        die 'no island vertices?!' unless defined $best_n;
        my $ccix= $wiarchs->connected_component_by_vertex($best_n);
-       printf DEBUG
+       printf $debugfh
            "%2d,%-2d arch-island-select %-5s d2=%4d cc%-2d     %-10s %s\n",
            $ax,$ay, $best_n, $ccix, $best_d2, $arch, $winode2island{$best_n};
        my $desc= join "\n", map {
@@ -311,7 +280,7 @@ sub yppedia_archs_fillbynearest() {
        next unless @islandnodes; # don't care, then
 
        foreach my $islandnode (@islandnodes) {
-           printf DEBUG "%-5s arch-join-need cc%-2d             %s\n",
+           printf $debugfh "%-5s arch-join-need cc%-2d             %s\n",
                $islandnode, $sourceccix, $winode2island{$islandnode};
        }
        my $best_dist= 9999999;
@@ -337,7 +306,7 @@ sub yppedia_archs_fillbynearest() {
 
        my $arch= $wiccix2arch{$best_targetccix};
        my $best_island= $winode2island{$best_target};
-       printf DEBUG "%-5s arch-join-to %-5s dist=%2d cc%-2d  %-10s %s\n",
+       printf $debugfh "%-5s arch-join-to %-5s dist=%2d cc%-2d  %-10s %s\n",
            $best_source, $best_target, $best_dist,
            $best_targetccix, $arch,
            defined($best_island) ? $best_island : "-";
@@ -359,7 +328,7 @@ sub widist ($$) {
 #    die "$p $q" unless defined $pl;
 #    my @pv= $wialldists->path_vertices($p,$q);
 #    if (@pv == $pl) { return $pl; }
-#   printf DEBUG "%-5s PATHLENGTH %-5s pl=%s pv=%s\n", $p,$q,$pl,join('|',@pv);
+#   printf $debugfh "%-5s PATHLENGTH %-5s pl=%s pv=%s\n", $p,$q,$pl,join('|',@pv);
     return $pl;
 }
                        
@@ -496,14 +465,14 @@ sub shortest_path_reduction ($$) {
 
 END
     
-    printf DEBUG "spr %s before %d\n", $what, scalar($g->edges());
+    printf $debugfh "spr %s before %d\n", $what, scalar($g->edges());
 
     my $result= Graph::Undirected->new();
     foreach my $edge_ac ($g->edges()) {
         $result->add_vertex($edge_ac->[0]); # just in case
         next if $edge_ac->[0] eq $edge_ac->[1];
        my $edgename_ac= join ' .. ', @$edge_ac;
-       printf DEBUG "spr %s edge %s\n", $what, $edgename_ac;
+       printf $debugfh "spr %s edge %s\n", $what, $edgename_ac;
        my $w_ac= $g->get_edge_weight(@$edge_ac);
        my $needed= 1;
        foreach my $vertex_b ($g->vertices()) {
@@ -515,17 +484,17 @@ END
            next unless defined $w_ac;
            next if $w_ab + $w_bc > $w_ac;
            # found path
-           printf DEBUG "spr %s edge %s unnecessary %s\n",
+           printf $debugfh "spr %s edge %s unnecessary %s\n",
                $what, $edgename_ac, $vertex_b;
            $needed= 0;
            last;
        }
        if ($needed) {
-           printf DEBUG "spr %s edge %s essential\n", $what, $edgename_ac;
+           printf $debugfh "spr %s edge %s essential\n", $what, $edgename_ac;
            $result->add_weighted_edge(@$edge_ac,$w_ac);
        }
     }
-    printf DEBUG "spr %s result %d\n", $what, scalar($result->edges());
+    printf $debugfh "spr %s result %d\n", $what, scalar($result->edges());
 
     my $apsp= $result->APSP_Floyd_Warshall();
     foreach my $ia (sort $g->vertices()) {
@@ -567,11 +536,10 @@ sub yppedia_ocean_fetch_done () {
 
 sub yppedia_ocean_fetch_chart () {
     if ($stdin_chart) {
-       open OCEAN, "<& STDIN" or die $!;
-       yppedia_chart_parse();
+       run_yppedia_chart_parse('STDIN');
     } else {
        yppedia_ocean_fetch_start(1);
-       yppedia_chart_parse();
+       run_yppedia_chart_parse('OCEAN');
        yppedia_ocean_fetch_done();
     }
 }
@@ -628,7 +596,7 @@ sub database_fetch_ocean () {
     undef %dbisland2arch;
     $dbdists= Graph::Undirected->new();
     while ($row= $sth->fetchrow_hashref) {
-       print DEBUG "database-island $row->{'islandname'}".
+       print $debugfh "database-island $row->{'islandname'}".
                     " $row->{'archipelago'}\n";
        $dbisland2arch{$row->{'islandname'}}= $row->{'archipelago'};
     }
@@ -772,7 +740,7 @@ for (;;) {
            print STDERR "*** --stdin-chart, aborting!\n";
            exit 1;
        }
-       progress("checking database");        db_check_referential_integrity();
+       progress("checking database");      db_check_referential_integrity(1);
        progress("committing database");       $dbh->commit();
        progress("committing _ocean-*.txt");   localtopo_commit();
        exit 0;
index d55f7ac..ba145ea 100755 (executable)
@@ -88,14 +88,16 @@ def fetch():
                url_base = 'index.php?title=Template:Map:%s_Ocean&action=edit'
        else:
                url_base = '%s_Ocean'
-       url = ('http://yppedia.puzzlepirates.com/' +
-                       (url_base % urllib.quote(ocean,'')))
-       debug('fetching',url)
-       dataf = urllib.urlopen(url)
-       debug('fetched',dataf)
+       url_base = url_base % urllib.quote(ocean,'')
+       if opts.localhtml is None:
+               url = ('http://yppedia.puzzlepirates.com/' + url_base)
+               debug('fetching',url)
+               dataf = urllib.urlopen(url)
+               debug('fetched',dataf)
+       else:
+               dataf = file(opts.localhtml + '/' + url_base, 'r')
        soup = BeautifulSoup(dataf)
 
-
 title_arch_re = regexp.compile('(\\S.*\\S) Archipelago \\((\\S+)\\)$')
 title_any_re = regexp.compile('(\\S.*\\S) \((\\S+)\\)$')
 href_img_re = regexp.compile('\\.png$')
@@ -189,6 +191,9 @@ def main():
                help='print chart source rather than arch/island info')
        ao('--debug', action='count', dest='debug', default=0,
                help='enable debugging output')
+       ao('--local-html-dir', action='store', dest='localhtml',
+               help='get yppedia pages from local directory LOCALHTML'+
+                       ' instead of via HTTP')
 
        (opts,args) = pa.parse_args()
        if len(args) != 1: