Finding still life articles with suboptimal syntheses

For scripts to aid with computation or simulation in cellular automata.
Post Reply
User avatar
Apple Bottom
Posts: 1034
Joined: July 27th, 2015, 2:06 pm
Contact:

Finding still life articles with suboptimal syntheses

Post by Apple Bottom » January 9th, 2017, 1:45 pm

In light of chris_c's list of still life glider synthesis costs (see the "15 in 15" thread for more), dvgrn asked for my help writing a script to check which still life articles on the LifeWiki need updating to account for newer, more efficient syntheses.

I spent a few hours cooking up something in Perl (my preferred language), using the MediaWiki::Bot module from CPAN. To run this:

1. Fire up the CPAN shell using the "cpan" command, and force-install the module:

Code: Select all

$ cpan
Terminal does not support AddHistory.

cpan shell -- CPAN exploration and modules installation (v2.11)
Enter 'h' for help.

cpan[1]> force install MediaWiki::Bot
Reading '~/.cpan/Metadata'
  Database was generated on Mon, 09 Jan 2017 01:29:02 GMT
[...]
Note that "force install" is necessary due to (harmless, for the purpose of this bot) test suite failures.

2. Save Chris C.'s still_list.txt file in a suitable directory.

3. Save the following script in the same directory, as e.g. applebot.pl -- better yet, get it from Github:

Code: Select all

#!/usr/bin/perl

###############
### MODULES ###
###############

# preliminaries
use Modern::Perl '2014';
use English;
use utf8;               # script itself is in UTF-8

# core modules
use Getopt::Long;
use Term::ANSIColor     qw/:constants/;

# non-core modules
use Data::Dumper;       # for debugging
use File::Slurp;
use MediaWiki::Bot;
use PerlIO::Util;       # for ->push_layer on *STDOUT etc

##############################
### CONFIGURATION DEFAULTS ###
##############################

# run anonymously?
# NOTE: MediaWiki::Bot 5.006003 is unable to login to newer wikis, due to
# the module's lack of maintenance and the frequent and
# backwards-incompatible changes to the MediaWiki API.
our $be_anonymous       = 1;

# debugging level to be passed to MediaWiki::Bot (0, 1 or 2).
our $debug_level        = 0;

# filename for Chris C's still_list.txt; should be downloaded from
# https://github.com/ceebo/glider_synth/blob/master/still_list.txt
our $still_list_txt     = "still_list.txt";

# category to fetch pages from; suggested values are "Strict still lifes" or
# "Still lifes".
our $category           = "Strict still lifes";

# username to use.
our $username           = "Apple Bot";

# password to use. Don't specify this here; pass it on the command line.
our $password           => undef;

####################################################
### NO NEED TO CHANGE ANYTHING BEYOND THIS POINT ###
####################################################

# autoflush STDOUT
$OUTPUT_AUTOFLUSH = 1;

# also write console output to log file
*STDOUT->push_layer(tee => 'output.applebot.log');

# process options
GetOptions(
    "password|p=s"      => \$password,
    "username|u=s"      => \$username,
    "anonymous!"        => \$be_anonymous,
    ) or usage();

# create a bot object we'll be using to operate
our $applebot = MediaWiki::Bot->new({
#    assert             => 'bot',               # uncomment once Apple Bot has a bot flag on the wiki.
    operator            => 'Apple Bottom',
#    protocol           => 'https',             # does not currently work due to an invalid SSL certificate
    protocol            => 'http',
    host                => 'conwaylife.com',
    debug               => $debug_level,
});

# call MAIN routine and exit
exit MAIN();

####################
### MAIN ROUTINE ###
####################

sub MAIN {

    my $starting_time = time;

    say "Starting up at ", BRIGHT_WHITE, scalar localtime($starting_time), RESET, ".";

    # this hash will hold information on our objects.
    my $objects = {};

    # read Chris C.'s list
    print "Reading Chris C.'s list... ";
    my @ceebo_lines = read_file($still_list_txt);

    # process Chris C.'s list
    foreach my $ceebo_line (@ceebo_lines) {

        # split line into object number (e.g.  4.1), apgcode (e.g.  xs4_33)
        # and glider count (e.g.  2)
        my ($number, $apgcode, $synthesis) = split /\s+/, $ceebo_line;

        # record this object in our objects hash.
        $objects->{$apgcode} = {
            'number'            => $number,
            'ceebo_synthesis'   => $synthesis,
        };

    }

    say GREEN, "done", RESET;

    # log in to the wiki
    unless($be_anonymous) {

        # make sure user provided username and password.
        if(($username // "") eq "" or ($password // "") eq "") {
            die "No username/password specified!";
        }

        print "Logging in to the LifeWiki as ", BRIGHT_WHITE, $username, RESET, "... ";
        $applebot->login({
                username        => "Apple Bot",
                password        => "",
            }) or die "Login failed";
        say GREEN, "done", RESET;

    }

    # get list of page titles
    print "Getting list of strict still lifes... ";
    my @page_titles = $applebot->get_pages_in_category(
        "Category:$category",
        {
            max => 0,   # return all results
        }
    );
    say GREEN, "done", RESET;

    foreach my $page_title (@page_titles) {

        # get page text
        print "Getting wikitext for ${page_title}... ";
        my $wikitext = $applebot->get_text($page_title);

        # this could conceivably happen if a page gets deleted after we
        # fetched the list of page titles.
        unless(defined $wikitext) {
            say BRIGHT_RED, "page does not exist!";
            next;
        }

        say GREEN, "done", RESET;

        # apgcode and synthesis
        my $apgcode     = undef;
        my $synthesis   = undef;

        # attempt to extract glider synthesis
        if($wikitext =~ m/synthesis\s*=\s*([^\s\|]+)/g) {
            $synthesis = $1;

#            say "\tSynthesis: ", BRIGHT_WHITE, $synthesis, RESET;
#        } else {
#            say "\tNo synthesis found";
        }

        # attempt to extract apgcode
        if($wikitext =~ m/\{\{LinkCatagolue\|[^\}]*(xs(\d+)_([0-9a-z]+))/g) {
            $apgcode = $1;

#            say "\tapgcode: ", BRIGHT_WHITE, $apgcode, RESET;
#        } else {
#            say "\tNo apgcode found";
        }

        # did we extract an apgcode?
        if(defined $apgcode) {

            # yes; remember page title and synthesis count
            $objects->{$apgcode}->{'page_title'}        = $page_title;
            $objects->{$apgcode}->{'wiki_synthesis'}    = $synthesis;

        }

    }

    # Find objects we could improve (sorted by page title, only taking into
    # account objects that are on the wiki in the first place).
    foreach my $apgcode (sort { $objects->{$a}->{'page_title'} cmp $objects->{$b}->{'page_title'} } grep { exists $objects->{$_}->{'page_title'} } keys %$objects) {

        # if we have the wiki_synthesis (sub)hash key, the object was found
        # on the wiki (but the associated value may be undefined if no
        # glider synthesis count was extracted).  Same for Chris C.'s
        # synthesis.
        if(exists $objects->{$apgcode}->{'wiki_synthesis'} and exists $objects->{$apgcode}->{'ceebo_synthesis'}) {

            # extract synthesis counts, for convenience
            my ($wiki_synthesis, $ceebo_synthesis, $page_title) =
                map {
                    $objects->{$apgcode}->{$_}
                } ("wiki_synthesis", "ceebo_synthesis", "page_title");

            # is the object without a listed synthesis on the wiki?
            if(not defined $wiki_synthesis) {
                say BRIGHT_WHITE, $page_title, RESET, " has no synthesis on the wiki, but a ", BRIGHT_WHITE, $ceebo_synthesis, RESET, " glider synthesis in Chris C.'s list.";

            # or is the wiki synthesis worse than Chris C.'s?
            } elsif($wiki_synthesis > $ceebo_synthesis) {
                say BRIGHT_WHITE, $page_title, RESET, " has a ", BRIGHT_WHITE, $wiki_synthesis, RESET, " glider synthesis on the wiki, but a ", BRIGHT_WHITE, $ceebo_synthesis, RESET, " glider synthesis in Chris C.'s list.";

            }

        }

    }

    # log out of the wiki
    unless($be_anonymous) {

        print "Logging out... ";
        $applebot->logout();
        say GREEN, "done", RESET;

    }

    say "Finished at ", BRIGHT_WHITE, scalar localtime(time), RESET, ".";

    # success!
    return 0;
}

###################
### SUBROUTINES ###
###################

# print usage information
sub usage {
    print <<ENDOFUSAGE;
Usage: $0 [options]

Options:

    --anonymous             Do not login (default). Negate with --no-anonymous.
    --username=<...>        Use specified username for logging in.
    --password=<...>        Use specified password for logging in.

ENDOFUSAGE

    exit 1;
}
4. Run the script:

Code: Select all

Starting up at Mon Jan  9 18:46:30 2017.
Reading Chris C.'s list... done
Getting list of strict still lifes... done
Getting wikitext for Aircraft carrier... done
Getting wikitext for Amphisbaena... done
Getting wikitext for Barge... done
Getting wikitext for Barge with long tail... done
Getting wikitext for Bee hat... done
Getting wikitext for Beehive... done
Getting wikitext for Beehive and cap... done
Getting wikitext for Beehive and dock... done
Getting wikitext for Beehive and table... done
Getting wikitext for Beehive at beehive... done
Getting wikitext for Beehive at loaf... done
Getting wikitext for Beehive bend tail... done
Getting wikitext for Beehive with nine... done
Getting wikitext for Beehive with tail... done
Getting wikitext for Bi-cap... done
Getting wikitext for Bi-loaf 1... done
Getting wikitext for Bi-loaf 2... done
Getting wikitext for Bi-loaf 4... done
Getting wikitext for Bi-pond... done
Getting wikitext for Big S... done
Getting wikitext for Block... done
Getting wikitext for Block and cap... done
Getting wikitext for Block and dock... done
Getting wikitext for Block and two tails... done
Getting wikitext for Block on table... done
Getting wikitext for Boat... done
Getting wikitext for Boat on aircraft... done
Getting wikitext for Boat on snake... done
Getting wikitext for Boat with hooked tail... done
Getting wikitext for Boat with long tail... done
Getting wikitext for Boat with very long tail... done
Getting wikitext for Boat-ship-tie... done
Getting wikitext for Boat-tie... done
Getting wikitext for Bookends... done
Getting wikitext for BTS... done
Getting wikitext for Canoe... done
Getting wikitext for Cap and dock... done
Getting wikitext for Carrier siamese carrier... done
Getting wikitext for Carrier siamese snake... done
Getting wikitext for Carrier with feather... done
Getting wikitext for Cis-barge with tail... done
Getting wikitext for Cis-block and long hook... done
Getting wikitext for Cis-boat and dock... done
Getting wikitext for Cis-boat and table... done
Getting wikitext for Cis-boat with nine... done
Getting wikitext for Cis-boat with tail... done
Getting wikitext for Cis-fuse with two tails... done
Getting wikitext for Cis-hook and R-bee... done
Getting wikitext for Cis-hook with tail... done
Getting wikitext for Cis-loaf with tail... done
Getting wikitext for Cis-long boat with tail... done
Getting wikitext for Cis-mirrored R-bee... done
Getting wikitext for Cis-mirrored worm... done
Getting wikitext for Cis-mirrored worm siamese cis-mirrored worm... done
Getting wikitext for Cis-R-bee and R-loaf... done
Getting wikitext for Cis-rotated hook... done
Getting wikitext for Cis-rotated R-bee... done
Getting wikitext for Cis-shillelagh... done
Getting wikitext for Claw with tail... done
Getting wikitext for Claw with tub with tail... done
Getting wikitext for Cloverleaf interchange... done
Getting wikitext for Cthulhu... done
Getting wikitext for Dead spark coil... done
Getting wikitext for Dock siamese carrier... done
Getting wikitext for Eater 1... done
Getting wikitext for Eater 2... done
Getting wikitext for Eater 4... done
Getting wikitext for Eater head siamese carrier... done
Getting wikitext for Eater head siamese snake... done
Getting wikitext for Eater on boat... done
Getting wikitext for Eater siamese eater... done
Getting wikitext for Eater tail siamese carrier... done
Getting wikitext for Eater tail siamese snake... done
Getting wikitext for Eater with cape... done
Getting wikitext for Eleven loop... done
Getting wikitext for Elevener... done
Getting wikitext for Extra extra long snake... done
Getting wikitext for Extra long hook with tail... done
Getting wikitext for Extra long shillelagh... done
Getting wikitext for Extra long snake... done
Getting wikitext for Fourteener... done
Getting wikitext for Fuse with tail and long tail... done
Getting wikitext for Hat... done
Getting wikitext for Honeycomb... done
Getting wikitext for Hook with tail... done
Getting wikitext for House on house siamese table-on-table weld hat-siamese-hat... done
Getting wikitext for Hungry hat... done
Getting wikitext for Integral sign... done
Getting wikitext for Integral with hook... done
Getting wikitext for Integral with long hook... done
Getting wikitext for Integral with tub... done
Getting wikitext for Integral with tub and hook... done
Getting wikitext for Integral with two tubs... done
Getting wikitext for Lake 2... done
Getting wikitext for Loaf... done
Getting wikitext for Loaf siamese barge... done
Getting wikitext for Loaf siamese loaf... done
Getting wikitext for Long barge... done
Getting wikitext for Long boat... done
Getting wikitext for Long canoe... done
Getting wikitext for Long cis-hook with tail... done
Getting wikitext for Long cis-shillelagh... done
Getting wikitext for Long claw with tail... done
Getting wikitext for Long fuse with two tails... done
Getting wikitext for Long hook with tail... done
Getting wikitext for Long integral... done
Getting wikitext for Long long barge... done
Getting wikitext for Long long boat... done
Getting wikitext for Long long canoe... done
Getting wikitext for Long long hook with tail... done
Getting wikitext for Long long shillelagh... done
Getting wikitext for Long long ship... done
Getting wikitext for Long long snake... done
Getting wikitext for Long prodigal... done
Getting wikitext for Long shillelagh... done
Getting wikitext for Long ship... done
Getting wikitext for Long snake... done
Getting wikitext for Longhook and dock... done
Getting wikitext for Loop... done
Getting wikitext for Mango... done
Getting wikitext for Mickey Mouse... done
Getting wikitext for Mirrored dock... done
Getting wikitext for Moose antlers... done
Getting wikitext for Omnibus... done
Getting wikitext for Omnibus with tubs... done
Getting wikitext for Ortho-loaf and table... done
Getting wikitext for Paperclip... done
Getting wikitext for Pond... done
Getting wikitext for Pond and dock... done
Getting wikitext for Professor... done
Getting wikitext for Python siamese carrier... done
Getting wikitext for Python siamese snake... done
Getting wikitext for R-bee and snake... done
Getting wikitext for R-mango and house... done
Getting wikitext for Rotated C... done
Getting wikitext for Scorpion... done
Getting wikitext for Sesquihat... done
Getting wikitext for Shillelagh... done
Getting wikitext for Ship... done
Getting wikitext for Ship on long boat... done
Getting wikitext for Ship-tie... done
Getting wikitext for Sidewalk... done
Getting wikitext for Skew R-bees... done
Getting wikitext for Small lake... done
Getting wikitext for Snake... done
Getting wikitext for Snake bridge snake... done
Getting wikitext for Snake siamese snake... done
Getting wikitext for Snake with feather... done
Getting wikitext for Snorkel loop... done
Getting wikitext for Spiral... done
Getting wikitext for Super loaf... done
Getting wikitext for Super mango... done
Getting wikitext for Symmetric scorpion... done
Getting wikitext for Table and dock... done
Getting wikitext for Table on table... done
Getting wikitext for Tetraloaf I... done
Getting wikitext for Trans-barge with tail... done
Getting wikitext for Trans-block and long hook... done
Getting wikitext for Trans-boat and dock... done
Getting wikitext for Trans-boat and table... done
Getting wikitext for Trans-boat with nine... done
Getting wikitext for Trans-boat with tail... done
Getting wikitext for Trans-fuse with two tails... done
Getting wikitext for Trans-hook and R-bee... done
Getting wikitext for Trans-loaf with tail... done
Getting wikitext for Trans-long boat with tail... done
Getting wikitext for Trans-mirrored R-bee... done
Getting wikitext for Trans-R-bee and R-loaf... done
Getting wikitext for Trans-rotated R-bee... done
Getting wikitext for Tub... done
Getting wikitext for Tub with cis-tail... done
Getting wikitext for Tub with extra long tail... done
Getting wikitext for Tub with long long tail... done
Getting wikitext for Tub with long tail... done
Getting wikitext for Tub with tail... done
Getting wikitext for Twin hat... done
Getting wikitext for Up dove on dove... done
Getting wikitext for Up wing on wing... done
Getting wikitext for Very long integral... done
Getting wikitext for Very very long barge... done
Getting wikitext for Very very long boat... done
Getting wikitext for Very very long canoe... done
Getting wikitext for Very very long ship... done
Getting wikitext for Very^3 long boat... done
Getting wikitext for Very^4 long boat... done
Getting wikitext for Very^4 long snake... done
Getting wikitext for Very^5 long boat... done
Getting wikitext for Very^6 long boat... done
Getting wikitext for Very^7 long boat... done
Getting wikitext for Very^8 long boat... done
Getting wikitext for Very^9 long boat... done
Beehive and cap has no synthesis on the wiki, but a 4 glider synthesis in Chris C.'s list.
Beehive and dock has no synthesis on the wiki, but a 4 glider synthesis in Chris C.'s list.
Beehive at loaf has a 7 glider synthesis on the wiki, but a 5 glider synthesis in Chris C.'s list.
Beehive with nine has a 6 glider synthesis on the wiki, but a 5 glider synthesis in Chris C.'s list.
Bi-cap has a 9 glider synthesis on the wiki, but a 4 glider synthesis in Chris C.'s list.
Bi-pond has a 4 glider synthesis on the wiki, but a 3 glider synthesis in Chris C.'s list.
Boat with long tail has a 5 glider synthesis on the wiki, but a 4 glider synthesis in Chris C.'s list.
Boat with very long tail has a 8 glider synthesis on the wiki, but a 7 glider synthesis in Chris C.'s list.
Carrier siamese carrier has a 6 glider synthesis on the wiki, but a 5 glider synthesis in Chris C.'s list.
Carrier siamese snake has a 6 glider synthesis on the wiki, but a 4 glider synthesis in Chris C.'s list.
Carrier with feather has a 6 glider synthesis on the wiki, but a 4 glider synthesis in Chris C.'s list.
Cis-R-bee and R-loaf has no synthesis on the wiki, but a 5 glider synthesis in Chris C.'s list.
Cis-block and long hook has a 5 glider synthesis on the wiki, but a 4 glider synthesis in Chris C.'s list.
Cis-boat with nine has a 6 glider synthesis on the wiki, but a 5 glider synthesis in Chris C.'s list.
Cis-fuse with two tails has a 8 glider synthesis on the wiki, but a 6 glider synthesis in Chris C.'s list.
Cis-hook and R-bee has no synthesis on the wiki, but a 4 glider synthesis in Chris C.'s list.
Cis-hook with tail has a 8 glider synthesis on the wiki, but a 5 glider synthesis in Chris C.'s list.
Cis-long boat with tail has a 7 glider synthesis on the wiki, but a 6 glider synthesis in Chris C.'s list.
Cis-rotated R-bee has no synthesis on the wiki, but a 6 glider synthesis in Chris C.'s list.
Cis-rotated hook has no synthesis on the wiki, but a 4 glider synthesis in Chris C.'s list.
Dock siamese carrier has no synthesis on the wiki, but a 4 glider synthesis in Chris C.'s list.
Eater head siamese snake has a 8 glider synthesis on the wiki, but a 6 glider synthesis in Chris C.'s list.
Eater siamese eater has a 5 glider synthesis on the wiki, but a 4 glider synthesis in Chris C.'s list.
Extra long snake has a 6 glider synthesis on the wiki, but a 5 glider synthesis in Chris C.'s list.
Fuse with tail and long tail has a 7 glider synthesis on the wiki, but a 6 glider synthesis in Chris C.'s list.
Honeycomb has a 11 glider synthesis on the wiki, but a 9 glider synthesis in Chris C.'s list.
Integral with tub has a 5 glider synthesis on the wiki, but a 4 glider synthesis in Chris C.'s list.
Loaf siamese barge has a 9 glider synthesis on the wiki, but a 6 glider synthesis in Chris C.'s list.
Loaf siamese loaf has a 8 glider synthesis on the wiki, but a 4 glider synthesis in Chris C.'s list.
Long long hook with tail has a 7 glider synthesis on the wiki, but a 6 glider synthesis in Chris C.'s list.
Long long shillelagh has a 6 glider synthesis on the wiki, but a 4 glider synthesis in Chris C.'s list.
Long long snake has a 5 glider synthesis on the wiki, but a 4 glider synthesis in Chris C.'s list.
Long shillelagh has a 6 glider synthesis on the wiki, but a 4 glider synthesis in Chris C.'s list.
Loop has a 5 glider synthesis on the wiki, but a 4 glider synthesis in Chris C.'s list.
Ortho-loaf and table has a 6 glider synthesis on the wiki, but a 5 glider synthesis in Chris C.'s list.
R-bee and snake has a 7 glider synthesis on the wiki, but a 4 glider synthesis in Chris C.'s list.
Sesquihat has a 6 glider synthesis on the wiki, but a 5 glider synthesis in Chris C.'s list.
Ship on long boat has a 6 glider synthesis on the wiki, but a 5 glider synthesis in Chris C.'s list.
Skew R-bees has no synthesis on the wiki, but a 5 glider synthesis in Chris C.'s list.
Snake bridge snake has a 9 glider synthesis on the wiki, but a 7 glider synthesis in Chris C.'s list.
Snake siamese snake has a 6 glider synthesis on the wiki, but a 5 glider synthesis in Chris C.'s list.
Snorkel loop has a 6 glider synthesis on the wiki, but a 4 glider synthesis in Chris C.'s list.
Super mango has a 25 glider synthesis on the wiki, but a 14 glider synthesis in Chris C.'s list.
Symmetric scorpion has no synthesis on the wiki, but a 4 glider synthesis in Chris C.'s list.
Table and dock has no synthesis on the wiki, but a 6 glider synthesis in Chris C.'s list.
Trans-R-bee and R-loaf has no synthesis on the wiki, but a 4 glider synthesis in Chris C.'s list.
Trans-block and long hook has a 5 glider synthesis on the wiki, but a 4 glider synthesis in Chris C.'s list.
Trans-boat and dock has no synthesis on the wiki, but a 5 glider synthesis in Chris C.'s list.
Trans-boat and table has a 6 glider synthesis on the wiki, but a 4 glider synthesis in Chris C.'s list.
Trans-hook and R-bee has no synthesis on the wiki, but a 4 glider synthesis in Chris C.'s list.
Trans-long boat with tail has a 5 glider synthesis on the wiki, but a 4 glider synthesis in Chris C.'s list.
Trans-rotated R-bee has no synthesis on the wiki, but a 4 glider synthesis in Chris C.'s list.
Tub with cis-tail has a 8 glider synthesis on the wiki, but a 4 glider synthesis in Chris C.'s list.
Tub with long long tail has a 7 glider synthesis on the wiki, but a 6 glider synthesis in Chris C.'s list.
Tub with long tail has a 5 glider synthesis on the wiki, but a 4 glider synthesis in Chris C.'s list.
Very long integral has a 9 glider synthesis on the wiki, but a 5 glider synthesis in Chris C.'s list.
Very very long barge has no synthesis on the wiki, but a 4 glider synthesis in Chris C.'s list.
Very very long canoe has a 7 glider synthesis on the wiki, but a 5 glider synthesis in Chris C.'s list.
Very very long ship has no synthesis on the wiki, but a 5 glider synthesis in Chris C.'s list.
Very^3 long boat has no synthesis on the wiki, but a 6 glider synthesis in Chris C.'s list.
Very^4 long boat has no synthesis on the wiki, but a 7 glider synthesis in Chris C.'s list.
Finished at Mon Jan  9 18:47:51 2017.
5. Fix up all the articles it lists.

6. Profit.
If you speak, your speech must be better than your silence would have been. — Arabian proverb

Catagolue: Apple Bottom • Life Wiki: Apple Bottom • Twitter: @_AppleBottom_

Proud member of the Pattern Raiders!

chris_c
Posts: 966
Joined: June 28th, 2014, 7:15 am

Re: Finding still life articles with suboptimal syntheses

Post by chris_c » January 9th, 2017, 2:43 pm

Apple Bottom wrote: 5. Fix up all the articles it lists.
Cool. I will make a version of my display synthesis script that takes a list of apgcodes and outputs files consisting of glider synthesis RLE.

Thinking more ambitiously, maybe someone could write some Python/Javascript/Perl that looks at my min_paths.txt and converts an apgcode into a glider synthesis RLE directly in the broswer?

Note that the most "Golly-dependent" parts of my script are the bits that convert a still life on the screen to an apgcode. If you already have the apgcode then you can strip out all of the "canonise" and "get_period" functions and what is left is really not very complicated. The only calls to g.evolve are in display_synthesis and in get_gliders. The first is basically cosmetic and could be ignored, the second call is just used to advance a glider by 0,1,2 or 3 generations.

Does anyone have thoughts on this? Would it be feasible to port my display_synth script to Javascript and get everything running on the client-side? I have no experience with any kind of web-scripts.

EDIT: Added a new script. It's a Golly script that reads from a file named apgcodes.txt and outputs a bunch of glider synthesis RLEs. The file apgcodes.txt should consist of lines of the form "<apgcode>SPACE<output_filename>" or just "<apgcode>" e.g.:

Code: Select all

xs4_33 block
xp2_7 blinker
xs16_8u16853z32
would output glider syntheses to "block.rle" "blinker.rle" and "xs16_8u16853z32.rle".

User avatar
Apple Bottom
Posts: 1034
Joined: July 27th, 2015, 2:06 pm
Contact:

Re: Finding still life articles with suboptimal syntheses

Post by Apple Bottom » January 9th, 2017, 4:01 pm

chris_c wrote:Thinking more ambitiously, maybe someone could write some Python/Javascript/Perl that looks at my min_paths.txt and converts an apgcode into a glider synthesis RLE directly in the broswer?
That's a very cool idea. I wonder if this could be integrated with the Catagolue browser extension (which I really should put on Github as well now that I have an account there) -- it would be a good fit, and the framework for handling Catagolue pages is already in place, so all that'd be left to do'd be piecing together the glider synthesis.

Note that this would likely require a copy of min_paths.txt to be included with the extension. Queries to arbitrary external web resources from browser extensions are thorny, and I've never tried to do something like that.
Note that the most "Golly-dependent" parts of my script are the bits that convert a still life on the screen to an apgcode. If you already have the apgcode then you can strip out all of the "canonise" and "get_period" functions and what is left is really not very complicated. The only calls to g.evolve are in display_synthesis and in get_gliders. The first is basically cosmetic and could be ignored, the second call is just used to advance a glider by 0,1,2 or 3 generations.

Does anyone have thoughts on this? Would it be feasible to port my display_synth script to Javascript and get everything running on the client-side? I have no experience with any kind of web-scripts.
Dealing with Catagolue pages, the apgcode's already known by definition, so any current dependence on Golly shouldn't be an issue. :)

Other than that -- this could also be implemented as a good ol' CGI script, right? I'm thinking something along the lines of Jason Summer's own Oscillizer here: a page somewhere where you can paste an object's RLE and/or apgcode, and receive a glider synthesis (glider count and synthesis RLE).

Upsides -- this could be done in any language, including Python, the dependency on Golly wouldn't be an issue (in principle anyway), it could more easily pull in updates to min_paths.txt, it would work for all browsers (the Catagolue extension is Opera-specific ATM), and it'd not be specific to Catagolue object pages.
If you speak, your speech must be better than your silence would have been. — Arabian proverb

Catagolue: Apple Bottom • Life Wiki: Apple Bottom • Twitter: @_AppleBottom_

Proud member of the Pattern Raiders!

User avatar
dvgrn
Moderator
Posts: 10670
Joined: May 17th, 2009, 11:00 pm
Location: Madison, WI
Contact:

Re: Finding still life articles with suboptimal syntheses

Post by dvgrn » January 9th, 2017, 4:39 pm

Apple Bottom wrote:
chris_c wrote:Thinking more ambitiously, maybe someone could write some Python/Javascript/Perl that looks at my min_paths.txt and converts an apgcode into a glider synthesis RLE directly in the browser?
That's a very cool idea. I wonder if this could be integrated with the Catagolue browser extension (which I really should put on Github as well now that I have an account there) -- it would be a good fit, and the framework for handling Catagolue pages is already in place, so all that'd be left to do'd be piecing together the glider synthesis.
Another option -- it might be worth asking Calcyman Adam if he'd have any interest in supporting something along these lines integrated into Catagolue.

The original vision for Catagolue included an online collection system for glider syntheses -- paste in RLE that's all gliders, with a lower count than the current record, and if the new recipe produces the same object then your name can be added to in the Record Cheapest Synthesis section, just like that.

-- Yes, the test would include rewinding all the gliders by some reasonable distance before running the pattern, but that's easy enough.

Anyway, it might be a reasonably small step toward that old Catagolue goal, to display a glider synthesis whenever one is known, maybe in LifeViewer...?

User avatar
BlinkerSpawn
Posts: 1992
Joined: November 8th, 2014, 8:48 pm
Location: Getting a snacker from R-Bee's

Re: Finding still life articles with suboptimal syntheses

Post by BlinkerSpawn » January 9th, 2017, 5:05 pm

Apple Bottom wrote:2. Save Chris C.'s still_list.txt file in a suitable directory.
...
5. Fix up all the articles it lists.
Bob Shemyakin recently posted a table comparing his results to those in Chris C.'s database and there's apparently quite a few syntheses for which even still_list.txt has a suboptimal synthesis.
Is it at all plausible (or even possible) to run comparisons from both Chris C.'s and Bob Shemyakin's lists?
LifeWiki: Like Wikipedia but with more spaceships. [citation needed]

Image

User avatar
Apple Bottom
Posts: 1034
Joined: July 27th, 2015, 2:06 pm
Contact:

Re: Finding still life articles with suboptimal syntheses

Post by Apple Bottom » January 9th, 2017, 5:08 pm

BlinkerSpawn wrote:Bob Shemyakin recently posted a table comparing his results to those in Chris C.'s database and there's apparently quite a few syntheses for which even still_list.txt has a suboptimal synthesis.
Is it at all plausible (or even possible) to run comparisons from both Chris C.'s and Bob Shemyakin's lists?
Absolutely. Just point me to Bob Shemyakin's file, and I'll tweak my above script to read that as well.
If you speak, your speech must be better than your silence would have been. — Arabian proverb

Catagolue: Apple Bottom • Life Wiki: Apple Bottom • Twitter: @_AppleBottom_

Proud member of the Pattern Raiders!

User avatar
dvgrn
Moderator
Posts: 10670
Joined: May 17th, 2009, 11:00 pm
Location: Madison, WI
Contact:

Re: Finding still life articles with suboptimal syntheses

Post by dvgrn » January 9th, 2017, 5:55 pm

Apple Bottom wrote:Absolutely. Just point me to Bob Shemyakin's file, and I'll tweak my above script to read that as well.
The summary table was just posted here, for 4 through 15 bits, with 16-bit objects planned to be added soon. Looks like if the sixth column is a positive number, that signals an improvement in Bob's collection over chris_c's current database.

There's a lot of cross-checking ongoing at the moment, especially in terms of finding ways to automatically build objects by incremental conversion, usually from a smaller number of bits to a slightly larger number. I think Mark Niemiec's expert system currently has the largest total number of conversion recipes for doing this kind of thing -- but Chris and Bob each have recipes that Mark doesn't, and vice versa, so they're all getting caught up.

Not sure which collection will turn out to be most accessible for integration with the LifeWiki. Seems like chris_c's repository is a fairly good bet, since it's out there on github and easy to update -- so maybe all you'll have to do is wait, and re-run your current script every now and then...

chris_c
Posts: 966
Joined: June 28th, 2014, 7:15 am

Re: Finding still life articles with suboptimal syntheses

Post by chris_c » January 9th, 2017, 6:02 pm

Apple Bottom wrote: Note that this would likely require a copy of min_paths.txt to be included with the extension. Queries to arbitrary external web resources from browser extensions are thorny, and I've never tried to do something like that.
Currently min_paths.txt is 430K but to just take care of objects that have pages on the wiki I am sure this could be reduced substantially.
Apple Bottom wrote: Other than that -- this could also be implemented as a good ol' CGI script, right? I'm thinking something along the lines of Jason Summer's own Oscillizer here: a page somewhere where you can paste an object's RLE and/or apgcode, and receive a glider synthesis (glider count and synthesis RLE).
Yeah something like that would work, especially if I got rid of the Golly dependence. Trouble is that I have zero experience of doing anything with a web server.
dvgrn wrote: The original vision for Catagolue included an online collection system for glider syntheses -- paste in RLE that's all gliders, with a lower count than the current record, and if the new recipe produces the same object then your name can be added to in the Record Cheapest Synthesis section, just like that.
I have code that already does this although it does depend on Golly. It doesn't require only gliders --- any initial constellation is fine providing that constellation is already known to be synthesisable or has a synthesis elsewhere in the RLE. I haven't had any trouble with the code in the last couple of months so I suppose that means it's in a releasable state...

User avatar
dvgrn
Moderator
Posts: 10670
Joined: May 17th, 2009, 11:00 pm
Location: Madison, WI
Contact:

Re: Finding still life articles with suboptimal syntheses

Post by dvgrn » January 9th, 2017, 6:34 pm

chris_c wrote:
dvgrn wrote:The original vision for Catagolue included an online collection system for glider syntheses -- paste in RLE that's all gliders, with a lower count than the current record, and if the new recipe produces the same object then your name can be added to in the Record Cheapest Synthesis section, just like that.
I have code that already does this although it does depend on Golly. It doesn't require only gliders --- any initial constellation is fine providing that constellation is already known to be synthesisable or has a synthesis elsewhere in the RLE. I haven't had any trouble with the code in the last couple of months so I suppose that means it's in a releasable state...
For an online record-keeping system (no pun intended) it kind of seems simplest to require that the candidate recipes be all gliders. That would be just to make sure that no one can game the system by offering "new records" that are really just unstable predecessors of objects -- low in bit count, but probably not trivial to synthesize.

I suppose it would be fine to include single L/M/HWSSes from each direction, anyway, or anything that's easy to rewind and has a known cost with no sneaky exceptions.

User avatar
Apple Bottom
Posts: 1034
Joined: July 27th, 2015, 2:06 pm
Contact:

Re: Finding still life articles with suboptimal syntheses

Post by Apple Bottom » January 9th, 2017, 6:50 pm

dvgrn wrote:The summary table was just posted here, for 4 through 15 bits, with 16-bit objects planned to be added soon. Looks like if the sixth column is a positive number, that signals an improvement in Bob's collection over chris_c's current database.
Thanks. I've updated applebot.pl to read this data from a file (which should be called called "bob_shemyakin.txt") if it exists. Running the script has revealed that none of Bob's improvements over Chris's list (the copy of Chris's list that I have saved locally, not the older one that Bob's datafile is apparently based on, judging from Chris's comment over in the "15 in 15" thread) apply to patterns the LifeWiki has articles for, though.

As before, the code is on Github; alternatively here's the current version of the script:

Code: Select all

#!/usr/bin/perl

###############
### MODULES ###
###############

# preliminaries
use Modern::Perl '2014';
use English;
use utf8;		# script itself is in UTF-8

# core modules
use Getopt::Long;
use Term::ANSIColor	qw/:constants/;

# non-core modules
use Data::Dumper;	# for debugging
use File::Slurp;
use MediaWiki::Bot;
use PerlIO::Util;	# for ->push_layer on *STDOUT etc

##############################
### CONFIGURATION DEFAULTS ###
##############################

# run anonymously?
# NOTE: MediaWiki::Bot 5.006003 is unable to login to newer wikis, due to
# the module's lack of maintenance and the frequent and
# backwards-incompatible changes to the MediaWiki API.
our $be_anonymous	= 1;

# debugging level to be passed to MediaWiki::Bot (0, 1 or 2).
our $debug_level	= 0;

# filename for Chris C's still_list.txt; should be downloaded from 
# https://github.com/ceebo/glider_synth/blob/master/still_list.txt
our $still_list_txt	= "still_list.txt";

# filename for Bob Shemyakin's list; should be copied from
# http://conwaylife.com/forums/viewtopic.php?p=39164#p39164 (or a later post
# that contains an updated version.
our $bob_shemyakin_txt	= "bob_shemyakin.txt";

# category to fetch pages from; suggested values are "Strict still lifes" or
# "Still lifes".
our $category		= "Strict still lifes";

# username to use.
our $username		= "Apple Bot";

# password to use. Don't specify this here; pass it on the command line.
our $password		=> undef;

####################################################
### NO NEED TO CHANGE ANYTHING BEYOND THIS POINT ###
####################################################

# version and name
our $VERSION	= 0.01;
our $NAME	= "applebot.pl";

# we may dump debug info, in which case sorted hash keys would be nice.
$Data::Dumper::Sortkeys = 1;

# autoflush STDOUT
$OUTPUT_AUTOFLUSH = 1;

# also write console output to log file
*STDOUT->push_layer(tee => 'output.applebot.log');

# process options
GetOptions(
    "password|p=s"	=> \$password,
    "username|u=s"	=> \$username,
    "anonymous!"	=> \$be_anonymous,
    ) or usage();

# create a bot object we'll be using to operate
our $applebot = MediaWiki::Bot->new({
#    assert		=> 'bot',		# uncomment once Apple Bot has a bot flag on the wiki.
    operator		=> 'Apple Bottom',
#    protocol		=> 'https',		# does not currently work due to an invalid SSL certificate
    protocol		=> 'http',
    host		=> 'conwaylife.com',
    debug		=> $debug_level,
});

# call MAIN routine and exit
exit MAIN();

####################
### MAIN ROUTINE ###
####################

sub MAIN {

    my $starting_time = time;
    
    # introduce ourselves
    say "Howdy, this is ", BRIGHT_BLUE, $NAME, RESET, " v", BRIGHT_WHITE, $VERSION, RESET;
    say "Starting up at ", BRIGHT_WHITE, scalar localtime($starting_time), RESET, ".";

    # make sure Chris C's datafile exist.  We can live without Bob
    # Shemyakin's, but this one is essential for now.
    -e $still_list_txt
        or die "$still_list_txt not found.";
    
    # this hash will hold information on our objects.
    my $objects = {};
    
    # read Chris C.'s list
    print "Reading Chris C.'s list... ";
    my @ceebo_lines = read_file($still_list_txt);

    # process Chris C.'s list
    foreach my $ceebo_line (@ceebo_lines) {
    
        # split line into object number (e.g.  4.1), apgcode (e.g.  xs4_33)
        # and glider count (e.g.  2)
        my ($number, $apgcode, $synthesis) = split /\s+/, $ceebo_line;
        
        # record this object in our objects hash.
        $objects->{$apgcode} = {
            'number'		=> $number,
            'ceebo_synthesis'	=> $synthesis,
        };

    }
    
    say GREEN, "done", RESET, " (", BRIGHT_WHITE, (scalar @ceebo_lines), RESET, " lines read)";
    
    # read Bob Shemyakin's list, if found
    if(-e $bob_shemyakin_txt) {
    
        print "Reading Bob Shemyakin's list... ";
        my @bob_lines = read_file($bob_shemyakin_txt);
        
        # the first line is a header line; ignore that.
        shift @bob_lines;
        
        # Bob Shemyakin does not list apgcodes, so we construct a temporary
        # helper hash converting object numbers to codes.
        my %number2code = map {
            $objects->{$_}->{'number'} => $_
        } keys %$objects;
        
        # process Bob Shemyakin's list
        foreach my $bob_line (@bob_lines) {
        
            # split line into fields
            my ($overall_number, $bits, $bits_number, $chris_gliders, $bob_gliders, $delta_g) = split /\s+/, $bob_line;
            
            # this is the number we're interested in.
            my $number = "${bits}.${bits_number}";
            
            if(exists $number2code{$number}) {
                # we have an apgcode.
                $objects->{$number2code{$number}}->{'bob_synthesis'} = $bob_gliders;
            
            } else {
                # this shouldn't happen.
                warn "Could not identify object from Bob Shemyakin's list: $bob_line";
            
            }
        }
        
        say GREEN, "done", RESET, " (", BRIGHT_WHITE, (scalar @bob_lines), RESET, " lines read)";
    }
    
    # debugging: dump our object hash.
    debug_dump($objects);
    
    # log in to the wiki
    unless($be_anonymous) {
    
        # make sure user provided username and password.
        if(($username // "") eq "" or ($password // "") eq "") {
            die "No username/password specified!";
        }
    
        print "Logging in to the LifeWiki as ", BRIGHT_WHITE, $username, RESET, "... ";
        $applebot->login({
                username	=> "Apple Bot",
                password	=> "",
            }) or die "Login failed";
        say GREEN, "done", RESET;
        
    }

    # get list of page titles        
    print "Getting list of wiki pages... ";
    my @page_titles = $applebot->get_pages_in_category(
        "Category:$category",
        {
            max	=> 0,	# return all results
        }
    );
    say GREEN, "done", RESET, " (", BRIGHT_WHITE, (scalar @page_titles), RESET, " articles found)";
    
    foreach my $page_title (@page_titles) {
    
        # get page text
        print "Getting wikitext for ${page_title}... ";
        my $wikitext = $applebot->get_text($page_title);
        
        # this could conceivably happen if a page gets deleted after we
        # fetched the list of page titles.
        unless(defined $wikitext) {
            say BRIGHT_RED, "page does not exist!";
            next;
        }
        
        say GREEN, "done", RESET;
        
        # apgcode and synthesis
        my $apgcode	= undef;
        my $synthesis	= undef;
        
        # attempt to extract glider synthesis
        if($wikitext =~ m/synthesis\s*=\s*([^\s\|]+)/g) {
            $synthesis = $1;
            
#            say "\tSynthesis: ", BRIGHT_WHITE, $synthesis, RESET;
#        } else {
#            say "\tNo synthesis found";
        }
        
        # attempt to extract apgcode
        if($wikitext =~ m/\{\{LinkCatagolue\|[^\}]*(xs(\d+)_([0-9a-z]+))/g) {
            $apgcode = $1;
        
#            say "\tapgcode: ", BRIGHT_WHITE, $apgcode, RESET;
#        } else {
#            say "\tNo apgcode found";
        }
        
        # did we extract an apgcode?
        if(defined $apgcode) {
        
            # yes; remember page title and synthesis count
            $objects->{$apgcode}->{'page_title'}	= $page_title;
            $objects->{$apgcode}->{'wiki_synthesis'}	= $synthesis;
            
        }
        
    }
    
    # Find objects we could improve (sorted by page title, only taking into
    # account objects that are on the wiki in the first place).
    foreach my $apgcode (sort { $objects->{$a}->{'page_title'} cmp $objects->{$b}->{'page_title'} } grep { exists $objects->{$_}->{'page_title'} } keys %$objects) {

        # if we have the wiki_synthesis (sub)hash key, the object was found
        # on the wiki (but the associated value may be undefined if no
        # glider synthesis count was extracted).  Same for Chris C.'s
        # synthesis.
        if(exists $objects->{$apgcode}->{'wiki_synthesis'} and exists $objects->{$apgcode}->{'ceebo_synthesis'}) {
        
            # extract synthesis counts, for convenience
            my ($wiki_synthesis, $ceebo_synthesis, $bob_synthesis, $page_title) = 
                map { 
                    $objects->{$apgcode}->{$_} 
                } ("wiki_synthesis", "ceebo_synthesis", "bob_synthesis", "page_title");
                
            # is the object without a listed synthesis on the wiki?
            if(not defined $wiki_synthesis) {
            
                if(defined $bob_synthesis and $bob_synthesis < $ceebo_synthesis) {
                    say BRIGHT_WHITE, $page_title, RESET, " has no synthesis on the wiki, but a ", BRIGHT_WHITE, $bob_synthesis, RESET, " glider synthesis in Bob Shemyakin's list.";
                } else {
                    say BRIGHT_WHITE, $page_title, RESET, " has no synthesis on the wiki, but a ", BRIGHT_WHITE, $ceebo_synthesis, RESET, " glider synthesis in Chris C.'s list.";
                }
            
            # or is the wiki synthesis worse than Chris C.'s?
            } elsif($wiki_synthesis > $ceebo_synthesis or $wiki_synthesis > ($bob_synthesis // 999999)) {
                if(defined $bob_synthesis and $bob_synthesis < $ceebo_synthesis) {
                    say BRIGHT_WHITE, $page_title, RESET, " has a ", BRIGHT_WHITE, $wiki_synthesis, RESET, " glider synthesis on the wiki, but a ", , BRIGHT_WHITE, $bob_synthesis, RESET, " glider synthesis in Bob Shemyakin's list.";
                } else {
                    say BRIGHT_WHITE, $page_title, RESET, " has a ", BRIGHT_WHITE, $wiki_synthesis, RESET, " glider synthesis on the wiki, but a ", , BRIGHT_WHITE, $ceebo_synthesis, RESET, " glider synthesis in Chris C.'s list.";
                }
            
                
            }
        
        }
            
    }
        
    # log out of the wiki
    unless($be_anonymous) {

        print "Logging out... ";        
        $applebot->logout();
        say GREEN, "done", RESET;    
        
    }
    
    # say goodbye
    say "Finished at ", BRIGHT_WHITE, scalar localtime(time), RESET, ".";
    
    # success!
    return 0;
}

###################
### SUBROUTINES ###
###################

# print usage information
sub usage {
    print <<ENDOFUSAGE;
Usage: $0 [options]
Options:
    --anonymous             Do not login (default). Negate with --no-anonymous.
    --username=<...>        Use specified username for logging in.
    --password=<...>        Use specified password for logging in.
ENDOFUSAGE

    exit 1;
}

# dump some data to our debug dump file
sub debug_dump {

    # file handle state variable
    state $DUMPER_FILE;
    
    # try to open file, if necessary
    unless(defined $DUMPER_FILE) {
    
        # we actually genuinely don't care if this fails. If it doesn't, the
        # dump won't get logged, and we'll try to open the file again next
        # time.  Of course it's not ideal if the dump doesn't get logged,
        # but what alternative is there, really?
        open $DUMPER_FILE, ">", "dumper.txt";
    }
    
    # if the file is open, log our dump. If the open failed, the dump will
    # silently be "dumped", no pun intended.  Since this is just logging
    # this isn't a big deal, and there's not much we can do anyway.
    if(defined $DUMPER_FILE) {
        say $DUMPER_FILE Data::Dumper::Dumper(@_);
    }
    
    # note that the dump file never gets closed explicitely in this entire
    # script.
}
Not sure which collection will turn out to be most accessible for integration with the LifeWiki. Seems like chris_c's repository is a fairly good bet, since it's out there on github and easy to update -- so maybe all you'll have to do is wait, and re-run your current script every now and then...
That's easy enough to do -- and I'm thinking about giving the script the ability to pull in a current copy of Chris's data from Github when told to do so.
chris_c wrote:Currently min_paths.txt is 430K but to just take care of objects that have pages on the wiki I am sure this could be reduced substantially.
That's OK, 430k isn't actually so bad. (Famous last words -- next thing I know I'll find out Opera imposes strict limits on the amount of RAM extensions can use, or some such thing.)
chris_c wrote:Yeah something like that would work, especially if I got rid of the Golly dependence. Trouble is that I have zero experience of doing anything with a web server.
Neither do I, I'm afraid, and I also have no place to host such a thing. I'm tempted to say it would be a good fit for conwaylife.com, though, so if anyone feels like writing such a tool, I'm sure Nathaniel could be talked into hosting it.
If you speak, your speech must be better than your silence would have been. — Arabian proverb

Catagolue: Apple Bottom • Life Wiki: Apple Bottom • Twitter: @_AppleBottom_

Proud member of the Pattern Raiders!

chris_c
Posts: 966
Joined: June 28th, 2014, 7:15 am

Re: Finding still life articles with suboptimal syntheses

Post by chris_c » January 10th, 2017, 2:51 pm

I put some html that knows how to synthesise any still life up to 12 bits here.

You need to add a hash and an apgcode to the end to tell it what to display and apparently you need to prepend with "htmlpreview.github.io?" in order to make github display it as real HTML instead of just some text.

For example this should give a beehive synthesis with any luck.

When I change the apgcode and hit refresh I get a new RLE, at least in my browser.

User avatar
dvgrn
Moderator
Posts: 10670
Joined: May 17th, 2009, 11:00 pm
Location: Madison, WI
Contact:

Re: Finding still life articles with suboptimal syntheses

Post by dvgrn » January 10th, 2017, 6:38 pm

chris_c wrote:I put some html that knows how to synthesise any still life up to 12 bits here...
Nice! Want to try putting the RLE into a LifeViewer instance?

A few months ago I found I was able to add LifeViewer to my b3s23life weblog without too many problems (though there are a few minor glitches with multiple LifeViewers, that I haven't taken the time to figure out yet.)

chris_c
Posts: 966
Joined: June 28th, 2014, 7:15 am

Re: Finding still life articles with suboptimal syntheses

Post by chris_c » January 11th, 2017, 2:39 pm

dvgrn wrote: Nice! Want to try putting the RLE into a LifeViewer instance?
Good idea! I managed to get it working once I loaded the lv-plugin in the body of the html. Otherwise I think Life Viewer was running before the RLE in the codebox had been written.

I put the pages up on glidersynth.neocities.org. For example:

http://glidersynth.neocities.org/#xs4_33

You need to edit the apgcode and hit refresh to get a new still life. Hopefully it works up to 12 bit.

User avatar
dvgrn
Moderator
Posts: 10670
Joined: May 17th, 2009, 11:00 pm
Location: Madison, WI
Contact:

Re: Finding still life articles with suboptimal syntheses

Post by dvgrn » January 11th, 2017, 6:13 pm

chris_c wrote:I put the pages up on glidersynth.neocities.org. For example:

http://glidersynth.neocities.org/#xs4_33

You need to edit the apgcode and hit refresh to get a new still life. Hopefully it works up to 12 bit.
Seems to work like a charm on the random-sample 12-bitters I tried out. The only caveat was that at least on Google Chrome, I couldn't just paste in a different apgcode and hit [Enter] -- maybe because it tried first to find the named anchor #{newapgcode} in the existing HTML, rather than doing whatever you're doing to generate new HTML. A second [Enter] or a refresh definitely does the trick.

There are various options that could be added like #C [[ AUTOSTART LOOP 500 ]] (or some more appropriate restart time) and possibly AUTOFIT -- but maybe it's best to keep things simple. It's nice that you get the click-to-select-the-RLE functionality for free with the LifeViewer.

chris_c
Posts: 966
Joined: June 28th, 2014, 7:15 am

Re: Finding still life articles with suboptimal syntheses

Post by chris_c » January 11th, 2017, 7:29 pm

dvgrn wrote: Seems to work like a charm on the random-sample 12-bitters I tried out. The only caveat was that at least on Google Chrome, I couldn't just paste in a different apgcode and hit [Enter] -- maybe because it tried first to find the named anchor #{newapgcode} in the existing HTML, rather than doing whatever you're doing to generate new HTML. A second [Enter] or a refresh definitely does the trick.
This was just complete lack of knowledge on my part. I never knew that the "?" that commonly appears in URLs was a dedicated part of the syntax. I only knew about "#" so that's what I used. Instead I made the javascript look for "?" and now things like http://glidersynth.neocities.org/?xp2_7 seem to work as well as can be expected.

EDIT: by the way, to get the "click to select rle" functionality I had to copy the function "selectCode" from forum_fn.js on these forums. Hope that's ok :)

mniemiec
Posts: 1590
Joined: June 1st, 2013, 12:00 am

Re: Finding still life articles with suboptimal syntheses

Post by mniemiec » January 11th, 2017, 8:48 pm

chris_c wrote:now things like http://glidersynth.neocities.org/?xp2_7 seem to work as well as can be expected.
Nice! I had thought this was about still-lifes, but it seems to include other things. What is this page's scope supposed to be?

chris_c
Posts: 966
Joined: June 28th, 2014, 7:15 am

Re: Finding still life articles with suboptimal syntheses

Post by chris_c » January 12th, 2017, 7:56 am

mniemiec wrote:
chris_c wrote:now things like http://glidersynth.neocities.org/?xp2_7 seem to work as well as can be expected.
Nice! I had thought this was about still-lifes, but it seems to include other things. What is this page's scope supposed to be?
The strings that define a glider synthesis are of the form <input_apgcode>;<output_apgcode>;<glider_synthesis_data>. The input and output apgcodes can be any stable or oscillating pattern. Locally I have a rather large file consisting of all such strings that my analysis system has ever produced. Many of these will be from older syntheses that are no longer records. After this I have a have a program (basically it runs dijkstra's algorithm) that decides which objects are "targeted" and only outputs optimal recipes for those objects and any objects that those objects depend on.

For my large file of of paths here the set of targeted objects was any still life of 16-bits or less. The file is 430K. For the strings at the end of the javascript file here I only decided to target still lifes of 12-bit or less just to make the file smaller. Even though the targets are still lifes in both cases there can be oscillators or psedo-still lifes in the file if the object happens to be on an optimal path between the empty universe and some targeted still life. This happens to be true for the blinker. Probably it is true for other small oscillators such as traffic light, toad, beacon, etc... although I haven't checked.

User avatar
Apple Bottom
Posts: 1034
Joined: July 27th, 2015, 2:06 pm
Contact:

Re: Finding still life articles with suboptimal syntheses

Post by Apple Bottom » January 14th, 2017, 4:08 pm

Bob Shemyakin posted a list for 16-bitters, so I modified applebot.pl to also read that.

Code's on Github, or below:

Code: Select all

#!/usr/bin/perl

###############
### MODULES ###
###############

# preliminaries
use Modern::Perl '2014';
use English;
use utf8;		# script itself is in UTF-8

# core modules
use Getopt::Long;
use List::Util		qw/min/;
use Term::ANSIColor	qw/:constants/;

# non-core modules
use Data::Dumper;	# for debugging
use File::Slurp;
use MediaWiki::Bot;
use PerlIO::Util;	# for ->push_layer on *STDOUT etc

##############################
### CONFIGURATION DEFAULTS ###
##############################

# run anonymously?
# NOTE: MediaWiki::Bot 5.006003 is unable to login to newer wikis, due to
# the module's lack of maintenance and the frequent and
# backwards-incompatible changes to the MediaWiki API.
our $be_anonymous	= 1;

# debugging level to be passed to MediaWiki::Bot (0, 1 or 2).
our $debug_level	= 0;

# filename for Chris C's still_list.txt; should be downloaded from 
# https://github.com/ceebo/glider_synth/blob/master/still_list.txt
our $still_list_txt	= "still_list.txt";

# filename for Bob Shemyakin's list; should be copied from
# http://conwaylife.com/forums/viewtopic.php?p=39164#p39164 (or a later post
# that contains an updated version).
our $bob_shemyakin_txt	= "bob_shemyakin.txt";

# filename for Bob Shemyakin's 16-bit list; should be copied from
# http://conwaylife.com/forums/viewtopic.php?p=39299#p39299 (or a later post
# that contains an updated version).
our $still16_txt	= "still16.txt";

# category to fetch pages from; suggested values are "Strict still lifes" or
# "Still lifes".
our $category		= "Strict still lifes";

# username to use.
our $username		= "Apple Bot";

# password to use. Don't specify this here; pass it on the command line.
our $password		=> undef;

####################################################
### NO NEED TO CHANGE ANYTHING BEYOND THIS POINT ###
####################################################

# version and name
our $VERSION	= 0.01;
our $NAME	= "applebot.pl";

# we may dump debug info, in which case sorted hash keys would be nice.
$Data::Dumper::Sortkeys = 1;

# autoflush STDOUT
$OUTPUT_AUTOFLUSH = 1;

# also write console output to log file
*STDOUT->push_layer(tee => 'output.applebot.log');

# process options
GetOptions(
    "password|p=s"	=> \$password,
    "username|u=s"	=> \$username,
    "anonymous!"	=> \$be_anonymous,
    ) or usage();

# create a bot object we'll be using to operate
our $applebot = MediaWiki::Bot->new({
#    assert		=> 'bot',		# uncomment once Apple Bot has a bot flag on the wiki.
    operator		=> 'Apple Bottom',
#    protocol		=> 'https',		# does not currently work due to an invalid SSL certificate
    protocol		=> 'http',
    host		=> 'conwaylife.com',
    debug		=> $debug_level,
});

# call MAIN routine and exit
exit MAIN();

####################
### MAIN ROUTINE ###
####################

sub MAIN {

    my $starting_time = time;
    
    # introduce ourselves
    say "Howdy, this is ", BRIGHT_BLUE, $NAME, RESET, " v", BRIGHT_WHITE, $VERSION, RESET;
    say "Starting up at ", BRIGHT_WHITE, scalar localtime($starting_time), RESET, ".";

    # make sure Chris C's datafile exist.  We can live without Bob
    # Shemyakin's, but this one is essential for now.
    -e $still_list_txt
        or die "$still_list_txt not found.";
    
    # this hash will hold information on our objects.
    my $objects = {};
    
    # read Chris C.'s list
    print "Reading Chris C.'s list... ";
    my @ceebo_lines = read_file($still_list_txt);

    # process Chris C.'s list
    foreach my $ceebo_line (@ceebo_lines) {
    
        # split line into object number (e.g.  4.1), apgcode (e.g.  xs4_33)
        # and glider count (e.g.  2)
        my ($number, $apgcode, $synthesis) = split /\s+/, $ceebo_line;
        
        # record this object in our objects hash.
        $objects->{$apgcode} = {
            'number'		=> $number,
            'ceebo_synthesis'	=> $synthesis,
        };

    }
    
    say GREEN, "done", RESET, " (", BRIGHT_WHITE, (scalar @ceebo_lines), RESET, " lines read)";
    
    # Bob Shemyakin does not list apgcodes, so we construct a temporary
    # helper hash converting object numbers to codes.
    my %number2code = map {
        $objects->{$_}->{'number'} => $_
    } keys %$objects;
        
    # read Bob Shemyakin's list, if found
    if(-e $bob_shemyakin_txt) {
    
        print "Reading Bob Shemyakin's list... ";
        my @bob_lines = read_file($bob_shemyakin_txt);
        
        # the first line is a header line; ignore that.
        shift @bob_lines;
        
        # process Bob Shemyakin's list
        foreach my $bob_line (@bob_lines) {
        
            # split line into fields
            my ($overall_number, $bits, $bits_number, $chris_gliders, $bob_gliders, $delta_g) = split /\s+/, $bob_line;
            
            # this is the number we're interested in.
            my $number = "${bits}.${bits_number}";
            
            if(exists $number2code{$number}) {
                # we have an apgcode.
                $objects->{$number2code{$number}}->{'bob_synthesis'} = $bob_gliders;
            
            } else {
                # this shouldn't happen.
                warn "Could not identify object from Bob Shemyakin's list: $bob_line";
            
            }
        }
        
        say GREEN, "done", RESET, " (", BRIGHT_WHITE, (scalar @bob_lines), RESET, " lines read)";
    }
    
    # read Bob Shemyakin's still16.txt list, if found
    if(-e $still16_txt) {
    
        print "Reading Bob Shemyakin's 16-bit list... ";
        my @bob_lines = read_file($still16_txt);
        
        # the first line is a header line; ignore that.
        shift @bob_lines;
        
        # process Bob Shemyakin's list
        foreach my $bob_line (@bob_lines) {
        
            # split line into fields
            my ($bits, $bits_number, $bob_gliders) = split /\s+/, $bob_line;
            
            # "999 gliders" indicates no synthesis.
            next if $bob_gliders == 999;
            
            # this is the number we're interested in.
            my $number = "${bits}.${bits_number}";
            
            if(exists $number2code{$number}) {
                # we have an apgcode.
                $objects->{$number2code{$number}}->{'bob2_synthesis'} = $bob_gliders;
            
            } else {
                # this shouldn't happen.
                warn "Could not identify object from Bob Shemyakin's still16.txt list: $bob_line";
            
            }
        }
        
        say GREEN, "done", RESET, " (", BRIGHT_WHITE, (scalar @bob_lines), RESET, " lines read)";
    }
    
    # debugging: dump our object hash.
    debug_dump($objects);
    
    # log in to the wiki
    unless($be_anonymous) {
    
        # make sure user provided username and password.
        if(($username // "") eq "" or ($password // "") eq "") {
            die "No username/password specified!";
        }
    
        print "Logging in to the LifeWiki as ", BRIGHT_WHITE, $username, RESET, "... ";
        $applebot->login({
                username	=> "Apple Bot",
                password	=> "",
            }) or die "Login failed";
        say GREEN, "done", RESET;
        
    }

    # get list of page titles        
    print "Getting list of wiki pages... ";
    my @page_titles = $applebot->get_pages_in_category(
        "Category:$category",
        {
            max	=> 0,	# return all results
        }
    );
    say GREEN, "done", RESET, " (", BRIGHT_WHITE, (scalar @page_titles), RESET, " articles found)";
    
    foreach my $page_title (@page_titles) {
    
        # get page text
        print "Getting wikitext for ${page_title}... ";
        my $wikitext = $applebot->get_text($page_title);
        
        # this could conceivably happen if a page gets deleted after we
        # fetched the list of page titles.
        unless(defined $wikitext) {
            say BRIGHT_RED, "page does not exist!";
            next;
        }
        
        say GREEN, "done", RESET;
        
        # apgcode and synthesis
        my $apgcode	= undef;
        my $synthesis	= undef;
        
        # attempt to extract glider synthesis
        if($wikitext =~ m/synthesis\s*=\s*([^\s\|]+)/g) {
            $synthesis = $1;
            
#            say "\tSynthesis: ", BRIGHT_WHITE, $synthesis, RESET;
#        } else {
#            say "\tNo synthesis found";
        }
        
        # attempt to extract apgcode
        if($wikitext =~ m/\{\{LinkCatagolue\|[^\}]*(xs(\d+)_([0-9a-z]+))/g) {
            $apgcode = $1;
        
#            say "\tapgcode: ", BRIGHT_WHITE, $apgcode, RESET;
#        } else {
#            say "\tNo apgcode found";
        }
        
        # did we extract an apgcode?
        if(defined $apgcode) {
        
            # yes; remember page title and synthesis count
            $objects->{$apgcode}->{'page_title'}	= $page_title;
            $objects->{$apgcode}->{'wiki_synthesis'}	= $synthesis;
            
        }
        
    }
    
    say "Wiki         | Chris        | Bob          | Bob (16 bit) | Pattern";
    say "-------------+--------------+--------------+--------------+--------------";
    
    # Find objects we could improve (sorted by page title, only taking into
    # account objects that are on the wiki in the first place).
    foreach my $apgcode (sort { $objects->{$a}->{'page_title'} cmp $objects->{$b}->{'page_title'} } grep { exists $objects->{$_}->{'page_title'} } keys %$objects) {

        # if we have the wiki_synthesis (sub)hash key, the object was found
        # on the wiki (but the associated value may be undefined if no
        # glider synthesis count was extracted).  Same for Chris C.'s
        # synthesis.
        if(exists $objects->{$apgcode}->{'wiki_synthesis'}) {
        
            # extract synthesis counts, for convenience
            my ($wiki, $ceebo, $bob, $bob2, $page_title) = 
                map { 
                    $objects->{$apgcode}->{$_} 
                } ("wiki_synthesis", "ceebo_synthesis", "bob_synthesis", "bob2_synthesis", "page_title");
                
            # best synthesis in Chris's and Bob's files
            my $best = min ($ceebo // 999999, $bob // 999999, $bob2 // 999999);
            
            # skip patterns not on any list.
            next if $best == 999999;
            
            # is the wiki synthesis suboptimal?
            if(!defined $wiki or $best < $wiki) {
            
                # formatted values for prniting.
                my $wiki_p  = (defined $wiki)  ? sprintf("%12d", $wiki ) : "           -";
                my $ceebo_p = (defined $ceebo) ? sprintf("%12d", $ceebo) : "           -";
                my $bob_p   = (defined $bob)   ? sprintf("%12d", $bob  ) : "           -";
                my $bob2_p  = (defined $bob2)  ? sprintf("%12d", $bob2 ) : "           -";
            
                print $wiki_p;
                print " | ";
                print BOLD if ($ceebo // 999999) == $best;
                print $ceebo_p;
                print RESET;
                print " | ";
                print BOLD if ($bob   // 999999) == $best;
                print $bob_p;
                print RESET;
                print " | ";
                print BOLD if ($bob2  // 999999) == $best;
                print $bob2_p;
                print RESET;
                print " | ";
                say   $page_title;
            }
                
        }
            
    }
        
    # log out of the wiki
    unless($be_anonymous) {

        print "Logging out... ";        
        $applebot->logout();
        say GREEN, "done", RESET;    
        
    }
    
    # say goodbye
    say "Finished at ", BRIGHT_WHITE, scalar localtime(time), RESET, ".";
    
    # success!
    return 0;
}

###################
### SUBROUTINES ###
###################

# print usage information
sub usage {
    print <<ENDOFUSAGE;
Usage: $0 [options]

Options:

    --anonymous             Do not login (default). Negate with --no-anonymous.
    --username=<...>        Use specified username for logging in.
    --password=<...>        Use specified password for logging in.

ENDOFUSAGE

    exit 1;
}

# dump some data to our debug dump file
sub debug_dump {

    # file handle state variable
    state $DUMPER_FILE;
    
    # try to open file, if necessary
    unless(defined $DUMPER_FILE) {
    
        # we actually genuinely don't care if this fails. If it doesn't, the
        # dump won't get logged, and we'll try to open the file again next
        # time.  Of course it's not ideal if the dump doesn't get logged,
        # but what alternative is there, really?
        open $DUMPER_FILE, ">", "dumper.txt";
    }
    
    # if the file is open, log our dump. If the open failed, the dump will
    # silently be "dumped", no pun intended.  Since this is just logging
    # this isn't a big deal, and there's not much we can do anyway.
    if(defined $DUMPER_FILE) {
        say $DUMPER_FILE Data::Dumper::Dumper(@_);
    }
    
    # note that the dump file never gets closed explicitely in this entire
    # script.
}
I've also changed the output to a tabular format -- should make it easier for the user, and will also allow adding more data sources more easily.
If you speak, your speech must be better than your silence would have been. — Arabian proverb

Catagolue: Apple Bottom • Life Wiki: Apple Bottom • Twitter: @_AppleBottom_

Proud member of the Pattern Raiders!

Post Reply