###############################################################
# p^3 Generator
# Author: John Wilkinson jkw@koth.org
#
# vestion 2.2: 2000-12-06
#   Added ; comments on the output to explain the L/W/T table
#   that was used to make the output
#
# version 2.1: 2000-11-26
#   Generates p^3 code segment based on state table input file
#
#   Now allows a "start xx" line where xx is the state number
#   to start off in.  If xx is "0", the output is as before.
#
#   Now ;assert's coresize is large enough to accomodate the
#   numbers in the table.
#
#   Also ;assert's 0 to make sure you notice error messages.
#
#   Checks for invalid state assignements, and for the first
#   two actions not being identical.
###############################################################

use strict;

if (scalar(@ARGV) < 1) {
	print "Usage 'perl p3-2.pl filename'\n";
	print "\nWhere filename is a state diagram text file, similar to the following:\n";
	print "start 0\n";
	print "S	A	L  W  T\n";
	print "0	w0	1  0  0\n";
	print "1	w0	2  0  1\n";
	print "2	w1	3  2  2\n";
	print "3	w1	0  2  3\n";
	print "\nThe S column represents the number of the state.\n";
	print "\nThe A column represents the action to be jumped to,\nthis will be a label in your warrior's code.\n";
	print "\nThe L/W/T columns represents the state to go to\non a loss/win/tie, respectively.\n";
	exit;
	}

open(F,"<".$ARGV[0]);
my @file = (<F>);
close(F);

my %states;
my $starting = 0;

foreach (@file) {
	if (/^start (\d+)/) {
		$starting = $1;
		}
	if (/(\d+)\s+(\S+)\s+(\d+)\s+(\d+)\s+(\d+)/) {
		$states{$1}{action} = $2;
		$states{$1}{a} = $3;
		$states{$1}{b} = $4;
		$states{$1}{c} = $5;
		}
	}

my $n = scalar keys %states;
if ($n < 2) { print "\n;assert 0\n;;;there must be at least 2 states\n\n"; } # 0 =< a < m

my $m;
if ($n % 2) { $m = $n + 1; }
else 	    { $m = $n + 2; }


print "PLOC equ ".int(rand(400)+100)."\n\n";
print "think	ldp.a	#0,	in\n";
if ($starting != 0) { print "	jmz.b	3,	*in\n"; }
print "	ldp.ba	tloc,	table\n";
print "	mod.ba	*in,	table\n";
print "tloc	stp.b	*table,	#PLOC\n";
print "	mov.i	#0,	-1   ;;  S  L  W  T\n";

foreach my $snum (sort { $a <=> $b } keys %states) {
	my $a = $states{$snum}{a};
	my $b = $states{$snum}{b};
	my $c = $states{$snum}{c};

	my $i = $b + $c - (2 * $a);
	my $j;
	
	if (($a < 0) || ($a >= $m)) { print "\n;assert 0\n;;;invalid a $a, in state $snum\n\n"; } # 0 =< a < m
	if (($b < 0) || ($b >= $m - 1)) { print "\n;assert 0\n;;;invalid b $b, in state $snum\n\n"; } # 0 =< b < m-1
	if (($c < 0) || ($c >= $m + 1)) { print "\n;assert 0\n;;;invalid c $c, in state $snum\n\n"; } # 0 =< c < m+1

	if ($i % 2) { $j = ($i+1+$m)/2; }
	else 	    { $j = $i/2; }

	my $p = (($j*($m-1)+$b-$a)*$m+$a) % ($m*($m-1)*($m+1));
	
	if ($snum == 0) {
		printf "table	jmp	}%s,	%4s ;; %2s %2s %2s %2s\n",$starting,$p,$snum,$states{$snum}{a},$states{$snum}{b},$states{$snum}{c};
		if ($states{0}{action} ne $states{1}{action}) {	print ";assert 0\n;;; action of state 0 != action of state 1.\n;;; behavior will not be as designed.\n"; }
		}
	else {
		printf "	dat	%s,	%4s ;; %2s %2s %2s %2s\n",$states{$snum}{action},$p,$snum,$states{$snum}{a},$states{$snum}{b},$states{$snum}{c};
		}
	}


print ";assert (CORESIZE > ".($m*($m-1)*($m+1)).")\n";

if ($starting != 0) { print "	dat	0,	0\n"; }

print "in	dat	".$states{0}{action}.",	".$m. ((($m - $n) > 0)?" ; brainwashing with ".($n)."\n":"\n");
print "	dat	".$states{0}{action}.",	".($m - 1). ((($m - $n) > 1)?" ; brainwashing with ".($n+1)."\n":"\n");
print "	dat	0,	".($m + 1)."\n";

exit;