MindPerformanceHacks 2fForceYourConnections

Hack #20: Force Your Connections

Use a simple process to generate many complex ideas quickly from a limited pool of simple ideas.

Additions and Suggestions

Tracy Atteberry <Tracy@magicbydesign.com> submitted an improved version of pyro in March 2007, writing:

Hi Ron,

I just received your book "Mind Performance Hacks" yesterday and I'm thoroughly enjoying it. Thanks!

I made a few changes to your pyro script that I thought you might like to know about. Other people have probably mailed in similar changes, but just in case they haven't I've attached the revised script. Some of the changes include:

The script worked very well as provided but I found these changes personally useful. See attached file for full details.

Cheers, Tracy Atteberry

PS. My first use of the script was to generate characters, motivations, effects, and complete acts for a magic performance. Very fun!

Thanks, Tracy! The new script works beautifully! I'm using it to generate possible titles for my new book.

Here's the improved code listing. You can also download the script.

-- Ron Hale-Evans [[DateTime?(2007-06-06T22:53:29Z)]]

#!/usr/bin/perl -w

# #######################################################################
#
# Pyro
#
#  The original version of this script is from the book "Mind Performance
#  Hacks" written by Ron Hale-Evans and published by O'Reilly Media.  It
#  was written to perform random nested substitutions to promote creative
#  thought.  Here is Ron's description:
#
#  The pyro script is so named because it is the indirect descendant of a
#  HyperCard stack called Inspirograph, and because while I was writing
#  it, I was reminded of the Creative Fire of the Stoics, and also
#  because it allows "expyration" (breathing out every possible
#  permutation of the data in a file) as well as "inspyration" (breathing
#  in a few permutations and allowing them to inspire you). It occurs in
#  Hack #20, "Force Your Connections" and Hack #49, "Roll the Dice".
#
#  - Ron Hale-Evans
#
#  This script was subsequently hacked and updated by Tracy Atteberry as
#  follows:
#
#  * Usage notes are now printed when script is run without parameters
#  * Eliminated the use of the temporary file
#  * Fixed small bug involving inconsistent regexes
#  * Allow user to specify number of permutations to generate
#  * Write full "expyrations" to specified output file
#
# #######################################################################


# if we don't have at least two argument then print usage notes and bail
if ($#ARGV + 1 < 2)
{
   &usage();
   exit;
}

my $infilename = $ARGV[0];
my $basevar = "\@$ARGV[1]\@";
my $writetofile = 0;
my $quantity = 1;
if ($ARGV[2])
{
    # if the argument is numeric we use it for the quantity
    if ($ARGV[2] =~ /^\d+$/)
    {
        $quantity = $ARGV[2];
    }
    # otherwise we'll write out to a file by this name
    else
    {
       $writetofile = $ARGV[2];
    }
}

for ($i=0; $i < $quantity; $i++)
{
    my $output = &generateOutput($infilename, $basevar, $writetofile);
    print $output;
}

sub generateOutput
{
    my ($infilename, $basevar, $writetofile) = @_;

    # Seed the output file
    if ($writetofile)
    {
        open(OUTFILE, "> $writetofile")
        or die "Couldn't open $writetofile for writing: $!\n";
        print OUTFILE "$basevar\n";
        close(OUTFILE);
    }

    local $/;
    undef $/;

    open(INFILE, "< $infilename")
    or die "Couldn't open $infilename for reading: $!\n";
    $infilecontents = <INFILE>; 
    close(INFILE);

    $outfilecontents = "$basevar\n";
    if ($writetofile)
    {
        open(OUTFILE, "< $writetofile")
        or die "Couldn't open $writetofile for reading: $!\n";
        $outfilecontents = <OUTFILE>;
        close(OUTFILE);
    }

    # changed this from /\@[A-Za-z0-9]+\@/ to match the regex used below
    while ($outfilecontents =~ /\@\w+\@/)
    {
        local $/;
        undef $/;

        if ($writetofile)
        {
            open(OUTFILE, "< $writetofile")
            or die "Couldn't open $writetofile for reading: $!\n";
            $outfilecontents = <OUTFILE>;
            close(OUTFILE);
        }

        # $baseline is the first line in OUTFILE with a variable.
        if ($outfilecontents =~ /^(.*?)(\@\w+\@)(.*?)$/m)
        {
            $baseline = "$1$2$3";
            $varname=$2;
        }
        chomp $varname;

        if ($infilecontents =~ /\#$varname\n(.*?)\n\n/s)
        {
            $varblock = "$1\n";
        }
        else
        {
            die "Did not find variable $varname in $infilename.\n";
        }

        @varblockarr = split (/\n/, $varblock);
        @outlinesarr = ();

        if (!$writetofile)
        {
            # Generate a random string from the input elements
            $randline = $varblockarr [ rand @varblockarr ];
            $curline = $baseline;
            chomp ($curline);
            chomp ($randline);
            $curline =~ s/$varname/$randline/;
            push (@outlinesarr, $curline);
        }
        else
        {
            # Generate all possible combinations of the input elements
            foreach $varline (@varblockarr)
            {
                $curline = $baseline;
                chomp ($curline);
                chomp ($varline);
                $curline =~ s/$varname/$varline/;
                push (@outlinesarr, $curline);
            }
        }

        $outlines = join ("\n", @outlinesarr);
        $outfilecontents =~ s/\Q$baseline\E/$outlines/s
                          or die "baseline not found.\n";
        $outfilecontents =~ s/\n\n/\n/mg;
        if ($writetofile)
        {
            open(OUTFILE, "> $writetofile")
            or die "Couldn't open $writetofile for writing: $!\n";
            print OUTFILE $outfilecontents;
            close(OUTFILE);
        }
    }

    if ($writetofile)
    {
       $outfilecontents = "Done... check \"$writetofile\" for output.\n";
    }

    return $outfilecontents;
}

sub usage
{
   print <<EOF;

   Usage: pyro datafile varname [number | filename]

   datafile   - data file to use as input
   varname    - data file variable to start with
   number     - specifies the number of outputs desired (defaults to 1)
   filename   - if given will generate all possible outputs to filename

   Examples:

      # generate and show two places
      \$ perl pyro utopia.dat place 2

      # generate all possible places and put in file all.txt
      \$ perl pyro utopia.dat place all.txt

      # more examples
      \$ perl pyro utopia.dat place
      \$ perl pyro utopia.dat place all.txt
      \$ perl pyro whattodo.dat activity 20
      \$ perl pyro whattodo.dat funhome
      \$ perl pyro whattodo.dat funout

EOF
}

Windows users will probably need to change the (Unix-based) path of the output file in the pyro script. For example, assuming the directory "C:\temp" exists on your system, open the pyro script in a text editor and change "/tmp/pyro.txt" (in line 11) to "C:/temp/pyro.txt". Note that a forward slash, not a backslash, is used after the drive designation.

Links

Errata

Errata go here.

Hack Author

Ron Hale-Evans

Return to Main Book Page

This is a page for a hack from the book MindPerformanceHacks by Ron Hale-Evans.