//	A demonstrator for the PFL graphics functions
//	---------------------------------------------

//	The top left pixel of the graphics window has co-ordinate (0,0); the
//	pixel immediately below it has co-ordinate (0,1); and the pixel to its 
//	right has co-ordinate (1,0).  All of the graphics functions below
//	return a boolean.  They are builtin functions, whose types are
//	declared in primfuncs.env.  Note that the graphics code does contain
//	known bugs.  In particular, iconising a window whilst a function is
//	writing to it will screw things up ...

//	We can fill a pixel using the "drawpoint" function.
//	You'll need a magnifying glass to see the effect of these:

drawpoint 0 0;
drawpoint 0 1;
drawpoint 1 0;


//	To get rid of all the garbage in the window, use the "clear" function.
//	Use this before each of the following examples just to keep the window tidy:

clear;


//	You can draw a line from one co-ordinate to another using "drawline":

drawline 50 50 100 100;


//	You can write a string to the graphics window using "drawstring":

clear;
drawstring 105 100 "that was a line from 50 50 to 100 100";


//	You can draw an arc in a box using the "drawarc" function.  The
//	following expression draws an arc in a box whost top left
//	co-ordinate is at (300,300), whose width is 200 pixels and whose
//	height is 100 pixels.  The arc is drawn from 0 to 90 degrees:

clear;
drawarc 300 300 200 100 90 180;


//	So you can now draw a circle in a box:

clear;
drawarc 200 200 25 25 0 360;


//	Because PFL is a lazy language, you may get some unexpected behaviour.  
//	For example, compare the following (clearing the screen with "clear"
//	before each one):

clear;
(drawline 50 50 100 100) & (drawline 100 50 50 100);

clear;
(drawline 50 50 100 100) # (drawline 100 50 50 100);

//	Note that in the case of # ("or") PFL doesn't need to evaluate the
//	right-hand operand to know that the result is True, so it doesn't
//	bother.


//	A number of graphics functions can be found in "graphics.env".  We 
//	describe the most important below.  Again, each of these functions 
//	returns a boolean.

//	You can draw a circle with centre at (100,100) and of radius 5 as follows:

clear;
circle 100 100 5;


//	You can draw a square at (50,50) with sides of length 10:

clear;
square 50 50 10;


//	You can draw a rectangle with bottom left corner at (50,50),
//	of width 300 and height 10:

clear;
rectangle 50 50 300 10;


//	You can draw a number of points using the "points" function ("rand", which
//	is defined in "common.env", takes a seed (an integer) and gives an infinite 
//	list of not very random numbers; "%" is the modulus function):

clear;
points [(x % 241,x % 251) | x <- rand 2000000];


//	You can draw a histogram for a list [(s1,n1),...,(sm,nm)] where the
//	si's are strings and each ni represents a percentage for si:

clear;
histogram [("Lab",37),("Con",43),("Lib",17)];


//	Since each function returns a boolean, we can use "&" to execute two 
//	graphics operations (as we've already seen), and can use "and" to
//	execute a (possibly infinite) list of operations:

clear;
and [circle 0 0 x | x <- [0..250]];


//	Finally, lets define a function which takes a starting co-ordinate and a 
//	list of random numbers, and uses these random numbers to wander around
//	the graphics window:

_define snake x y []	==	[];
_define snake x y (h:t)	==	(x,y) : (switch [(h % 4 = 0,snake (x-2) y t),
						 (h % 4 = 1,snake (x+2) y t),
						 (h % 4 = 2,snake x (y-2) t),
						 (h % 4 = 3,snake x (y+2) t)]);

//	And now lets use this function to see what happens, using 1000 random
//	numbers (recall that "points" draws a list of points):

clear;
points (snake 250 100 (take 1000 (rand 2000000)));
