#!/usr/bin/perl -w
use strict;

# these are min and max values that seem to be safe on a fairly
# wide range of printers.  They probably aren't safe on all printers.
my @center = ((20+575)/2, (20+772)/2);

print "$center[0] $center[1] moveto\n";

my $boxspacing = 5.52; # points; this is calculated to fit 100 boxes in the
                       # 555 points between 20 and 575, with a little bit of
		       # fuzz.

print <<eosetup;
/boxspacing $boxspacing def
/negboxspacing 0 boxspacing sub def

/boxsize boxspacing 0.9 mul def
/negboxsize 0 boxsize sub def

/fontsize 0.37 boxspacing mul def
/Times-Roman findfont fontsize scalefont setfont

/boxpath { 
	boxsize 2 div dup rmoveto
	0 negboxsize rlineto
	negboxsize 0 rlineto
	0 boxsize rlineto
	closepath
} bind def

% move to appropriate point from which the text could be
% shown centered on the old currentpoint.
% "(text) dup center show" will show the text centered on the
% old currentpoint.  (You could also do something weird instead
% of just 'show'.)
/center { % string -- 
	gsave
		newpath 0 0 moveto
		true charpath flattenpath pathbbox
	grestore
	-2 div exch
	-2 div exch
	rmoveto
	pop pop
} bind def

% draw a big X on currentpoint.  (For debugging 'center'.)
/x { % -- 
	gsave
		100 100 rlineto
		-200 -200 rlineto
		100 100 rmoveto
		100 -100 rlineto
		-200 200 rlineto
		stroke
	grestore
} bind def

/beblack { 0 setgray } bind def
/bewhite { 1 setgray } bind def

% prints string centered in a black box
/blackbox { % string --
	gsave
		currentpoint newpath moveto
		beblack
		boxpath fill
	grestore
	gsave
		bewhite
		dup center show
	grestore
} bind def

% prints string centered in a white box
/whitebox { % string -- 
	gsave
		currentpoint newpath moveto
		beblack
		boxpath stroke
	grestore
	gsave
		beblack
		dup center show
	grestore
} bind def

/goup {0 boxspacing rmoveto} bind def
/godown {0 negboxspacing rmoveto} bind def
/goleft {negboxspacing 0 rmoveto} bind def
/goright {boxspacing 0 rmoveto} bind def
/directions [/goleft /godown /goright /goup] def
/direction 0 def
% 'turn' defines 'gofunc' to be a function from 'directions'.
/turn {
	direction 1 add 4 mod /direction exch def
	directions direction get /gofunc exch def
} bind def
/nextbox {gofunc load exec} bind def

0.01 setlinewidth

eosetup

# OK, now to do the spiral.
# whenever we reach the turning number, we turn.
# whenever we turn vertically, we increment the side length.
# whenever we turn, we add the side length to the turning number.

# conflate the loops of the Sieve of Eratosthenes and of drawing a spiral.
my $spiral_end = 10000;
my @isprime = (0, 0, map {1} (2..$spiral_end));
my $i;
my $addone = 1;
my $sidelength = 0;
my $turnat = 1;
my $deprime;
for $i (1..$spiral_end) {
	if ($isprime[$i]) {
		# mark the multiples of $i as nonprime, starting at
		# $i * $i.  Original sieve starts at $i * 2, but that's
		# redundant.  (This saves a bit of work, although if I
		# were really concerned about efficiency, this wouldn't be
		# the place to start.)
		$deprime = $i * $i;
		while ($deprime <= $spiral_end) {
			$isprime[$deprime] = 0;
			$deprime += $i;
		}
		print "($i) blackbox ";
	} else {
		print "($i) whitebox ";
	}
	if ($turnat == $i) {
		if ($addone) {
			$sidelength ++;
			$addone = 0;
		} else {
			$addone = 1;
		}
		$turnat += $sidelength;
		print "turn nextbox\n";
	} else {
		print "nextbox\n";
	}
}

print "showpage\n";
