#!/usr/bin/perl
#
# ABOUT:
# ca.pl can be used to make the simple the cellular automata output
# from Stephen Wolfram's book "A New Kind of science", pages 51 - 59.
# No need for mathematica, "only" for Perl ;)
#
# VERSION:
# 1.0
# 
# COPYRIGHT:
# Copyright 2002 by Andreas Hauser, hauser@informatik.uni-muenchen.de
# 
# DISCLAIMER:
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# LICENSE:
# Use and distribution of this script is only allowed
# under Perl's ARTISTIC LICENSE, the BSD LICENSE.
# For the fulltext of these licenses see:
# http://www.cip.informtik.uni-muenchen.de/~hauser/licenses/
#

use strict;

unless(@ARGV)
{
    print <<EOF;
    Usage:
    $0 RULENUMBER [WIDTH [HEIGHT]]

    Where RULENUMBER is a value specified in decimal
    or bigendian binary between 0 and 255 or (00000000 and 11111111).

    And where WIDTH HEIGHT (if supplied) define the output size.
    As the default terminal size is 80x25,
    we use it as default if nothing other is specified.

    Examples:

    $0 110

    $0 30 80 25

    $0 00011110 1000 50

EOF
    exit;
}

my $rule    = shift;
my $width   = shift || 80;
my $height  = shift || 25;

# convert to binary representation
$rule = sprintf("%b",$rule) if(length($rule) < 4);
my @rule = reverse split(//,$rule);

my (@last_line,@line);
$line[$_] = 0 for(0..$width - 1);   # init line with zeros
$line[@line / 2] = 1;   # set initial black cell

## MAINLOOP ##

for my $iter (0..$height)
{
    lineprint(@line);
    @last_line = @line;
    @line = compute(\@last_line,\@line);
}

exit;


## SUBS ##

sub lineprint()
{
    foreach my $cell (@_)
    {
        print " " if($cell == 0);
        print "*" if($cell == 1);
    }
    print "\n";
}

sub compute()
{
    my @lastline = @{$_[0]};
    my @line = @{$_[1]};
    
    for my $i (1..@last_line - 1)
    {
        if(black(@last_line[$i - 1 .. $i + 1]) == 1)
        { $line[$i] = 1 } else { $line[$i] = 0 }
    }
    return @line;
}

sub black()
{
    my $i = 2;
    my $ancest = 0;
    # covert to decimal representation
    foreach my $bit (@_)
    {
        $ancest += 2 ** $i * $bit;
        $i--;
    }
    return $rule[$ancest];
}
