#!/usr/sww/bin/perl

# set up a random number seed
#
$RAND = time ^ $$;

# default number of runs
#
$NUM = 100;

# use default population size
#
$POP = -1;

# get arguments
#
&getArgs();

# set up unbuffered STDOUT
#
$| = 1;

# let 'em know what the starting random number was
#
srand $RAND;
print "Initial seed = $RAND\n";

foreach $app (@APPLIST) {
  print "## $app ##\n";
  for ($i = 0; $i < $NUM; $i++) {
    $RAND = rand() * 1000000000;
    $lastgen = $bestgen = undef;
    open(RUN, "nice -19 ./$app $ARGLIST -r $RAND |") ||
	die "Couldn't start program!\n";
    while (<RUN>) {
      if (/^\s*Generation ([0-9]*)/) {
        $lastgen = $1;
      } elsif (/^Hits: Best=([0-9]*), Average=([0-9]*), /) {
        $besthits = $1;
        $avghits = $2;
      } elsif (/^Standardized Fitness: Best=([\-0-9\.]*), Average=([\-0-9\.]*), /) {
        $beststd = $1;
        $avgstd = $2;
      } elsif (/^Structural Complexity:/) {
        printf "\t%3d: H[%d, %d] S[%f, %f]\n", $lastgen, $besthits, $avghits,
		$beststd, $avgstd;
      } elsif (/Elapsed time = ([ 0-9.]*) seconds/) {
        $time = $1;
      } elsif (/^Best program found on generation ([0-9]*)/) {
        $bestgen = $1;
      }
    }
    close(RUN);
    printf "%3d: ", $i;
    print "Seed=$RAND, Last=$lastgen, Best=$bestgen, Time=$time\n";

    # clean up if it dumped core
    #
    if (-f "./core") {
      print STDERR "Core dumped on $app $ARGLIST -r $RAND\n";
      unlink "./core";
    }
  }
}

exit 0;

# process arguments
#
sub getArgs {
  local($usage);
  local($_, $tournament, $overselection);

  while ($_ = shift(@ARGV)) {
    if (s/^-//) {

      # check for state option
      #
      if (/^[oO]/) {
	$_ = shift(@ARGV);
	if ($_ <= 0) {
	  print STDERR "Overselection percentage must be greater than 0.0!\n";
	  $usage = 1;
	} elsif ($_ >= 1.0) {
	  print STDERR "Overselection percentage must be less than 1.0!\n";
	  $usage = 1;
	} else {
	  $overselection = $_;
	}
      } elsif (/^[Nn]/) {
	$_ = shift(@ARGV);
	if ($_ <= 0) {
	  print STDERR "Number of runs must be greater than 0!\n";
	  $usage = 1;
	} else {
	  $NUM = $_;
	}
      } elsif (/^[Pp]/) {
	$_ = shift(@ARGV);
	if ($_ <= 0) {
	  print STDERR "Population size must be greater than 0!\n";
	  $usage = 1;
	} else {
	  $POP = $_;
	}
      } elsif (/^[Rr]/) {
	$_ = shift(@ARGV);
	if ($_ <= 0) {
	  print STDERR "Random number seed must be greater than 0!\n";
	  $usage = 1;
	} else {
	  $RAND = $_;
	}
      } elsif (/^[tT]/) {
	$_ = shift(@ARGV);
	if ($_ <= 0) {
	  print STDERR "Tournament rounds must be greater than 0!\n";
	  $usage = 1;
	} else {
	  $tournament = $_;
	}
      }

      # bad arg
      #
      else {
	print STDERR "$PROGNAME: Invalid argument '$c'!\n";
	$usage = 1;
      }
    } else {

      # add to program list if it's an executable
      #
      if (-x $_) {
	push(@APPLIST, $_);
      } else {
	print STDERR "'$_' is not executable!\n";
	$usage = 1;
      }
    }
  }

  # make sure they didn't select both tournament and overselection
  #
  if ($tournament > 0 && $overselection > 0) {
    print STDERR "You can't choose both tournament and overselection!\n";
    $usage = 1;
  }

  # make sure there's at least one program
  #
  if ($usage == 0 && @APPLIST eq 0) {
    print STDERR "Please choose at least ONE program!\n";
    $usage = 1;
  }

  # if they screwed up, print usage message and die
  #
  if ($usage) {
    print STDERR "Usage: $PROGNAME";
    print STDERR " [-n numberOfRuns]";
    print STDERR " [-o overselectionPercentage]";
    print STDERR " [-p population]";
    print STDERR " [-r randomNumberSeed]";
    print STDERR " [-t tournamentRounds]";
    print STDERR " program ...\n";
    exit 1;
  }

  # build the argument list
  #
  if ($tournament > 0) {
    $ARGLIST = "-s t -t $tournament";
  } elsif ($overselection > 0.0) {
    $ARGLIST = "-s g -o $overselection";
  }
  $ARGLIST .= " -p $POP" if ($POP > 0);
}
