#! /usr/bin/perl

use strict;
use warnings FATAL => 'all';

my $debug = 0;


# lookup tables
# +-------+-------+-------+
# | A1 .. | A2 .. | .. .. |
# |       |       |       |
# | .. .. | B1 .. | B2 .. |
# +-------+-------+-------+    +-------+    +-------|
# | A3 C1 | A4 C2 | .. .. |    | AA BB |    |  1  2 |
# |       |       |       |    |       |    |       |
# | .. .. | B3 D1 | B4 D2 |    | CC DD |    |  4  8 |
# +-------+-------+-------+    +-------+    +-------|
# | .. C3 | .. C4 | .. .. |
# |       |       |       |
# | .. .. | .. D3 | .. D4 |
# +-------+-------+-------+

# +---------------+---------------+---------------+
# | .. ..   .. .. | .. ..   .. .. | .. ..   .. .. |
# | .. ..   .. .. | .. ..   .. .. | .. ..   .. .. |
# |               |               |               |
# | .. ..   A1 .. | A2 B1   A2 B1 | .. B2   .. .. |
# | .. ..   .. .. | .. ..   .. .. | .. ..   .. .. |
# +---------------+---------------+---------------+
# | .. ..   A3 .. | A* B3   A4 B* | .. B4   .. .. |
# | .. ..   C1 .. | C2 D1   C2 D1 | .. D2   .. .. |
# |               |               |               |
# | .. ..   A3 .. | A4 B3   A4 B3 | .. B4   .. .. |
# | .. ..   C1 .. | C* D1   C2 D* | .. D2   .. .. |
# +---------------+---------------+---------------+
# | .. ..   .. .. | .. ..   .. .. | .. ..   .. .. |
# | .. ..   C3 .. | C4 D3   C4 D3 | .. D4   .. .. |
# |               |               |               |
# | .. ..   .. .. | .. ..   .. .. | .. ..   .. .. |
# | .. ..   .. .. | .. ..   .. .. | .. ..   .. .. |
# +---------------+---------------+---------------+


#		A1  A2  A3  A4  B1  B2  B3  B4  C1  C2  C3  C4  D1  D2  D3  D4
#		..  ..  .+  x+  ..  ..  +x  +.  .+  ++  .+  ++  ++  +.  ++  +.
#		.+  ++  .+  ++  ++  +.  ++  +.  .+  x+  ..  ..  +x  +.  ..  ..

#		nibble
#		 0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15
#		..  +.  .+  ++  ..  +.  .+  ++  ..  +.  .+  ++  ..  +.  .+  ++
#		..  ..  ..  ..  +.  +.  +.  +.  .+  .+  .+  .+  ++  ++  ++  ++

# rules: b0000xxxm
# 		000/0	000/1	001/0	001/1	010/0	010/1	011/0	011/1
# 		  0/0	  0/1	  1/0 	  1/1	  2/0	  2/1	  3/0	  3/1


my @bits = (
	"....", "+...", ".+..", "++..", "..+.", "+.+.", ".++.", "+++.",
	"...+", "+..+", ".+.+", "++.+", "..++", "+.++", ".+++", "++++"
);

sub count($$) {
	my ($bits, $pat) = @_;
	my $c = 0;
	for (my $i = 0; $i < 4; $i++) {
		if (substr($bits, $i, 1) eq "+" && substr($pat, $i, 1) eq "+") {
			$c++;
		}
	}
	return $c;
}

sub match($) {
	my $pat = shift;
	print "\t.db\t";
	for (my $i = 0; $i < 16; $i++) {
		my $c = count($bits[$i], $pat);
		printf "%2d", ($c << 4);
		if ($i != 15) {
			print ", ";
		}
	}
	print "\n";
}

sub match_pat($@) {
	my ($me, @pats) = @_;
	my $i = 1;
	foreach my $pat (@pats) {
		print "bitref_$me$i:\n";
		match($pat);
		$i++;
	}
}

sub match_result($$$) {
	my ($me, $m, $pat) = @_;
	print "bitref_$me:\n";

	my @binary = ( "...", "..+", ".+.", ".++", "+..", "+.+", "++.", "+++" );

	my $mecount = $pat;
	$mecount =~ tr/.+/+./;

#	print "mecount: $mecount\n";

	# neighbour count is in native binary order (000, 001, 010, 011 etc.)
	# cells are in reverse, 0b0000DCBA

	# three-nibble neighbourhood can have at most 5 live neighbours
	for (my $n = 0; $n <= 5; $n++) {
		($debug) || print "\t.db\t";
		for (my $i = 0; $i < 16; $i++) {
			my $c = $n + count($bits[$i], $mecount);
			my $live = count($bits[$i], $pat);
			my $r;
			if (($live == 1 && ($c == 2 || $c == 3)) ||
					($live == 0 && $c == 3)) {
				$r = $m;
			} else {
				$r = 0;
			}
			if ($debug) {
				print "($c/$live) " .
						$binary[$n] ." " .
						$bits[$i] . " -> $r\n";
			} else {
				print "$r";
				if ($i != 15) {
					print ", ";
				}
			}
		}
		($debug) || print "\n";
	}
}


print "\n";
match_pat("a", "...+", "..++", ".+.+", ".+++");
match_result("a", 1, "+...");

print "\n";
match_pat("b", "..++", "..+.", "+.++", "+.+.");
match_result("b", 2, ".+..");

print "\n";
match_pat("c", ".+.+", "++.+", ".+..", "++..");
match_result("c", 4, "..+.");

print "\n";
match_pat("d", "+++.", "+.+.", "++..", "+...");
match_result("d", 8, "...+");
