#!/usr/bin/perl

use DFA::Cellular;
use strict;

{
  package Margolus;
  our @ISA=qw(DFA::Cellular);

  sub step{
    my $self=shift;

    ++$self->{'Margolus::tick'};
    my $offset=$self->{'Margolus::tick'} % -2;

    for(my $x=$offset; $x<$self->{width}-1; $x+=2){
      for(my $y=$offset; $y<$self->{height}-1; $y+=2){

	my $neigh=$self->cneigh($x,$y);

	for my $rule(@{$self->{rules}}){
	  defined(my $nstate=$rule->transforms($neigh))
	    or next;
          $self->cneigh($x,$y,$nstate);
	  last;
	}
      }
    }
  }

  sub cneigh{
    my($self,$x,$y,$neigh)=@_;
    my $cstate=$self->{cstate};
    if($neigh){
      ($cstate->[$y][$x],$cstate->[$y][$x+1],
       $cstate->[$y+1][$x+1],$cstate->[$y+1][$x])=split //,$neigh;
    }else{
      return join '',
	$cstate->[$y][$x],$cstate->[$y][$x+1],
	$cstate->[$y+1][$x+1],$cstate->[$y+1][$x],
      ;
    }
  }

}


my($m,$n,$density)=@ARGV;
$m||=78;
$n||=22;
$density||=0.2;

my @grid;
for(1..$n){
  my $line;
  for(1..$m){
    $line.=rand()<$density ? '.' : ' ';
  }
  push @grid,$line;
}
substr($grid[$n/2],$m/2,1)='*';

my $dfa=Margolus->new($m,$n,join "\n",@grid);
$dfa->addrule(DFA::Cellular::ProcRule->new(sub{
  local($_)=@_;
  /\*/ or return;
  y/./*/;
  $_;
}));
$dfa->addrule(DFA::Cellular::ProcRule->new(sub{
  local($_)=@_;
  /\./ && / / or return;
  if(rand()<0.5){
    s/(.)(...)/$2$1/;
  }else{
    s/(...)(.)/$2$1/;
  }
  $_;
}));

$dfa->show;
$SIG{ALRM} = sub { warn "TICKS: $dfa->{'Margolus::tick'}\n"; exit };
alarm $ENV{TIMELIMIT} || 120;
while(1){
  $dfa->step;
  $dfa->show;
}

