chiark / gitweb /
Merge branch 'origin'
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Tue, 30 Jun 2009 17:19:08 +0000 (18:19 +0100)
committerIan Jackson <Ian.Jackson@eu.citrix.com>
Tue, 30 Jun 2009 17:19:08 +0000 (18:19 +0100)
Conflicts:
pctb/TODO

13 files changed:
pctb/README
pctb/TODO
pctb/commod-results-processor
pctb/common.h
pctb/convert.c
pctb/convert.h
pctb/dictionary-manager
pctb/dictionary-pixmap-options
pctb/pages.c
pctb/rgbimage.c
pctb/structure.c
pctb/structure.h
pctb/x.gdb

index 9bb9867e917eba91c99a0c920459c5538ec62788..e2452ddec32dd8a85a93f04a0390588c2e301ebf 100644 (file)
@@ -12,6 +12,8 @@ To run it, change to this directory, type `make', and then:
 While it is capturing the screenshots, do not move the mouse or use
 the keyboard.  Keyboard focus must stay in the YPP client window.
 
+You will probably need to turn off `Use antialiased font' in the YPP
+client.  This is in the Ye panel, Options, tab `General'.
 
 Command-line options
 --------------------
index 8088a10b854f8e9a96ceeaac9cf3c84cdfa20cc1..6a603c61c61989ea6b94a3042f3bc785a14fffdb 100644 (file)
--- a/pctb/TODO
+++ b/pctb/TODO
@@ -1,8 +1,6 @@
 add UI option to dictionary-manager to make user specify which dictionary
   to add multi-context entries to
 install/test dictionary upload/approval
-onboard ship island name horizontal trim
 write real uploader
 test real uploader
-building island name extractor
-speed it up
+further speedups
index 32763293ac705f6128cd88a7312000ce296501ae..36473186a80f242a7a0fcece99f7d8db6c2ba72a 100755 (executable)
@@ -218,7 +218,7 @@ sub main__tsv () {
 
 
 our (%commodmap);
-our ($pctb) = $ENV{'YPPSC_PCTB_PCTB'};  die unless $pctb;
+our ($pctb) = $ENV{'YPPSC_PCTB_PCTB'};
 
 our ($ua)= LWP::UserAgent->new;
 
@@ -235,6 +235,7 @@ sub load_commodmap() {
 }
 
 sub refresh_commodmap() {
+    die unless $pctb;
     my $resp= $ua->get("$pctb/commodmap.php?version=2");
     die $resp->status_line unless $resp->is_success;
 
@@ -331,6 +332,16 @@ sub bs_gen_md ($$) {
 
 sub writeint { return pack 'v*', @_; }
 
+our (%stalltypetoabbrevmap)= qw(
+                               Apothecary    A
+                               Distilling    D
+                               Furnishing    F
+                               Ironworking   I
+                               Shipbuilding  S
+                               Tailoring     T
+                               Weaving       W
+                               );
+
 sub genmarketdata () {
     our $version= '005b';
 
@@ -355,7 +366,18 @@ sub genmarketdata () {
     my $ot= sprintf("$version\n".
                    "%d\n",
                    scalar(@stallmap));
-    foreach $stall (@stallmap) { $ot .= "$stall\n"; }
+    foreach $stall (@stallmap) {
+       my $st= $stall;
+       if ($st =~ m/^(\S+)\'s (\S+) Stall$/) {
+           my $stkind= $stalltypetoabbrevmap{$2};
+           if (defined $stkind) {
+               $st= "$1^$stkind";
+           } else {
+               warn "unknown stall type $2 in $st\n";
+           }
+       }
+       $ot .= "$st\n";
+    }
     return $ot.$ob;
 }
 
@@ -365,9 +387,9 @@ sub main__genmarketdata () {
 }
 
 sub main__upload () {
+    die unless $pctb;
     my $o= genmarketdata();
     my $url= "$pctb/upload.php";
-    $url= "http://www.chiark.greenend.org.uk/ucgi/~ijackson/check/upload.php";
     my $content= {
        'marketdata' => [ undef, "marketdata.gz",
                          Content_Type => 'application/gzip',
@@ -378,7 +400,33 @@ sub main__upload () {
                        Content_Type => 'form-data');
     die $resp->status_line unless $resp->is_success;
 
-    print "[[ ",$resp->content," ]]\n";
+    my $resptxt= $resp->content();
+
+    my @filenames= $resptxt =~
+ m/input\s+type="hidden"\s+name="filename"\s+value=\"([_.0-9a-z]+)\"/i;
+    @filenames or die "$resptxt ?";
+
+    my @forcerls= $resptxt =~
+ m/input\s+type="hidden"\s+name="forcereload"\s+value=\"([1-9]\d+)\"/i;
+    @forcerls or die "$resptxt ?";
+
+    my $filename= $filenames[0];
+    my $forcerl= $forcerls[0];
+
+    die "$resptxt | @filenames ?" if grep { $_ ne $filename } @filenames;
+    die "$resptxt | @forcerls ?" if grep { $_ ne $forcerl } @forcerls;
+
+#    my $setsland= {
+#      'action' => 'setisland'
+#      'filename' => $filename,
+#      'forcereload' => $forcerl,
+#    my $url_setisland= "$url
+#
+#http://pctb.ilk.org/upload.php?topisland=560&ocean=2&island=48&action=setisland&forcereload=1244748679&filename=PFayDW' >v.html 
+#    
+    print ">$filename|$forcerl<\n";
+
+    system 'printenv|grep YPP|sort';
 }
 
 
index 3fa8a81d985621ad15277a461b7a5fb313b10398..48483e238b58d82e9ede0eaedf89600301804f46 100644 (file)
@@ -74,6 +74,7 @@ typedef struct { /* both inclusive */
    DF(struct)                                  \
    DF(ocr)                                     \
    DF(rsync)                                   \
+   DF(structcolon)                             \
    DF(callout)
 
 enum {
index 433b043a3dadd5a043f7f9087733c21262e12160..3ef5018fb1d3ca4167d2260113b68c993770447b 100644 (file)
@@ -226,8 +226,14 @@ int main(int argc, char **argv) {
   /* Consequential changes to options */
 
   if (o_mode & mf_analyse) {
-    if (!o_outmode_kind)
-      o_outmode_kind= (o_flags & ff_printisland) ? omk_none : omk_str;
+    if (!o_outmode_kind) {
+      if (o_flags & ff_printisland) {
+       o_outmode_kind= omk_none;
+       o_flags |= ff_singlepage;
+      } else {
+       o_outmode_kind= omk_upload;
+      }
+    }
 
     if (o_outmode_kind==omk_upload) {
       o_flags |= ffs_upload;
@@ -264,12 +270,12 @@ int main(int argc, char **argv) {
   if (!ocean)  ocean=  o_ocean;
   if (!pirate) pirate= o_pirate;
   
-  if (o_flags & ff_needisland) {
+  if (o_flags & ff_needisland)
     if (!ocean)
       badusage("need --ocean option when replaying images"
               " (consider supplying --pirate too)");
+  if (ocean)
     sysassert(! setenv("YPPSC_OCEAN",ocean,1) );
-  }
   if (pirate && (o_flags & ff_dict_pirate))
     sysassert(! setenv("YPPSC_PIRATE",pirate,1) );
 
@@ -277,6 +283,7 @@ int main(int argc, char **argv) {
     open_screenshot_file("w");
     if (o_flags & ff_singlepage) take_one_screenshot();
     else take_screenshots();
+    progress_log("OK for you to move the mouse now.");
   }
   if (o_mode & mf_readscreenshot) {
     open_screenshot_file("r");
@@ -285,9 +292,10 @@ int main(int argc, char **argv) {
   }
   if (o_mode & mf_analyse) {
     if (o_flags & ff_needisland) {
-      find_islandname();
+      find_islandname(page0_rgbimage);
       if (o_flags & ff_printisland)
        printf("%s, %s\n", archipelago, island);
+      sysassert(! setenv("YPPSC_ISLAND",island,1) );
     }
     switch (o_outmode_kind) {
     case omk_upload: case omk_str:   run_analysis();        break;
index d38c38efab83362a3ec7cb22e30dcc8539565cfb..80979ec2e885829f8d15faccd887c9c63a6812b0 100644 (file)
@@ -54,14 +54,16 @@ typedef struct RgbImage {
 void identify_rgbimage(const RgbImage *base, Rect portion,
                       char result[MAXIMGIDENT], const char *what);
 RgbImage *alloc_rgb_image(int w, int h);
+void fwrite_ppmraw(FILE *f, const RgbImage *ri);
 
 #define RI_PIXEL(ri,x,y) ((ri)->data + ((y)*(ri)->w + (x)) * 3)
 
 /*----- from structure.c -----*/
 
 void find_structure(const CanonImage *im, int *max_relevant_y_r);
+Rect find_sunshine_widget(void);
 
-void find_islandname(void);
+void find_islandname(RgbImage *ri);
 void check_correct_commodities(void);
 void read_screenshots(void);
 void read_one_screenshot(void);
index 7284b374cc666852e7d4562372562f4ebe4c258d..374c4ef7a67b9595cc4edddc63eec02fdaeef8d7 100755 (executable)
@@ -274,6 +274,11 @@ proc required/char {} {
     startup_cursor
 }
 
+proc approve_showentry_xinfo/char {w def} {
+    set unic [string2unicodenames $def]
+    label $w -text $unic
+}
+
 #========== PIXMAPS ==========
 
 #---------- pixmap database read and write ----------
@@ -406,6 +411,10 @@ proc required/pixmap {} {
     }
 }
 
+proc approve_showentry_xinfo/pixmap {w def} {
+    label $w -image image/empty
+}
+
 #========== UPLOADS TO DICTIONARY SERVER ==========
 
 proc upload_init {} {
@@ -488,7 +497,7 @@ proc maybe_upload_entry {im def} {
 
     set query [eval ::http::formatQuery $pl]
     regsub -all {%0d} $query {} query
-    debug "DB-UPDATE QUERY [string range $query 0 200]..."
+    debug "DB-UPDATE QUERY $query"
 
     if {[regexp {^\.?/} $url]} {
        set cmd [list $url $query]
@@ -729,8 +738,8 @@ proc recursor/text {} {
     focus .d.csr.csr.e
     bind .d.csr.csr.e <Key-Return> {
        set strq [.d.csr.csr.e get]
-       if {[regexp -line {^(?:[!-[]|[]-~]|\\\\|\\x[0-9a-f]{2})+} $strq]} {
-           RETURN_RESULT DEFINE "$cur_0 $cur_1 $strq"
+       if {[string length $strq]} {
+           RETURN_RESULT DEFINE [list $cur_0 $cur_1 $strq]
        }
     }
     bind .d.csr.csr.e <Key-Escape> {
@@ -916,14 +925,7 @@ proc remote-serv/take {yesno file dict} {
 
     must_gets_exactly stdin confirmed
 
-    if {![string compare pixmap $dict]} {
-       set reqkind pixmap
-       debug "DICT PIXMAP"
-    } elseif {[regexp {^(char)([1-9]\d*)$} $dict dummy reqkind rows]} {
-       debug "DICT CHAR rqk=$reqkind r=$rows."
-    } else {
-       error "$dict ?"
-    }
+    manyset [dict2_reqkind_rows reqkind rows]
     
     if {$yesno} {
        read_database $dictdir/master-$dict.txt
@@ -984,6 +986,18 @@ proc regsub-data {exp subspec args} {
     }
 }
 
+proc dict2_reqkind_rows {dict} {
+    if {![string compare pixmap $dict]} {
+       return {pixmap {}}
+       debug "DICT PIXMAP"
+    } elseif {[regexp {^(char)([1-9]\d*)$} $dict dummy reqkind rows]} {
+       debug "DICT CHAR rqk=$reqkind r=$rows."
+       return [list $reqkind rows]
+    } else {
+       error "$dict ?"
+    }
+}
+
 proc chop_counted {var} {
     upvar 1 $var val
     global data
@@ -1018,8 +1032,18 @@ proc approve_compare {fd1 fd2} {
     return [string compare $sv1 $sv2]
 }
 
+proc string2unicodenames {str} {
+    return [exec perl -e {
+       use Unicode::CharName qw(uname);
+       $ARGV[0] =~ s/^ //;
+       foreach $_ (split //,$ARGV[0]) {
+           print uname(ord),"\n" or die $!
+       }
+    } " $str"]
+}
+
 proc approve_showentry {ix file specdata} {
-    global approve_ixes
+    global approve_ixes reqkind
     
     approve_decompose_data $specdata
 
@@ -1043,11 +1067,19 @@ proc approve_showentry {ix file specdata} {
     image create photo approve/$ix -data $ppm
     label $wb-image -image approve/$ix -bd 2 -relief sunken
 
+    manyset [dict2_reqkind_rows $dict] reqkind
+    approve_showentry_xinfo/$reqkind $wb-xinfo $def
+
+    if {$ix} {
+       label $wb-div -bd 1 -relief sunken -image image/empty
+       grid configure $wb-div -columnspan 5 -sticky ew -padx 5
+    }
+
     frame $wb-act
     button $wb-act.rej -text Reject -command [list approve_reject $ix]
     pack $wb-act.rej
 
-    grid $wb-def $wb-image $wb-act $wb-inf -padx 3
+    grid $wb-def $wb-image $wb-xinfo $wb-act $wb-inf -padx 3
     grid configure $wb-image -ipadx 3 -ipady 3 -sticky w
 
     lappend approve_ixes $ix
@@ -1143,6 +1175,8 @@ proc main/approve {} {
     pack .right -side right
     pack .ok -side bottom
 
+    image create bitmap image/empty
+
     set approve_page 0
     approve_fetch_list
 }
index 67ca72264d95414b881710e385ed435d2ed30b77..e83f685a7275d0ae103042dab646e9f2b09fb674 100755 (executable)
@@ -105,7 +105,7 @@ Land {On land} {
     Booty  Booty
     Ahoy!  Ahoy!
 }
-Ship {On board a ship} {
+Vessel {On board a ship} {
     Crew   Crew
     Vessel Vessel
     Ye     Ye
index 32e429ab39df1be1220b2bedbe083a1be7ccf17d..c5cc941b7a942c655d03b4709cbd54707d01c555 100644 (file)
@@ -243,6 +243,7 @@ static void snapshot(Snapshot **output) {
 
   double begin= timestamp();
   if (shmim) {
+    rtimestamp(&begin, "XShmGetImage before");
     xassert( XShmGetImage(disp,id,shmim, 0,0, AllPlanes) );
     rtimestamp(&begin, "XShmGetImage");
 
@@ -253,6 +254,7 @@ static void snapshot(Snapshot **output) {
     memcpy(im_free->data, shmim->data, dsz);
     rtimestamp(&begin, "mmalloc/memcpy");
   } else {
+    rtimestamp(&begin, "XGetImage before");
     xassert( im_use= im_free=
             XGetImage(disp,id, 0,0, wwidth,wheight, AllPlanes, ZPixmap) );
     rtimestamp(&begin, "XGetImage");
@@ -299,7 +301,7 @@ static int identical(const Snapshot *a, const Snapshot *b) {
     return 0;
 
   int compare_to= a->h;
-  if (max_relevant_y && compare_to > max_relevant_y)
+  if (max_relevant_y>=0 && compare_to > max_relevant_y)
     compare_to= max_relevant_y;
   
   return !memcmp(a->data, b->data, a->w * 3 * compare_to);
@@ -319,46 +321,57 @@ static void wait_for_stability(Snapshot **output,
   va_start(al,fmt);
 
   Snapshot *last=0;
+  int nidentical=0;
   /* waits longer if we're going to return an image identical to previously
    * if previously==0, all images are considered identical to it */
 
-  debugf("PAGING  wait_for_stability"
-         "  last_input=%f previously=%p\n",
-         last_input, previously);
-
   char *doing;
-  sysassert( vasprintf(&doing,fmt,al) >=0);
+  sysassert( vasprintf(&doing,fmt,al) >=0 );
 
-  progress("%s",doing);
+  debugf("PAGING  wait_for_stability"
+         "  last_input=%f previously=%p `%s'\n",
+         last_input, previously, doing);
 
+  double min_interval= 25000; /*us*/
   for (;;) {
-    double at_snapshot= timestamp();
-    double need_sleep= min_update_allowance - (at_snapshot - last_input);
-    if (need_sleep > 0) { delay(need_sleep); continue; }
+    progress_spinner("%s",doing);
+    
+    double since_last_input= timestamp() - last_input;
+    double this_interval= min_interval - since_last_input;
 
-    snapshot(output);
+    if (this_interval >= 0)
+      usleep(this_interval);
 
-    if (!with_keypress &&
-       !(previously && identical(*output,previously))) {
-      debugf("PAGING  wait_for_stability  simple\n");
-      break;
-    }
+    snapshot(output);
 
-    if (last && identical(*output,last)) {
-      debugf("PAGING  wait_for_stability  stabilised\n");
-      break;
+    if (!last) {
+      debugf("PAGING  wait_for_stability first...\n");
+      last=*output; *output=0;
+    } else if (!identical(*output,last)) {
+      debugf("PAGING  wait_for_stability changed...\n");
+      free(last); last=*output; *output=0;
+      nidentical=0;
+      if (!with_keypress) {
+       min_interval *= 3.0;
+       min_interval += 0.5;
+      }
+    } else {
+      nidentical++;
+      int threshold=
+       !previously ? 3 :
+       identical(*output,previously) ? 5
+       : 1;
+      debugf("PAGING  wait_for_stability nidentical=%d threshold=%d\n",
+             nidentical, threshold);
+      if (nidentical >= threshold)
+       break;
+
+      min_interval += 0.5;
+      min_interval *= 2.0;
     }
-    
-    progress_spinner("%s",doing);
-
-    debugf("PAGING  wait_for_stability  retry\n");
-
-    free_snapshot(&last); last=*output; *output=0;
 
     if (with_keypress)
       with_keypress();
-
-    delay(0.5);
   }
 
   free_snapshot(&last);
@@ -402,8 +415,10 @@ static void raise_and_get_details(void) {
 
   check_client_window_all_on_screen();
 
-  int shm= XShmQueryExtension(disp);
-    shm=0;
+  Bool shmpixmaps=0;
+  int major=0,minor=0;
+  int shm= XShmQueryVersion(disp, &major,&minor,&shmpixmaps);
+  debugf("PAGING shm=%d %d.%d pixmaps=%d\n",shm,major,minor,shmpixmaps);
   if (shm) {
     xassert( shmim= XShmCreateImage(disp, attr.visual, attr.depth, ZPixmap,
                                    0,&shminfo, wwidth,wheight) );
@@ -482,24 +497,18 @@ static void set_focus_commodity(void) {
 static CanonImage *convert_page(Snapshot *sn, RgbImage *ri) {
   CanonImage *im;
 
-  fprintf(screenshot_file,
-         "P6\n"
-         "%d %d\n"
-         "255\n", sn->w, sn->h);
+  fwrite_ppmraw(screenshot_file, sn);
+  if (ri) memcpy(ri->data, sn->data, ri->h * ri->w * 3);
 
+  unsigned char *pixel= sn->data;
   CANONICALISE_IMAGE(im, sn->w, sn->h, {
-    int i;
-    rgb= 0;
-    for (i=0; i<3; i++) {
-      rgb <<= 8;
-      unsigned long sample= RI_PIXEL(sn,x,y)[i];
-      rgb |= sample;
-      fputc(sample, screenshot_file);
-    }
-    if (ri)
-      CANONIMG_ALSO_STORERGB(ri);
+    rgb=
+      (pixel[0] << 16) |
+      (pixel[1] <<  8) |
+      (pixel[2]      );
+    pixel += 3;
   });
-
+    
   sysassert(!ferror(screenshot_file));
   sysassert(!fflush(screenshot_file));
 
@@ -514,28 +523,18 @@ static void prepare_ypp_client(void) {
   raise_and_get_details();
   wait_for_stability(&current,0,0, "checking current YPP client screen...");
 
-#if 1
-timestamp();
-snapshot(&current);
-snapshot(&current);
-snapshot(&current);
-snapshot(&current);
-snapshot(&current);
-snapshot(&current);
-snapshot(&current);
-snapshot(&current);
-snapshot(&current);
-snapshot(&current);
-timestamp();
-#endif
-
   test= convert_page(current, 0);
   find_structure(test, &max_relevant_y);
   check_correct_commodities();
+  Rect sunshine= find_sunshine_widget();
+
+  progress("poking client...");
+  mouse_1_updown((sunshine.tl.x   + sunshine.br.x) / 2,
+                (sunshine.tl.y*9 + sunshine.br.y) / 10);
+
   free(test);
-  free_snapshot(&current);
 
-  progress("requesting status information...");
+  wait_for_stability(&current,0,0, "checking basic YPP client screen...");
   mouse_1_updown(250, wheight-10);
   mouse_1_updown_here();
   mouse_1_updown_here();
@@ -545,6 +544,11 @@ timestamp();
   send_key(XK_w);
   send_key(XK_Return);
   sync_after_input();
+
+  Snapshot *status=0;
+  wait_for_stability(&status,current,0, "awaiting status information...");
+  free_snapshot(&current);
+  free_snapshot(&status);
 }
 
 void take_screenshots(void) {
@@ -596,7 +600,7 @@ void take_one_screenshot(void) {
   prepare_ypp_client();
   wait_for_stability(&current,0,0, "taking screenshot...");
   page0_rgbimage= alloc_rgb_image(current->w, current->h);
-  page_images[0]= convert_page(current, 0);
+  page_images[0]= convert_page(current, page0_rgbimage);
   npages= 1;
   progress_log("collected single screenshot.");
 }
@@ -607,115 +611,120 @@ void set_yppclient_window(unsigned long wul) {
 
 DEBUG_DEFINE_SOME_DEBUGF(findypp,debugfind)
 
+static int nfound;
+static Atom wm_name;
+static int screen;
+
+static void findypp_recurse(int depth, int targetdepth, Window w) {
+  unsigned int nchildren;
+  int i;
+  Window *children=0;
+  Window gotroot, gotparent;
+
+  static const char prefix[]= "Puzzle Pirates - ";
+  static const char onthe[]= " on the ";
+  static const char suffix[]= " ocean";
+#define S(x) (sizeof((x))-1)
+
+  debugfind("FINDYPP %d/%d screen %d  %*s %lx",
+           depth,targetdepth,screen,
+           depth,"",(unsigned long)w);
+  
+  if (depth!=targetdepth) {
+    xassert( XQueryTree(disp,w,
+                       &gotroot,&gotparent,
+                       &children,&nchildren) );
+    debugfind(" nchildren=%d\n",nchildren);
+  
+    for (i=0; i<nchildren; i++) {
+      Window child= children[i];
+      findypp_recurse(depth+1, targetdepth, child);
+    }
+    XFree(children);
+    return;
+  }
+    
+
+  int gotfmt;
+  Atom gottype;
+  unsigned long len, gotbytesafter;
+  char *title;
+  unsigned char *gottitle=0;
+  xassert( !XGetWindowProperty(disp,w, wm_name,0,512, False,
+                              AnyPropertyType,&gottype, &gotfmt, &len,
+                              &gotbytesafter, &gottitle) );
+  title= (char*)gottitle;
+
+  if (DEBUGP(findypp)) {
+    debugfind(" gf=%d len=%lu gba=%lu \"", gotfmt,len,gotbytesafter);
+    char *p;
+    for (p=title; p < title+len; p++) {
+      char c= *p;
+      if (c>=' ' && c<=126) fputc(c,debug);
+      else fprintf(debug,"\\x%02x",c & 0xff);
+    }
+    fputs("\": ",debug);
+  }
+
+#define REQUIRE(pred)                                                  \
+  if (!(pred)) { debugfind(" failed test  %s\n", #pred); return; }     \
+  else
+
+  REQUIRE( gottype!=None );
+  REQUIRE( len );
+  REQUIRE( gotfmt==8 );
+
+  REQUIRE( len >= S(prefix) + 1 + S(onthe) + 1 + S(suffix) );
+
+  char *spc1= strchr(  title        + S(prefix), ' ');  REQUIRE(spc1);
+  char *spc2= strrchr((title + len) - S(suffix), ' ');  REQUIRE(spc2);
+
+  REQUIRE( (title + len) - spc1  >= S(onthe)  + S(suffix) );
+  REQUIRE(  spc2         - title >= S(prefix) + S(onthe) );
+
+  REQUIRE( !memcmp(title,                   prefix, S(prefix)) );
+  REQUIRE( !memcmp(title + len - S(suffix), suffix, S(suffix))  );
+  REQUIRE( !memcmp(spc1,                    onthe,  S(onthe))  );
+
+#define ASSIGN(what, start, end)                       \
+  what= masprintf("%.*s", (end)-(start), start);       \
+  if (o_##what) REQUIRE( !strcasecmp(o_##what, what) );        \
+  else
+
+  ASSIGN(ocean,  spc1 + S(onthe),   (title + len) - S(suffix));
+  ASSIGN(pirate, title + S(prefix),  spc1);
+
+  debugfind(" YES!\n");
+  id= w;
+  nfound++;
+  progress_log("found YPP client (0x%lx):"
+              " %s ocean - %s.",
+              (unsigned long)id, ocean, pirate);
+}
+
 void find_yppclient_window(void) {
-  Window root, gotroot, gotparent;
-  int screen;
-  int nfound=0;
+  int targetdepth;
+
+  nfound=0;
   
   if (id) return;
   
   progress("looking for YPP client window...");
 
-  static const char prefix[]= "Puzzle Pirates - ";
-  static const char onthe[]= " on the ";
-  static const char suffix[]= " ocean";
-#define S(x) (sizeof((x))-1)
+  xassert( (wm_name= XInternAtom(disp,"WM_NAME",True)) != None);
 
-  Atom wm_name= XInternAtom(disp,"WM_NAME",True);
-  xassert(wm_name != None);
-
-  for (screen=0; screen<ScreenCount(disp); screen++) {
-    debugfind("FINDYPP screen %d\n", screen);
-    root= RootWindow(disp,screen);
-    unsigned int nchildren1;
-    Window *children1=0;
-
-    xassert( XQueryTree(disp,root,
-                 &gotroot,&gotparent,
-                 &children1,&nchildren1) );
-    debugfind("FINDYPP screen %d nchildren1=%d\n", screen, nchildren1);
-
-    int i;
-    for (i=0; i<nchildren1; i++) {
-      Window w1= children1[i];
-      unsigned int nchildren2;
-      Window *children2=0;
-
-      xassert( XQueryTree(disp,w1,
-                         &gotroot,&gotparent,
-                         &children2,&nchildren2) );
-      debugfind("FINDYPP screen %d c1[%2d]=0x%08lx nchildren2=%d\n",
-               screen, i, (unsigned long)w1, nchildren2);
-
-      int j;
-      for (j=-1; j<(int)nchildren2; j++) {
-       Window w2= j<0 ? w1 : children2[j];
-       debugfind("FINDYPP screen %d c1[%2d]=0x%08lx c2[%2d]=0x%08lx",
-                 screen, i, (unsigned long)w1, j, (unsigned long)w2);
-
-       int gotfmt;
-       Atom gottype;
-       unsigned long len, gotbytesafter;
-       char *title;
-       unsigned char *gottitle=0;
-       xassert( !XGetWindowProperty(disp,w2, wm_name,0,512, False,
-                                    AnyPropertyType,&gottype, &gotfmt, &len,
-                                    &gotbytesafter, &gottitle) );
-       title= (char*)gottitle;
-
-       if (DEBUGP(findypp)) {
-         debugfind(" gf=%d len=%lu gba=%lu \"", gotfmt,len,gotbytesafter);
-         char *p;
-         for (p=title; p < title+len; p++) {
-           char c= *p;
-           if (c>=' ' && c<=126) fputc(c,debug);
-           else fprintf(debug,"\\x%02x",c & 0xff);
-         }
-         fputs("\": ",debug);
-       }
-
-#define REQUIRE(pred)                                                     \
-        if (!(pred)) { debugfind(" failed test  %s\n", #pred); continue; } \
-        else
-
-       REQUIRE( gottype!=None );
-       REQUIRE( len );
-       REQUIRE( gotfmt==8 );
-
-       REQUIRE( len >= S(prefix) + 1 + S(onthe) + 1 + S(suffix) );
-
-       char *spc1= strchr(  title        + S(prefix), ' ');  REQUIRE(spc1);
-       char *spc2= strrchr((title + len) - S(suffix), ' ');  REQUIRE(spc2);
-
-       REQUIRE( (title + len) - spc1  >= S(onthe)  + S(suffix) );
-       REQUIRE(  spc2         - title >= S(prefix) + S(onthe) );
-
-       REQUIRE( !memcmp(title,                   prefix, S(prefix)) );
-       REQUIRE( !memcmp(title + len - S(suffix), suffix, S(suffix))  );
-       REQUIRE( !memcmp(spc1,                    onthe,  S(onthe))  );
-
-#define ASSIGN(what, start, end)                               \
-       what= masprintf("%.*s", (end)-(start), start);          \
-       if (o_##what) REQUIRE( !strcmp(o_##what, what) );       \
-       else
-
-       ASSIGN(ocean,  spc1 + S(onthe),   (title + len) - S(suffix));
-       ASSIGN(pirate, title + S(prefix),  spc1);
-
-       debugfind(" YES!\n");
-       id= w2;
-       nfound++;
-       progress_log("found YPP client (0x%lx):"
-                    " %s ocean - %s.",
-                    (unsigned long)id, ocean, pirate);
-      }
-      if (children2) XFree(children2);
+  for (targetdepth=1; targetdepth<4; targetdepth++) {
+    for (screen=0; screen<ScreenCount(disp); screen++) {
+      debugfind("FINDYPP screen %d\n", screen);
+      findypp_recurse(0,targetdepth, RootWindow(disp,screen));
     }
-    if (children1) XFree(children1);
+    if (nfound) break;
   }
+
   if (nfound>1)
-    fatal("Found several possible YPP clients."
-         " Close one, or specify the windowid with --window-id.\n");
+    fatal("Found several possible YPP clients.   Close one,\n"
+         " disambiguate with --pirate or --ocean,"
+         " or specify --window-id.\n");
   if (nfound<1)
     fatal("Did not find %sYPP client."
          " Use --window-id and/or report this as a fault.\n",
index d0ba6b797442ef7e7b5c64f6d6d1f557c0c9cafd..720e5dce78d398ed7f8fdfc8f1dde353a1532cf4 100644 (file)
@@ -89,7 +89,9 @@ static int identify1(const RgbImage *base, Rect portion,
          int c;
          dbassert( dbfile_scanf("%d",&c) == 1);
          dbassert(c>=0 && c<=255);
-         diff |= (c != RI_PIXEL(base, portion.tl.x + x, portion.tl.y + y)[i]);
+         int px= portion.tl.x + x, py= portion.tl.y + y;
+         diff |= px > portion.br.x || py > portion.br.y ||
+                 (c != RI_PIXEL(base,px,py)[i]);
        }
       }
     }
@@ -113,6 +115,17 @@ static int identify(const RgbImage *base, Rect portion,
          identify1(base,portion,result,what, "local");
 }
 
+void fwrite_ppmraw(FILE *f, const RgbImage *ri) {
+  fprintf(f,
+         "P6\n"
+         "%d %d\n"
+         "255\n", ri->w, ri->h);
+  int count= ri->w * ri->h * 3;
+  sysassert( fwrite(ri->data, 1, count, f) == count );
+  sysassert(!ferror(f));
+  sysassert(!fflush(f));
+}
+
 static void fwrite_ppm(FILE *f, const RgbImage *base, Rect portion) {
   int x,y,i;
   fprintf(f,"P3\n%d %d\n255\n", RECT_W(portion), RECT_H(portion));
index 35cf0d9507da3335dbe47df403e9992808bc8e85..fba7670a3b510e105dff978f1d21350928c0963f 100644 (file)
@@ -34,7 +34,7 @@ static inline char get_p(Point p) { return get(p.x,p.y); }
 
 DEBUG_DEFINE_DEBUGF(struct)
 
-#define START_MAIN {200,100}
+#define START_MAIN {200,200}
 #define MIN_COLUMNS         6
 #define INTERESTING_COLUMNS 7
 #define TEXT_COLUMNS        2
@@ -58,6 +58,8 @@ const CanonColourInfo canoncolourinfos[]= {
   { 0x6B828C, '*' }, /* background of ship status meter area */
   { 0x934405, '*' }, /* border of ship meter area */
   { 0x7D9094, '+' }, /* interbox */
+  { 0x022158, 'O' }, /* ahoy /w output foreground */
+  { 0xB5B686, 'H' }, /* ahoy /w output heading background */
 
   { 0xBDC5BF, ' ' }, /* background - pale  Sugar cane, etc. */
   { 0xADB5AF, ' ' }, /* background - dark                   */
@@ -90,10 +92,16 @@ const CanonColourInfo canoncolourinfos[]= {
 
 static void mustfail1(const char *file, int line, const char *what) {
   fprintf(stderr,
-         "\n\n"
-         "Unable to figure out contents of YPP client display.\n"
-         " Check that your client is logged in has the correct display.\n"
-         " If that isn't the problem, please report this as a fault.\n\n"
+ "\n\n"
+ "Unable to figure out contents of YPP client display.\n"
+ "Please check the following:\n"
+ "   * YPP client is showing commodity listing screen\n"
+ "   * YPP client has antialiased text turned off (Ye / Options / General)\n"
+ "   * YPP client window is on top (we try to raise it but your window\n"
+ "      manager might have prevented that from succeeding)\n"
+ "   * Your X display is 24bpp (NB some VNC servers use 16bpp by default)\n"
+ "\n"
+ "If all of these are true, please report this as a fault.\n\n"
          "Technical details:"
          " %s:%d: requirement failed:\n"
          " %s\n",
@@ -156,6 +164,32 @@ static void debug_rect(const char *what, int whati, Rect rr) {
   debug_flush();
 }
 
+static int commod_selector_matches(Rect search, const char *const *all,
+                                  int allh, int allw) {
+  int alloffy, alloffx;
+  for (alloffy=0; alloffy < search.br.y; alloffy++) {
+    if (alloffy+allh-1 < search.tl.y) continue;
+    for (alloffx=search.tl.x; alloffx+allw-1 <= search.br.x; alloffx++) {
+      int good=0, bad=0;
+      int x,y;
+      for (x=0; x<allw; x++)
+       for (y=0; y<allh; y++) {
+         int want= all[y][x];
+         if (want==' ') continue;
+          if (get(alloffx+x, alloffy+y) == want)
+           good++;
+         else
+           bad++;
+       }
+      debugf("CHECKCOMMOD alloff=%d,%d good=%d bad=%d\n",
+            alloffx,alloffy, good,bad);
+      if (good > 20*bad)
+       return 1;
+    }
+  }
+  return 0;
+}
+
 #define WALK_UNTIL(point,coord,increm,last,edge)                       \
   for (;;) {                                                           \
     if ((point).coord == (last)+(increm)) break;                       \
@@ -290,7 +324,7 @@ void check_correct_commodities(void) {
 
   debug_rect("commodselr",1, search);
 
-  static const char *all[]= {
+  static const char *all_small[]= {
     "   ___________________________________   ",
     "  ________X____X__X____________________  ",
     " ________ X___ X_ X_____XXXXXXXXXXX_____ ",
@@ -303,34 +337,30 @@ void check_correct_commodities(void) {
     "  ____X_____ _XX_ X______________________",
     "   __ _______  __ ______________________ ",
   };
+  static const char *all_big[]= {
+    "???_______________________________________???",
+    "??_________________________________________??",
+    "?_________X______X___X______________________?",
+    "_________?X_____?X__?X______XXXXXXXXXXX______",
+    "_________X_X____?X__?X_______XXXXXXXXX_______",
+    "________?X?X____?X__?X________XXXXXXX________",
+    "________X_?_X___?X__?X_________XXXXX_________",
+    "_______?X__?X___?X__?X__________XXX__________",
+    "_______?XXXXX___?X__?X___________X___________",
+    "_______X????_X__?X__?X_______________________",
+    "?_____?X____?X__?X__?X_______________________",
+    "??____X_____?_X_?X__?X_______________________",
+    "???__?_______?__?___?_______________________?",
+  };
 
-  static int allh= sizeof(all)/sizeof(all[0]);
-  const int allw= strlen(all[0]);
+#define COMMOD_SELECTOR_MATCHES(all)                           \
+  commod_selector_matches(search, all,                         \
+                         sizeof((all))/sizeof((all)[0]),       \
+                         strlen((all)[0]))
 
-  int alloffy, alloffx;
-  for (alloffy=0; alloffy < search.br.y; alloffy++) {
-    if (alloffy+allh-1 < search.tl.y) continue;
-    for (alloffx=search.tl.x; alloffx+allw-1 <= search.br.x; alloffx++) {
-      int good=0, bad=0;
-      int x,y;
-      for (x=0; x<allw; x++)
-       for (y=0; y<allh; y++) {
-         int want= all[y][x];
-         if (want==' ') continue;
-          if (get(alloffx+x, alloffy+y) == want)
-           good++;
-         else
-           bad++;
-       }
-      debugf("CHECKCOMMOD alloff=%d,%d good=%d bad=%d\n",
-            alloffx,alloffy, good,bad);
-      if (good > 20*bad)
-       goto all_found;
-    }
-  }
-  fatal("Commodities selector not set to `All'.");
-
- all_found:;
+  if (!(COMMOD_SELECTOR_MATCHES(all_small) ||
+       COMMOD_SELECTOR_MATCHES(all_big)))
+    fatal("Commodities selector not set to `All'.");
 }
 
 CanonImage *alloc_canon_image(int w, int h) {
@@ -499,23 +529,11 @@ void analyse(FILE *tsv_output) {
 
 //static Rect islandnamer;
 
-void find_islandname(void) {
-  Rect sunshiner;
-  char sunshine[MAXIMGIDENT], archisland[MAXIMGIDENT];
+DEBUG_DEFINE_SOME_DEBUGF(structcolon,colondebugf)
 
-  RgbImage *ri= alloc_rgb_image(page0_rgbimage->w, page0_rgbimage->h);
-  const unsigned char *srcp;
-  unsigned char *destp, *endp;
-  for (srcp=page0_rgbimage->data, destp=ri->data,
-        endp= ri->data + 3 * ri->w * ri->h;
-       destp < endp;
-       srcp++, destp++) {
-    unsigned char c= *srcp & 0xf0;
-    *destp= c | (c>>4);
-  }
+Rect find_sunshine_widget(void) {
+  Rect sunshiner;
 
-  cim= page_images[0];
-  
   sunshiner.tl.x= cim->w - 1034 +  885;
   sunshiner.br.x= cim->w - 1034 + 1020;
   sunshiner.tl.y= 227;
@@ -531,10 +549,28 @@ void find_islandname(void) {
   ADJUST_BOX(sunshiner,"o",20, (cim->w - 1034 + 700), MUST, tl,x,-1);
   ADJUST_BOX(sunshiner,"o",20,  cim->w,               MUST, br,x,+1);
   debug_rect("sunshiner",1, sunshiner);
+  return sunshiner;
+}
+
+void find_islandname(RgbImage *ri) {
+  find_structure(page_images[0], 0);
+
+  Rect sunshiner= find_sunshine_widget();
+  char sunshine[MAXIMGIDENT], archisland[MAXIMGIDENT];
+
+  const unsigned char *srcp;
+  unsigned char *destp, *endp;
+  for (srcp=page0_rgbimage->data, destp=ri->data,
+        endp= ri->data + 3 * ri->w * ri->h;
+       destp < endp;
+       srcp++, destp++) {
+    unsigned char c= *srcp & 0xf0;
+    *destp= c | (c>>4);
+  }
 
   identify_rgbimage(ri, sunshiner, sunshine, "sunshine widget");
   
-  if (!memcmp(sunshine,"Ship ",5)) {
+  if (!memcmp(sunshine,"Vessel ",5)) {
     Rect islandnamer;
     
     islandnamer.tl.x= cim->w - 1034 +  885;
@@ -545,6 +581,9 @@ void find_islandname(void) {
     ADJUST_BOX(islandnamer,"o",5, 0,      MUST, tl,y,+1);
     ADJUST_BOX(islandnamer,"o",5, cim->h, MUST, br,y,-1);
 
+    ADJUST_BOX(islandnamer,"o",1, 0,      MUST, tl,x,+1);
+    ADJUST_BOX(islandnamer,"o",1, cim->w, MUST, br,x,-1);
+
     debug_rect("islandnamer",0, islandnamer);
 //    int larger_islandnamebry= islandnamer.tl.y + 25;
 //    MUST(islandnamer.br.y < larger_islandnamebry,
@@ -564,7 +603,91 @@ void find_islandname(void) {
 
     identify_rgbimage(ri, islandnamer, archisland, "island");
   } else {
-    assert(!"not vessel");
+    Rect islandnamer;
+
+    islandnamer.tl.x= (sunshiner.tl.x + sunshiner.br.x) / 2;
+    islandnamer.tl.y= sunshiner.tl.y + 100;
+    islandnamer.br= islandnamer.tl;
+    debug_rect("islandnamer",__LINE__, islandnamer);
+    
+    WALK_UNTIL_MUST(islandnamer.tl,y, -1, sunshiner.br.y, 'H');
+    WALK_UNTIL_MUST(islandnamer.tl,x, -1, 0,              'o');
+    WALK_UNTIL_MUST(islandnamer.br,x, +1, cim->w,         'o');
+    debug_rect("islandnamer",__LINE__, islandnamer);
+
+    require_rectangle_r(islandnamer, "O*", __LINE__);
+
+    int rw= RECT_W(islandnamer);
+    ADJUST_BOX(islandnamer,"O",rw-4, cim->h, MUST,br,y,+1);
+    debug_rect("islandnamer",__LINE__, islandnamer);
+
+    islandnamer.br.y += 2;
+    ADJUST_BOX(islandnamer,"O",1,    cim->h, MUST,br,y,+1);
+    debug_rect("islandnamer",__LINE__, islandnamer);
+
+    islandnamer.tl.y= islandnamer.br.y-1;
+    islandnamer.br.y= islandnamer.br.y+1;
+    ADJUST_BOX(islandnamer,"*",rw,   cim->h, MUST,br,y,+1);
+    ADJUST_BOX(islandnamer,"O",1,    cim->w, MUST,tl,x,+1);
+    debug_rect("islandnamer",__LINE__, islandnamer);
+
+    MUST( RECT_H(islandnamer) <= 31, MR(islandnamer));
+
+    Point p;
+    int nspaces=1, might_be_colon=0;
+    uint32_t colon_pattern= 0;
+    p.y=-1;
+
+    for (p.x=islandnamer.br.x; p.x>islandnamer.tl.x; p.x--) {
+      colondebugf("structcolon: x=%4d nsp=%2d mbc=%d cp=%08"PRIx32" ",
+                 p.x, nspaces, might_be_colon, colon_pattern);
+
+      uint32_t pattern=0;
+      int runs[32], nruns=0;
+      runs[0]=0; runs[1]=0;
+      
+      for (p.y=islandnamer.tl.y; p.y<=islandnamer.br.y; p.y++) {
+       pattern <<= 1;
+       switch (get_p(p)) {
+       case 'O': runs[nruns]++;                         pattern |= 1u; break;
+       case '*': if (runs[nruns]) { nruns++; runs[nruns]=0; }          break;
+       default: abort();
+       }
+      }
+
+      colondebugf(" pat=%08"PRIx32" nruns=%d runs[]={%d,%d..} ",
+                 pattern, nruns, runs[0],runs[1]);
+
+      if (!pattern) {
+       if (might_be_colon)
+         /* omg it _is_ a colon */
+         goto colon_found;
+       nspaces++;
+       might_be_colon=0;
+      } else {
+       if (nruns==2 && runs[1]==runs[0]) {
+         if (!nspaces) {
+           if (pattern==colon_pattern)
+             goto ok_might_be_colon;
+         } else if (nspaces>=2) {
+           colon_pattern= pattern;
+           might_be_colon=1;
+           goto ok_might_be_colon;
+         }
+       }
+       might_be_colon=0;
+      ok_might_be_colon:
+       nspaces= 0;
+      }
+      colondebugf(" nsp=%2d mbc=%d\n", nspaces, might_be_colon);
+    }
+    MUST(!"colon found", MP(p);MR(islandnamer) );
+
+  colon_found:
+    colondebugf(" found\n");
+    islandnamer.br.x= p.x;
+
+    identify_rgbimage(ri, islandnamer, archisland, "island");
   }
 
   char *delim= strstr(archisland," - ");
index 0ad92a618e62386844f2ac50ebf652ac981ce754..ec399a2aaa7cb974dfee2b636971ad2abb348415 100644 (file)
@@ -42,38 +42,45 @@ extern const CanonColourInfo canoncolourinfos[];
 
 CanonImage *alloc_canon_image(int w, int h);
 
-#define CANONICALISE_IMAGE(im,w,h, COMPUTE_RGB) do{            \
-    /* compute_rgb should be a number of statements, or                \
-     * a block, which assigns to                               \
-     *   unsigned long rgb;                                    \
-     * given the values of                                     \
-     *   int x,y;                                              \
-     * all of which are anamorphic.  Result is stored in im.   \
-     * The COMPUTE_RGB is executed exactly once for            \
-     * each pixel in reading order.                            \
-     */                                                                \
-    (im)= alloc_canon_image((w), (h));                         \
-                                                               \
-    int x,y;                                                   \
-    for (y=0; y<(h); y++) {                                    \
-      for (x=0; x<(w); x++) {                                  \
-        const CanonColourInfo *cci;                            \
-        unsigned long rgb;                                     \
-       COMPUTE_RGB;                                            \
-       for (cci=canoncolourinfos; cci->c; cci++) {             \
-         if (cci->rgb == rgb) {                                \
-           (im)->d[y*(w) + x]= cci->c;                         \
-           break;                                              \
-         }                                                     \
-       }                                                       \
-      }                                                                \
-      if (DEBUGP(rect)) {                                      \
-       fprintf(debug, "%4d ",y);                               \
-       fwrite(im->d + y*w, 1,w, debug);                        \
-       fputc('\n',debug);                                      \
-      }                                                                \
-    }                                                          \
-    debug_flush();                                             \
+#define CANONICALISE_IMAGE(im,w,h, COMPUTE_RGB) do{                    \
+    /* compute_rgb should be a number of statements, or                        \
+     * a block, which assigns to                                       \
+     *   unsigned long rgb;                                            \
+     * given the values of                                             \
+     *   int x,y;                                                      \
+     * all of which are anamorphic.  Result is stored in im.           \
+     * The COMPUTE_RGB is executed exactly once for                    \
+     * each pixel in reading order.                                    \
+     */                                                                        \
+    (im)= alloc_canon_image((w), (h));                                 \
+                                                                       \
+    int x,y;                                                           \
+    unsigned long last_rgb= ~0UL;                                      \
+    int last_c= -1;                                                    \
+    for (y=0; y<(h); y++) {                                            \
+      for (x=0; x<(w); x++) {                                          \
+        const CanonColourInfo *cci;                                    \
+        unsigned long rgb;                                             \
+       COMPUTE_RGB;                                                    \
+       if (rgb == last_rgb) {                                          \
+         (im)->d[y*(w) + x]= last_c;                                   \
+       } else {                                                        \
+         for (cci=canoncolourinfos; cci->c; cci++) {                   \
+           if (cci->rgb == rgb) {                                      \
+             last_rgb= rgb;                                            \
+             (im)->d[y*(w) + x]= last_c= cci->c;                       \
+             break;                                                    \
+           }                                                           \
+         }                                                             \
+       }                                                               \
+      }                                                                        \
+      if (DEBUGP(rect)) {                                              \
+       fprintf(debug, "%4d ",y);                                       \
+       fwrite(im->d + y*w, 1,w, debug);                                \
+       fputc('\n',debug);                                              \
+      }                                                                        \
+    }                                                                  \
+    debug_flush();                                                     \
   }while(0)
 
 
index c6d2387b18f1795ee0911cec77dc07c6bc650922..5adf557e0ffb9d27784328376e6030b4664de9d1 100644 (file)
@@ -1,5 +1,8 @@
 file ypp-commodities
-set confirm off
-set args -Dcallout --ocean midnight --pirate aristarchus --same --raw-tsv >raw.tsv 
-break convert.c:260
+set args -Dpages --test-servers --find-island
+break pages.c:596
+
+#set args -Dcallout --ocean midnight --pirate aristarchus --same --raw-tsv >raw.tsv 
+#break convert.c:260
+
 run