From: lee@sq.sq.com (Liam R. E. Quin)
Subject: game (src) for OpenWindows 3 - HexSweeper 1.81
Organization: SoftQuad Inc., Toronto, Canada
Date: Mon, 7 Sep 92 22:57:44 GMT

Here is HexSweeper 1.81.  It's a little faster than 1.66 at many things,
has a high scorefile, a few bug fixes, a font menu to let you choose the
numbers font, and a picture of a Big Red Bang.

HexSweeper is a game a bit like the VMS (or Microsoft Windows) minesweeper
game, except that instead of a rectangular grid there's a grid of hexagons.
 
You must have OpenWindows 3.0 or later in order to run HexSweeper.
This program will not run on OpenWindows 2, Microsoft Windows, X Windows
or Greenhouse Windows :-)   It uses TNT 3.0, the NeWS Toolkit.

Known problems:
    * There's no Properties window yet.
    * Do not go directly from Texas Scale to Welsh Cottage Scale!
      (perhaps the program should prevent this)
    * GreyScale users might not be able to read all the numbers - if this
      happens, change "framebuffer /Color get" to "false" at or near line 74.
    * The high score file isn't protected against multiple people writing at
      once.  How do I do that in PostScript??
 
If you do get a problem, press L1 (STOP) if the mouse stops working, and
then use hexkill (enclosed) to get rid of the Hex NeWs processes.
 
Don't be discouraged by that warning - HexSweeper is fun to play with,
and it works in both colour and mono.  It uses your Window colour, so you can
bring up `props' (Workspace menu->Properties) and change the colours!
 
Please tell me if you like HexSweeper!
 
Lee
lee@sq.com

#! /bin/sh
: To unbundle, sh this file
echo x - hexsweeper 1>&2
sed 's/^X//' >hexsweeper <<'@@@End of hexsweeper'
X#! /bin/sh
X
X# $Id: hexsweeper,v 1.81 92/09/07 18:54:43 lee Exp $
X
Xpsh << 'barefoot_boy'
X
X/MyName (HexSweeper 1.81) def
X
X/NeWS 3 0 findpackage beginpackage
X/TNTCore 3 0 findpackage beginpackage
X/TNT 3 0 findpackage beginpackage
X% /debug 1 0 findpackage beginpackage
X
Xstatusdict begin 1200 setjobtimeout end
X
Xtrue setpacking
X
X/MineDict 30 dict dup begin
X    /SecondsSoFar 0 def
X    /Counting false def
X    /MineCount 0 def
X    /MineRows -1 def
X    /MineCols -1 def
Xend def
X
X/HexTimerProcess {
X    currentprocess /ProcessName (HexTimer) put
X    MineDict begin
X    [3 0] sleep
X    {
X	pause [1 0] sleep
X	Counting
X	{
X	    createevent dup begin
X		/Name /HexTimerEvent def
X		/Action (HexTimerEvent) def
X	    end
X	    sendevent
X	} if
X	pause
X    } loop
X} fork def
X
X/sqrt3 3 sqrt def
X
X/Hex3DDict 12 dict def
X/Hex3DInnerDict 12 dict def
X
X/SetHexSizeFromFlat {
X    /HexHWidth exch def
X    /HexDWidth HexHWidth 2 div def
X    /HexDHeight HexHWidth sqrt3 mul 2 div def
X    /HexHDelta HexDWidth HexHWidth add def
X    /HexWidth HexDWidth 2 mul HexHWidth add def
X    /HexHeight HexDHeight 2 mul def
X    /HexDepth HexHWidth 7 div cvi dup 0 eq { pop 1 } if def
X    MakeGlyphs
X} def
X
X/HexFont { /GillSans } def
X/HexBoldFont { /GillSans-Bold } def
X
X% TNT display items for glyphs:
X/MakeGlyphs {
X    /BombGlyph [ (\154) ] def
X    /SetBombFont { /ZapfDingbats findfont HexHWidth scalefont setfont } def
X    /WrongMarkGlyph [
X	(\067)
X	/ZapfDingbats findfont HexWidth scalefont % pretty huge...
X	1 0 0 rgbcolor
X    ] def
X    /MarkGlyph [(\076) /ZapfDingbats findfont HexWidth scalefont ] def
X
X    framebuffer /Color get {
X	/0Glyph ( ) def %% actually never used
X	/1Glyph [(1) HexFont findfont HexWidth scalefont
X	    .2 .2 1 rgbcolor ] def
X	/2Glyph [(2) HexFont findfont HexWidth scalefont
X	    .1 .9 .1 rgbcolor ] def
X	/3Glyph [(3) HexFont findfont HexWidth scalefont
X	    0 .9 1 rgbcolor ] def
X	/4Glyph [(4) HexBoldFont findfont HexWidth scalefont
X	    .95 0 .8 rgbcolor ] def
X	/5Glyph [(5) HexBoldFont findfont HexWidth scalefont
X	    1 .9 0 rgbcolor ] def
X	/6Glyph [(6) HexBoldFont  findfont HexWidth scalefont
X	    0.8 .1 .1 rgbcolor ] def
X    } {
X	/0Glyph ( ) def
X	/Black 0 0 0 rgbcolor def
X	/1Glyph [(1) HexFont findfont HexWidth scalefont Black ] def
X	/2Glyph [(2) HexFont findfont HexWidth scalefont Black ] def
X	/3Glyph [(3) HexFont findfont HexWidth scalefont Black ] def
X	/4Glyph [(4) HexBoldFont findfont HexWidth scalefont Black ] def
X	/5Glyph [(5) HexBoldFont findfont HexWidth scalefont Black ] def
X	/6Glyph [(6) HexBoldFont findfont HexWidth scalefont Black ] def
X    } ifelse
X
X    /GlyphArray [ 0Glyph 1Glyph 2Glyph 3Glyph 4Glyph 5Glyph 6Glyph ] def
X} def
X
X%%%% Default hex size
X
X25 SetHexSizeFromFlat
X% 30 SetHexSizeFromFlat
X
X/FindHexWestPoint { % x y FindHexWestPoint -> x y of p0
X    12 dict begin
X	% transform coordinates so the centre of hex 0,0 is at 0,0:
X	/y exch HexDHeight sub def
X	/x exch HexWidth 2 div sub def
X
X	% find a 60 degree line to the left of (x, y)
X	% that intersects the x axis at a multiple of HWidth units
X
X	%		+
X	%	       /|
X	%	      / |	 Angle t is 60 degrees, so
X	%	     /  | y	 x - x1 = y/sqrt3
X	%	    /t) |
X	%	   +----+ . . .+
X	%	   x1	x 	x2 [see below]
X
X	% (calculate x1 and round down to a multiple of HexHWidth)
X	/x1 x y sqrt3 div sub HexHWidth div dup 0 lt {
X	    /a exch def 
X	    a cvi dup a eq not {
X		1 sub
X	    } if
X	} {
X	    cvi
X	} ifelse def
X
X	% Now we do the same in the other direction:
X	/x2 y sqrt3 div x add HexHWidth div dup 0 lt {
X	    /a exch def 
X	    a cvi dup a eq not {
X		1 sub
X	    } if
X	} {
X	    cvi
X	} ifelse def
X
X	% intersect the two lines:
X	/x3 x2 x1 add 2 div HexHWidth mul def
X	/y3 x2 HexHWidth mul x3 sub sqrt3 mul def
X
X	% A debugging triangle:
X	% 2 setlinewidth 0 setgray x1 HexHWidth mul 0 moveto x3 y3 lineto stroke
X	% 1 setgray x2 HexHWidth mul 0 moveto x3 y3 lineto stroke
X	% x 0 moveto x y lineto stroke
X
X	% Now we check that the intersection will be a West point:
X	x1 x2 add 3 mod 3 add 3 mod {
X	    0 { % found a centre
X		/x1 x1 1 sub def
X		/x2 x2 1 sub def
X	    }
X	    1 {
X		% it's perfect!
X	    }
X	    2 {
X		% found a top left or bottom left corner.
X		% intersect the two lines:
X		y3 y lt {
X		    /x1 x1 1 sub def
X		} {
X		    /x2 x2 1 sub def
X		} ifelse
X	    }
X	} case
X
X	/x3 x2 x1 add 2 div HexHWidth mul def
X	/y3 x2 HexHWidth mul x3 sub sqrt3 mul def
X
X	% Another debugging triangle:
X	% 0 setlinewidth 0 setgray x1 HexHWidth mul 0 moveto x3 y3 lineto stroke
X	% 1 setgray x2 HexHWidth mul 0 moveto x3 y3 lineto stroke
X
X	x3 HexWidth 2 div add
X	y3 HexDHeight add
X    end
X} def
X
X/MakeHex {
X    /p0y exch def
X    /p0x exch def
X    /p1x HexDWidth p0x add def /p1y HexDHeight p0y add def
X    /p2x HexHWidth p1x add def /p2y p1y def
X    /p3x HexDWidth p2x add def /p3y p0y def
X    /p4x p2x def /p4y p0y HexDHeight sub def
X    /p5x p1x def /p5y p4y def
X} def
X
X/Draw2DHexAt {
X    Hex3DDict begin
X	% x y of Western (leftmost) point
X
X	canvas1 setcanvas
X	2 copy moveto % p0
X	/p0y exch def
X	/p0x exch def
X
X	HexDWidth HexDHeight rlineto % p1
X	HexHWidth 0 rlineto % p2
X	HexDWidth HexDHeight neg rlineto % p3
X	p0x HexHDelta add  p0y HexDHeight sub lineto % p4
X	p0x HexDWidth add  p0y HexDHeight sub lineto
X	gsave
X	    clip
X
X	    pause pause pause
X	    clippath BG2 setcolor fill
X	grestore
X	% pause pause pause
X	    % gsave
X	    % 1 setlinewidth FG setcolor stroke 
X	    % pause pause pause
X	% grestore
X    end
X} def
X
X/OldDraw2DHexAt {
X    Hex3DDict begin
X	MakeHex
X	0 setlinewidth
X	newpath p0x p0y moveto
X	p1x p1y lineto
X	p2x p2y lineto
X	p3x p3y lineto
X	p4x p4y lineto
X	p5x p5y lineto
X	gsave
X	    BG2 setcolor fill
X	grestore
X	gsave
X	    1.2 setlinewidth FG setcolor closepath stroke 
X	grestore
X% gsave % 
X% p0x p0y
X% SetBombFont exch HexWidth 2 div add exch % x y of centre of hex
X% FG setcolor (X) DisplayItemSize % x y w h
X% 2 div neg exch 2 div neg exch xyadd moveto (X) DisplayItemPaint
X% grestore
X    end
X} def
X
X/Draw3DHexAt {
X    Hex3DDict begin
X	MakeHex
X
X	0 setlinewidth
X	newpath p0x p0y moveto
X	p1x p1y lineto
X	p2x p2y lineto
X	p3x p3y lineto
X	p4x p4y lineto
X	p5x p5y lineto
X	clip
X	clippath BG setcolor fill
X
X 	HexDepth 2 mul setlinewidth
X
X	p0x p0y moveto 
X	p1x p1y lineto
X	p2x p2y lineto
X	BG0 setcolor stroke
X
X	p2x p2y moveto
X	p3x p3y lineto
X	p5x p5y moveto
X	p0x p0y lineto
X	BG2 setcolor stroke
X
X	p3x p3y moveto
X	p4x p4y lineto
X	p5x p5y lineto
X	BG3 setcolor stroke
X	initclip
X	HexHWidth 30 gt {
X	    gsave
X		0 setlinewidth
X		FG setcolor stroke
X	    grestore
X	} if
X    end
X} def
X
X
X/ClearMines { % rows cols ClearMines -
X    /MineBoard growabledict def
X    /PlacesBeen growabledict def
X    % Rows Cols
X    mul dup array % n array
X    MineDict exch % n Dict array
X    /NearbyMines exch put
X    % n 
X    1 sub -1 0 {
X	MineDict /NearbyMines get exch 0 put
X    } for
X} def
X
X/RecomputeNeighbours {
X    % (Computing neighbours for % by %)[MineDict /MineRows get 1 sub MineDict /MineCols get 1 sub]sprintf ==
X    /NeighboursDict growabledict def
X
X    8 dict begin
X	gsave
X	    canvas1 setcanvas
X	    bbox /ht exch def /wd exch def pop pop
X	    
X	    /Rockwell-Bold findfont 70 scalefont setfont
X	    /s (HEXSWEEPER!) def
X	    s DisplayItemSize 2 div neg exch 2 div neg exch 
X	    wd 2 div ht 2 div xyadd moveto
X	    s DisplayItemPaint
X
X	    /MaxCol MineDict /MineCols get 1 sub def
X	    /MaxRow MineDict /MineRows get 1 sub def
X
X	    % Do edges, but not the corners:
X	    1 1 MaxRow 1 sub {
X		/Row exch def
X		% Left edge:
X		NeighboursDict 0 Row (%-%) sprintf
X		[ null		[ Row 1 add  0] [Row 1]
X		  [Row 1 sub 1]	[ Row 1 sub  0] null ] put
X		% Right edge:
X		NeighboursDict MaxCol Row (%-%) sprintf
X		MaxCol 2 mod 0 eq {
X		    % even
X		    [ [Row MaxCol 1 sub] [Row 1 add MaxCol] null
X		      null [Row 1 sub MaxCol] [Row 1 sub MaxCol 1 sub]
X		    ]
X		} {
X		    % odd
X		    [ [Row 1 add MaxCol 1 sub] [Row 1 add MaxCol] null
X		      null  [Row 1 sub MaxCol] [Row MaxCol 1 sub]
X		    ]
X		} ifelse put
X
X		% now the intermediate columns:
X		1 1 MaxCol 1 sub {
X		    /Col exch def
X		    NeighboursDict
X			Col Row (%-%) sprintf
X			Col 2 mod 0 eq {
X			    [
X				[Row Col 1 sub] [Row 1 add Col]
X				[Row  Col 1 add] [Row 1 sub Col 1 add]
X				[Row 1 sub Col] [Row 1 sub Col 1 sub]
X			    ]
X			} {
X			    [
X				[Row 1 add  Col 1 sub] [Row 1 add  Col]
X				[Row 1 add  Col 1 add] [Row  Col 1 add]
X				[Row 1 sub Col] [Row Col 1 sub]
X			    ]
X			} ifelse
X		    put
X		} for
X
X		pause
X		random 0.2 ge {
X		    random Rows 1 add mul cvi
X		    random Cols 1 add mul cvi
X		    CoordsToPoint Draw3DHexAt
X		} if
X	    } for
X
X	    % now do the corners and top and bottom rows:
X	    0 1 MaxCol {
X		/Col exch def
X		NeighboursDict dup
X		    Col 0 (%-%) sprintf
X		    0 Col FindNeighbours
X		put
X		    Col MaxRow (%-%) sprintf
X		    MaxRow Col FindNeighbours
X		put
X	    } for
X
X	grestore
X    end
X} def
X
X/GetNearbyMines { % Row Col GetNearbyMines n
X    6 dict begin
X	/Col exch def
X	/Row exch def
X	/Rows MineDict /MineRows get def
X	/Cols MineDict /MineCols get def
X	    Col Cols ge Row Rows ge or
X	    Col 0 lt Row 0 lt or
X	or {
X	    (Tried to look at Row % Col %, max is Row % Col %)
X	    [Row Col Rows Cols] sprintf ==
X	    0
X	} {
X	    MineDict /NearbyMines get % array
X	    Row  Col Rows mul add  get % int or null
X	} ifelse
X    end
X} def
X
X/AddNearbyMine { % Row Col -
X    4 dict begin
X	/Col exch def
X	/Row exch def
X	/Rows MineDict /MineRows get def
X	/Cols MineDict /MineCols get def
X	MineDict /NearbyMines get dup % array
X	Row  Col Rows mul add  get % array int or null
X	dup null eq {
X	    pop 1
X	} {
X	    1 add
X	} ifelse
X	% Array value
X	Row  Col Rows mul add exch % Array index value
X	put % int or null
X    end
X} def
X
X/GetNeighbours {
X    exch (%-%) sprintf dup % name name
X    NeighboursDict exch known { % name 
X	NeighboursDict exch get
X    } {
X	pop [null null null null null null]
X    } ifelse
X} def
X
X/CheckInRange { % x y -> bool
X    4 dict begin
X	FindHexWestPoint % x' y'
X	PointToCoords
X	/Col exch def
X	/Row exch def
X
X	/Rows MineDict /MineRows get def
X	/Cols MineDict /MineCols get def
X
X	Col Cols ge Row Rows ge or    Col 0 lt Row 0 lt or
X	or % true if out or range
X	not % true iff in range
X    end
X} def
X
X/PointToCoords { % x y PointToCoords Row Col
X    % Note: the point must be the Westernmost corner of the Hex
X    exch % y x
X    HexHDelta div cvi % y y Col
X    dup 2 mod 1 eq { % y Col
X	exch % Col y
X	HexDWidth sub
X    } {
X	exch % Col y
X    } ifelse % Col y
X    HexDWidth sub
X    HexHeight div
X    dup 0 lt { 1 sub } if
X    cvi
X    exch
X} def
X
X/DoAutoWalk { % Row Col DoAutoWalk -
X    %%
X    %% Called when we find that we have landed on a hexagon with no
X    %% nearby mines (GetNearbyMines returned 0).  We have already been
X    %% drawn flat at this point.
X    %%
X    %% We flatten each of the neighbours.  If any neighbour has
X    %% no nearby mines, we repeat the process for that neighbour.
X    %%
X    /busy /setcursor window1 send
X    7 dict begin
X	/OnStack growabledict def
X
X	mark
X	3 1 roll % mark Row Col
X
X	{
X
X	    dup mark eq { pop exit } if
X
X	    % mark Row Col (and maybe Row Col Row Col...)
X	    2 copy (%-%) sprintf /NAME exch def
X	    PlacesBeen NAME true put
X
X% gsave
X% 6 setrasteropcode
X% SetBombFont
X% 2 copy CoordsToPoint % x y
X% exch HexWidth 2 div add exch % x y of centre of hex
X% (X) DisplayItemSize % x y w h
X% 2 div neg exch 2 div neg exch xyadd moveto (X) DisplayItemPaint
X% grestore
X
X	    % Row Col
X	    /C exch def
X	    /R exch def
X	    R C GetNeighbours % Array
X	    0.5 random gt { arrayreverse } if
X	    {
X		dup null eq {
X		    pop
X		} {
X		    aload pop
X		    % Try to reject as many neighbours as possible as soon as
X		    % possible...
X
X		    % Row Col
X		    2 copy (%-%) sprintf dup dup
X		    % Row Col name name name
X		    OnStack exch known % Row Col name name bool
X		    exch PlacesBeen exch known % Row Col name bool bool
X		    or {
X			%% Either already decided to look here, or already
X			%% visited here...
X			% Row Col name
X			pop pop pop
X		    } {
X			% Row Col Name
X			/N exch def
X
X			% Row Col
X			2 copy GetNearbyMines % Row Col n
X			/n exch def
X			2 copy CoordsToPoint % Row Col x y
X
X			n 0 eq {
X			    % Row Col x y
X			    Draw2DHexAt
X			    % Row Col
X			    /Needed true def
X
X			    % If there is a neighbour of this hex that
X			    % has zero nearby mines and is on the stack,
X			    % and is not (R, C), we don't need to
X			    % put _this_ one on the stack
X			    2 copy GetNeighbours {
X				dup null eq {
X				    pop
X				} {
X				    aload pop % row col
X				    % check it's not the starting hex:
X				    2 copy C ne exch R ne or
X				    % row col bool
X				    3 1 roll (%-%) sprintf % bool name
X				    OnStack exch known % bool bool
X				    and {
X					/Needed false def
X					exit
X				    } if
X				} ifelse
X				pause
X			    } forall
X			    Needed {
X				OnStack N true put
X			    } {
X				pop pop
X			    } ifelse
X			} {
X			    n DrawHexGlyphAt
X			    PlacesBeen N true put
X			    pop pop
X			} ifelse
X		    } ifelse
X		} ifelse
X	    } forall
X
X	    OnStack NAME undef
X	    pause pause pause
X
X	} loop
X    end
X    /basic /setcursor window1 send
X} def
X
X/FlattenHex { % x y n FlattenHex -
X    3 1 roll % n x y
X    2 copy Draw2DHexAt % -
X    % n x y 
X    3 -1 roll dup 0 eq {
X	pop pop pop
X    } {
X	% x y n
X	DrawHexGlyphAt
X    } ifelse
X} def
X
X/DrawHexGlyphAt { % x y n -
X    GlyphArray exch get % x y DisplayItem
X    3 1 roll % DI x y
X    2 copy OldDraw2DHexAt % DI x y
X    exch HexWidth 2 div add exch % (N) x' y
X    moveto % (n)
X    dup DisplayItemSize 2 div neg exch 2 div neg exch rmoveto
X    DisplayItemPaint
X} def
X
X/FindNeighbours { % row col FindNeighbours [ [x y] null null null null null ]
X    6 dict begin
X	/Col exch def
X	/Row exch def
X	/Z Col 2 mod def
X	/Neighbours [ null null null null null null ] def
X	Col 0 gt {
X	    Neighbours 0 [ Row Z add 	Col 1 sub ] put
X	    Neighbours 5 [ Row 1 sub Z add	Col 1 sub ] put
X	} if
X	Col MineDict /MineCols get 1 sub lt {
X	    Neighbours 2 [ Row Z add	Col 1 add ] put
X	    Neighbours 3 [ Row Z add 1 sub	Col 1 add ] put
X	} if
X	Row 0 gt {
X	    Neighbours 4 [ Row 1 sub	Col ] put
X	} {
X	    Z 0 eq {
X		Neighbours 3 null put
X		Neighbours 5 null put
X	    } if
X	} ifelse
X	Row MineDict /MineRows get 1 sub lt {
X	    Neighbours 1 [ Row 1 add	Col ] put
X	} {
X	    Z 1 eq {
X		Neighbours 0 null put
X		Neighbours 2 null put
X	    } if
X	} ifelse
X	Neighbours
X    end
X} def
X
X/CoordsToPoint {
X    dup 2 mod 0 eq {
X	HexDHeight
X    } {
X	HexHeight
X    } ifelse
X    3 1 roll % offset Row Col
X
X    HexHDelta mul % offset Row x
X    exch HexHeight mul % x bottom-of-hex-if-odd
X
X    3 -1 roll add % x y
X} def
X
X/VisualEffectForWinning {
X    gsave
X	6 setrasteropcode
X	Color { 2 } { 5 } ifelse % it's faster in mono!
X	{
X	    clippath fill
X	    pause
X	    [0 1000000 20 div cvi] sleep
X	    clippath fill
X	} repeat
X    grestore
X} def
X
X/VisualEffectForLosing {
X    gsave
X	6 setrasteropcode
X	Color { 2 } { 5 } ifelse % it's faster in mono!
X	{
X	    clippath fill
X	    pause
X	    [0 1000000 20 div cvi] sleep
X	    clippath fill
X	} repeat
X	12 setrasteropcode
X    grestore
X    % I don't think I like the fissures very much:
X    % gsave
X	% newpath
X	% DrawFissures
X    % grestore
X} def
X
X/MakeFissure { % x y length angle thickness -> -
X    MineDict begin 
X	/FissureCount FissureCount 1 add def
X	FissureCount (F%) sprintf % construct a key
X    end % key
X    FissureDict exch 6 dict dup % + dict key value value
X    4 1 roll % value dict key value
X    put
X    % value
X    begin % x y length angle thickness
X	/Thickness exch def
X	/Angle exch def
X	/Length exch def
X	/y exch def
X	/x exch def
X    end
X} def
X
X/DrawFissures { % x y -
X    % initialise
X    /FissureDict growabledict def
X    MineDict /FissureCount 0 put
X
X    % Makefissures
X    4 {
X	% x y
X	2 copy
X	75 random mul random mul % length
X	360 random mul
X	HexDepth 2 mul 1 random random mul sub mul
X	MakeFissure
X    } repeat
X
X    pop pop
X
X    % draw the fissures spreading out
X    {
X	MineDict /FissureCount get 0 le { exit } if
X
X	FissureDict {
X	    % name dict
X	    begin
X		% name
X		Thickness setlinewidth
X		x y moveto
X		/x Length  Angle cos  mul x add def
X		/y Length  Angle sin  mul y add def
X		x y lineto stroke
X		/Angle Angle 90 random mul 45 sub add def
X		/Thickness Thickness 1 random random mul sub mul def
X		/Length Length 1 random random mul sub def
X		% name
X		mark exch
X		Length 5 lt   Thickness 0.1 le  or
X	    end % name bool
X
X	    {
X		% name
X		FissureDict exch undef
X		MineDict /FissureCount get 1 sub % n
X		MineDict /FissureCount 3 -1 roll put
X	    } {
X		pop % don't care about the the name
X	    } ifelse
X	    [ 0 50000 ] sleep
X	    pause pause pause
X	    mark ne {
X		deary me I found a bug if this happens.
X	    } if
X	} forall
X
X	MineDict /FissureCount get 0 le { exit } if
X
X	0.01 random lt {
X	    FissureDict dup
X	    MineDict /FissureCount get 1 add random mul cvi
X	    (F%) sprintf dup
X	    % dict dict key key
X	    3 1 roll known {
X		% dict key
X		get begin
X		    x y
X		    Length .75 mul
X		    Angle 90 random mul 45 sub add
X		    Thickness
X		end
X		MakeFissure
X	    } {
X		pop pop
X	    } ifelse
X	} if
X
X    } loop
X} def
X
X/ShowMines {
X    gsave
X	SetBombFont
X	MineBoard {
X	    % /Key Value
X	    aload pop
X	    CoordsToPoint
X	    % /Key x y
X	    exch HexWidth 2 div add exch 
X	    % x y of centre of hex
X	    BombGlyph DisplayItemSize % x y w h
X		2 div neg exch 2 div neg exch
X	    xyadd moveto
X	    BombGlyph DisplayItemPaint
X	    pop % get rid of /Key
X	} forall
X    grestore
X} def
X
X/IsThereAMineHere? { % Row Col -> bool
X    (%-%) sprintf
X    % name 
X    MineBoard exch known
X    % bool
X} def
X
X/LayMines { % rows cols n_mines LayMines -
X    10 dict begin
X	/n exch def
X	n 0 le {
X	    /n 1 def
X	} if
X	/Rows MineDict /MineRows get def
X	/Cols MineDict /MineCols get def
X
X	(New Game...) (%...)[n] sprintf /setfooter window1 send
X
X	/MineCount n def
X	{
X	    n 0 eq { exit } if
X
X	    % Lay one mine
X	    random Rows mul  cvi
X	    random Cols mul  cvi
X	    2 copy % Row Col Row Col
X	    2 copy % Row Col Row Col Row Col
X	    (%-%) sprintf dup % Row Col name name
X
X	    MineBoard exch known {
X		% It's already there...
X
X		% Row Col Row Col name
X
X		pop pop pop pop pop
X		% let other things run if we're checking the same cell a lot:
X		pause pause pause
X	    } {
X		% Row Col Row Col name
X		3 1 roll % row col name row col
X		2 array astore % row col name [row col]
X		MineBoard 3 1 roll % row col dict name [row col]
X		put % Row Col
X		GetNeighbours {
X		    dup null eq {
X			pop
X		    } {
X			aload pop
X			% AddNearbyMine:
X			2 copy Rows mul add % index
X			MineDict /NearbyMines get exch get
X			1 add
X			% Row Col value
X			3 1 roll % value Row Col
X			Rows mul add % value index
X			exch % index value
X			MineDict /NearbyMines get % index value array
X			3 1 roll
X			% Array index value
X			put
X		    } ifelse
X		} forall
X		/n n 1 sub def
X		n 16 mod 2 eq {
X    (New Game...) (Laying % Mines)[n] sprintf /setfooter window1 send
X		} if
X		pause 
X	    } ifelse
X	} loop
X
X	MineDict /MineCount MineCount put
X	MineDict /TotalMines MineCount put
X    end
X} def
X
X/HighScoreCanvas ClassCanvas
Xdictbegin
X    /EntryCount 0 def
X    /MyScore 0 def
X    /HighScores 0 def
X    /f 0 def % file handle
X    /FilePath 0 def
X    /FileName (hexsweeper.scores) readonly def
X    /MyWidth 200 def
X    /MyHeight 40 def
X    /WidestScore 550 def
X    /ScoreTextSize 16 def
X    % MyScoreGlyph is a right-pointing arrow:
X    /MyScoreGlyph [ (\355) /ZapfDingbats findfont ScoreTextSize scalefont ]
X    readonly def
Xdictend
Xclassbegin
X    /SetFilePath {
X	/FilePath exch promote
X    } def
X
X    /minsize {
X	100 40
X    } def
X
X    /ReadScoreFile {
X	[
X	    (/usr/games/lib)
X	    (/usr/local/games/lib)
X	    { (HOME) getenv } stopped { (/tmp) } if
X	] /SetFilePath self send
X
X	FileName FilePath (r) filepathopen {
X	    /f exch promote % got a file
X	    % filepathopen left the correct path on the stack:
X	    % 1 array astore /SetFilePath self send
X	    pop
X
X	    % read the high score table
X
X	    % first, the number of entries:
X	    f 20 string readline {
X		/EntryCount exch cvi def
X	    } {
X		/EntryCount 0 def
X	    } ifelse
X
X	    % Allow a maximum of 30 entries:
X	    EntryCount 30 gt {
X		/EntryCount 30 def
X	    } if
X
X	    /EntryCount EntryCount promote
X
X	    /HighScores EntryCount 1 add array def
X	    /HighScores HighScores promote
X
X	    /n 0 def
X	    % now the actual entries
X
X	    /GillSans findfont ScoreTextSize scalefont setfont
X
X	    /WidestScore 0 promote
X
X	    0 1 EntryCount 1 sub {
X		f 100 string readline {
X		    % int string   
X		    dup % check to see if the string is wider than the max
X		    dup stringwidth pop % s s width
X		    exch cvi log cvi
X		    10 exch sub (0) stringwidth pop mul add
X		    WidestScore max /WidestScore exch def
X		    HighScores 3 1 roll put
X		    /n n 1 add def
X		} {
X		    pop pop exit
X		} ifelse
X	    } for
X
X	    /EntryCount n def
X	    /EntryCount n promote
X
X	    f closefile
X	    /f 0 promote
X	    /WidestScore
X		WidestScore MyScoreGlyph DisplayItemSize pop 1.2 mul add
X	    promote
X	} {
X	     pop
X	     /EntryCount 0 promote
X	    /HighScores 1 array promote
X	} ifelse
X    } def
X
X    /preferredsize {
X	WidestScore 20 add
X	31 18 mul 20 add % 32 is max No. of high scores + 1
X    } def
X
X    /WriteScoreFile {
X	FileName FilePath (w) filepathopen {
X	    /f exch promote
X	    EntryCount 30 gt {
X		/EntryCount 30 promote
X	    } if
X	    f  EntryCount 10 string cvs  writestring
X	    f (\n) writestring
X	    0 1 HighScores length 1 sub {
X		HighScores exch get
X		dup null ne {
X		    f exch writestring
X		    f (\n) writestring
X		} if
X	    } for
X	    f closefile
X	    /f 0 promote
X	    % filepathopen left the correct path on the stack:
X	    (Wrote score file %) sprintf
X	    MineDict /Score get (Score: %) sprintf
X	    /setfooter window1 send
X	} {
X	    (Couldn't write score file %) sprintf  (oops)
X					2 copy /setfooter highscore_win send
X					/setfooter window1 send
X	    % handle errors (urp)
X	} ifelse
X    } def
X
X    /SetHighScore {
X	ReadScoreFile
X	MineDict begin
X	    %% who am I?
X	    /UserName
X		{ (LOGNAME) getenv } stopped {
X		    { (USER) getenv } stopped {
X			(unknown) % unknown user...
X		    } if
X		} if
X	    def
X
X	    %% Score:
X	    %% metric is
X	    %% Number Of Mines ^ 2/ ( Row * Cols * max(Time, 0.25) )
X	    /Score
X		TotalMines  MineRows MineCols mul
X		/GetDifficulty canvas1 send mul  mul
X		SecondsSoFar dup 0 eq { pop 0.25 } if
X		div
X		36 mul % well, lots of sixes in Hexsweeper :-)
X		cvi
X	    def
X
X	    % \320 is an em dash (---)
X	    (% \320 % \320 Mines: %; Time: %; Grid: % x %) [
X		Score
X		UserName
X		TotalMines
X		SecondsSoFar
X		MineCols
X		MineRows
X	    ] sprintf % leave the string on the stack
X	end % MineDict
X	/MyScore exch promote
X	/HighScores HighScores dup EntryCount MyScore put promote
X
X	/e EntryCount 1 add array def
X
X	EntryCount 30 lt {
X	    /EntryCount EntryCount 1 add promote
X	} if
X
X	0 1 e length 1 sub {
X	    dup HighScores exch get % n score
X	    dup null eq {
X		pop exit
X	    } {
X		% n score
X		e 3 1 roll put
X	    } ifelse
X	} for
X
X	/HighScores e { cvi exch cvi exch lt } quicksort promote
X
X	WriteScoreFile
X	ShowHighScores
X    } def
X
X    /Paint {
X	gsave
X	    Update
X	grestore
X    } def
X
X    /Update { % update high score table on screen
X	self setcanvas
X	gsave
X	    BackgroundColor FillCanvas
X
X	    ReadScoreFile
X
X	    /GillSans findfont ScoreTextSize scalefont setfont
X	    FG setcolor
X	    /bbox self send /MyHeight exch def /MyWidth exch def pop pop
X	    10 MyHeight 10 sub moveto
X	    0 1 EntryCount 1 sub {
X		HighScores exch get % array
X		dup null eq { pop pop exit } if
X		currentpoint exch pop 10 exch moveto
X		0 -18 rmoveto
X		gsave
X		    currentpoint 3 -1 roll % x y string
X		    dup MyScore eq {
X			MyScoreGlyph DisplayItemPaint
X			(You made the high score!) ()
X			    /setfooter highscore_win send
X			    pause pause pause
X		    } if
X		    3 1 roll
X		    MyScoreGlyph DisplayItemSize pop 1.2 mul 0 xyadd moveto
X		    % allow room for 10 digits
X		    dup cvi log cvi
X		    10 exch sub (0) stringwidth pop mul 0 rmoveto
X		    show
X		    pause
X		grestore
X	    } for
X	grestore
X    } def
Xclassend def
X
X/ShowHighScores {
X    /Update highscore_can send
X    /reshaped? highscore_win send not {
X	/place highscore_win send
X    } if
X    /pin highscore_win send
X    /totop highscore_win send
X    /Footer? true /setattribute highscore_win send
X    /map highscore_win send
X} def
X
X/HelpCanvas ClassCanvas
Xdictbegin
X    /vspace 18 def
X    /textsize 16 def
Xdictend
Xclassbegin
X    % stolen shamelessly from $OPENWINHOME/demo/fontview
X    /minsize {
X	300 425
X    } def
X
X    /firstline {
X	10 395 moveto
X    } def
X
X    /nextline {
X	currentpoint exch pop
X	vspace sub 10 exch moveto
X    } def
X
X    /BackgroundColor {
X	Color {
X	    BG
X	} {
X	    1 1 1 rgbcolor
X	} ifelse
X	dup /BackgroundColor exch promote
X    } def
X
X    /Paint {
X	BackgroundColor FillCanvas
X
X	ForegroundColor setcolor
X	/Palatino-Roman findfont textsize scalefont setfont
X
X	firstline (HexSweeper) show
X	nextline /Symbol findfont textsize scalefont setfont (\343) show
X	/Palatino-Roman findfont textsize scalefont setfont
X	( Liam Quin, 1992     \(lee@sq.com\)) show
X
X	nextline ( ) show
X	nextline (HexSweeper  is a version of the VMS) show
X	nextline (minesweeper game for OpenWindows 3.) show
X	nextline ( ) show
X
X	nextline (The game window shows a number of) show
X	nextline (hexagons.  There are explosive mines) show
X	nextline (under some of them.  You must put a) show
X	nextline (Mark \(`m' or middle button\) over every) show
X	nextline (mine, but ) show
X	currentfont
X	/Palatino-Italic findfont textsize scalefont setfont
X	(not) show
X	setfont
X	( over any empty hexagons.) show
X	nextline (In order to help you, when you step on) show
X	nextline (a hexagon \(press the left mouse buttom) show
X	nextline (over a it, or press the space bar\) the) show
X	nextline (number of mines under the adjoning) show
X	nextline (hexagons will be shown.  If there are no) show
X	nextline (nearby mines, you could step safely on) show
X	nextline (all of the nearby hexagons, but that) show
X	nextline (would be tedious, so HexSweeper does) show
X	nextline (it for you.) show
X	nextline (Press `s' to see the high scores, and) show
X	nextline (`q' to quit.   Oh, and have fun!) show
X    } def
Xclassend def
X
X/ShowHelp {
X    /reshaped? help_win send not {
X	/place help_win send
X    } if
X    /pin help_win send
X    /totop help_win send
X    /map help_win send
X} def
X
X/HexCanvas ClassCanvas
Xdictbegin
X    /canvasWidth HexHDelta 6 mul def
X    /canvasHeight HexHeight 6 mul def
X    /Difficulty 1 6 div def
X
X    /MineFont /Palatino-Roman findfont HexHWidth 1.5 div scalefont def
X    /OldX -20000 def
X    /OldY -30000 def
Xdictend
Xclassbegin
X    %% default window size
X
X    /preferredsize {
X	550 300
X	% HexHDelta 10 mul HexDWidth add 2 add
X	% HexHeight 6 mul HexDHeight add 2 add
X    } def
X
X    /minsize {
X	HexWidth 5 mul
X	HexHeight 4 mul
X    } def
X
X    /SetDifficulty {
X	/Difficulty exch promote
X	Difficulty 1.0 gt Difficulty 0 le {
X	    /Difficulty 1 6 div def
X	} if
X    } def
X
X    /GetDifficulty { Difficulty } def
X
X    /SetOldXY {
X	self begin
X	    /OldY exch def /OldY OldY promote
X	    /OldX exch def /OldX OldX promote
X	end
X    } def
X
X    /ChangeFont {
X	/item exch send
X	aload pop   % this seems to be a bug work around 
X
X	/HexFont exch 1 array astore cvx def
X	/HexBoldFont HexFont def
X	MakeGlyphs
X	/PaintAll self send
X    } def
X
X    /StopTimer {
X	MineDict /GameInProgress false put
X	MineDict /TimerInterest known {
X	    MineDict begin
X		/Counting false def % stop the timer!
X		TimerInterest null ne {
X		    TimerInterest revokeinterest
X		    /TimerInterest null def
X		} if
X	    end
X	} {
X	    MineDict /Counting false put
X	} ifelse
X    } def
X
X    /EndTimer {
X	HexTimerProcess killprocess
X	StopTimer
X    } def
X
X    /StartTimer {
X	MineDict /Counting get {
X	    StopTimer
X	} if
X	MineDict begin
X	    /Counting true def
X	    /SecondsSoFar 0 def
X	    /TimerInterest createevent dup begin
X		/Name 1 dict dup begin
X		    /HexTimerEvent {
X			/HexTimer canvas1 send
X		    } def
X		end def
X		/Action (HexTimerEvent) def
X	    end def
X	    TimerInterest expressinterest
X	end
X    } def
X
X    /HexTimer {
X	MineDict begin
X	    Counting {
X		/SecondsSoFar SecondsSoFar 1 add def
X
X		    (% Mines left)[MineCount] sprintf
X		    (% seconds)[SecondsSoFar] sprintf
X		/setfooter window1 send
X	    } if
X	end
X	pop
X    } def
X
X
X    /MarkHex { % x y MarkHex
X	% x y
X	MineDict /Counting get not {
X	    StartTimer
X	} if
X	gsave
X	    2 copy Draw3DHexAt
X	    2 copy exch % x' y' y' x'
X	    HexWidth 2 div add exch % x' y' x+ y'
X	    MarkGlyph DisplayItemSize % x y x' y' w h
X		2 div neg exch 2 div neg exch
X	    % x y x y w h
X	    xyadd moveto
X	    % x y of leftmost corner
X	    FG setcolor
X	    MarkGlyph DisplayItemPaint
X	    % x y
X	    2 copy PointToCoords IsThereAMineHere? {
X		%  x y
X		2 copy
X		PointToCoords (%-%) sprintf PlacesBeen exch true put % -
X		MineDict begin
X		    /MineCount MineCount 1 sub def
X		    MineCount 0 eq {
X			StopTimer
X			() (You won in only % seconds!) [SecondsSoFar] sprintf
X						    /setfooter window1 send
X			VisualEffectForWinning
X			/SetHighScore highscore_can send
X		    } {
X			pop pop
X		    } ifelse
X		end % MineDict
X	    } {
X		2 copy % x y
X		WrongMarkGlyph DisplayItemSize % x y x y w h
X		    2 div neg exch 2 div neg HexWidth 2 div add exch
X		xyadd moveto
X		WrongMarkGlyph DisplayItemPaint
X		StopTimer
X		% x y
X		VisualEffectForLosing
X		% -
X		ShowMines
X	    } ifelse
X	grestore
X    } def
X
X    /DrawBoard { % width height DrawBoard -
X	18 dict begin
X	    /BoardHeight exch def
X	    /BoardWidth exch def
X	    % We will use an off-screen canvas to hold two columns of hexes -
X	    % actually from the middle of one through all of another and on to
X	    % the middle of a third.  We can then repeat this canvas to draw the
X	    % game board quickly.
X
X	    /TmpCan canvas1 newcanvas def
X	    /TmpWid HexWidth HexHWidth add def
X
X	    /TinyCan canvas1 newcanvas def
X	    TinyCan 0 0 HexWidth 2 mul HexHWidth add HexHeight rectpath reshapecanvas
X	    TmpCan 0 0
X	    % width:
X	    TmpWid
X	    % height:
X	    MineDict /MineRows get HexHeight mul HexDHeight add
X	    rectpath reshapecanvas
X
X	    % TmpCan /Mapped true put % for debugging
X	    % TinyCan /Mapped true put
X
X	    TinyCan setcanvas
X	    gsave
X		BG FillCanvas
X		% Draw things HexDHeight "too low"...
X
X		0 0 Draw3DHexAt
X		0 HexHeight Draw3DHexAt
X		HexHDelta HexDHeight Draw3DHexAt
X		HexHDelta HexHeight HexDHeight add Draw3DHexAt % off the top?
X		HexHDelta 2 mul dup
X		% x
X		0 Draw3DHexAt
X		% x
X		HexHeight Draw3DHexAt
X	    grestore
X
X	    % draw Col 0 on the main canvas:
X	    canvas1 setcanvas
X	    gsave
X		BG FillCanvas
X
X		0 HexDHeight translate
X		% row 0 on the main screen:
X		0 1 MineDict /MineRows get 2 sub {
X		    TinyCan imagecanvas
X		    pop 0 HexHeight translate
X		} for
X	    grestore
X
X	    % have to do the corners ourselves:
X	    gsave
X		% bottom corners of cols 0 and 2:
X		0 HexDHeight Draw3DHexAt
X		HexWidth HexHWidth add HexDHeight Draw3DHexAt
X		% top corners of cols 0 and 2:
X		MineDict /MineRows get HexHeight mul HexDHeight sub
X		% y
X		dup
X		0 exch Draw3DHexAt
X		dup HexWidth HexHWidth add exch Draw3DHexAt
X		% the top middle one:
X		HexDHeight add HexHDelta exch Draw3DHexAt
X	    grestore
X
X	    % copy that to the off-screen canvas:
X	    gsave
X		TmpCan setcanvas
X		BG FillCanvas
X
X		HexWidth 2 div neg 0 translate
X		canvas1 imagecanvas
X
X	    grestore
X
X	    canvas1 setcanvas
X
X	    gsave
X
X		% draw central columns:
X		HexWidth 2 div 0 translate
X		/Col 1 def
X		1 2 MineDict /MineCols get 2 sub {
X		    pop
X		    TmpCan imagecanvas
X		    TmpWid 0 translate
X		    /Col Col 2 add def
X		} for
X
X	    grestore
X
X	    gsave
X		% draw rightmost column or two
X		/Col Col 1 sub def
X		/x Col HexHDelta mul def
X		x 0 moveto
X		/Indent HexDHeight def
X		Col 1 MineDict /MineCols get 1 sub {
X		    /Col exch def
X		    /y Indent def
X		    0 1 MineDict /MineRows get 1 sub {
X			/Row exch def
X			x y Draw3DHexAt
X
X			x HexDWidth add y moveto
X			% (%,%) [Row Col] sprintf show
X
X			/y y HexHeight add def
X		    } for
X		    /x x HexHDelta add def
X		    /Indent
X			Indent HexDHeight eq {
X			    HexHeight
X			} {
X			    HexDHeight
X			} ifelse
X		    def
X		} for
X	    grestore
X
X	end
X    } def
X
X    /NewGame {
X	MineDict /GameInProgress false put
X	/Busy /setvisualstate window1 send
X
X	% set the cursor to a stopwatch:
X	/busy /setcursor window1 send
X
X	(New Game...) (Stopping timer) /setfooter window1 send
X
X	MineDict /Counting get {
X	    StopTimer
X	} if
X	MineDict /MineCount 0 put
X
X	2 copy % Rows Cols Rows Cols
X
X	2 copy MineDict /MineCols get ne
X	exch MineDict /MineRows get ne or {
X	    (New Game...) (recomputing) /setfooter window1 send
X	    MineDict begin
X		/MineCols exch def
X		/MineRows exch def
X	    end
X	    RecomputeNeighbours
X	} {
X	    pop pop
X	} ifelse
X
X	(New Game...) (Clearing Board...) /setfooter window1 send
X	MineDict /MineRows get MineDict /MineCols get ClearMines
X	% Row Col
X	mul Difficulty mul cvi LayMines
X
X	MineDict /MineCols get HexHDelta mul
X	MineDict /MineRows get HexHeight mul
X	(New Game...) (Drawing new Board...) /setfooter window1 send
X	DrawBoard
X
X	/basic /setcursor window1 send
X	MineDict /GameInProgress true put
X	/Active /setvisualstate window1 send
X	-10000 -10003 /SetOldXY canvas1 send
X	(Ready!)() /setfooter window1 send
X    } def
X
X    /DoBang {
X	% x y
X	{
X	    % clearsendcontexts
X
X	    12 dict begin
X		/MakeBangPath {
X		    newpath
X		    296 240 moveto 248 320 lineto 200 232 lineto 144 320 lineto
X		    144 232 lineto 56 312 lineto 104 232 lineto 0 200 lineto
X		    104 192 lineto 48 64 lineto 136 144 lineto 152 0 lineto
X		    176 128 lineto 264 8 lineto 280 120 lineto 392 8 lineto
X		    368 120 lineto 488 80 lineto 416 144 lineto 512 224 lineto
X		    424 208 lineto 472 272 lineto 360 232 lineto 376 320 lineto
X		    closepath
X		} def
X
X		gsave
X		    newpath
X		    /TmpCan framebuffer newcanvas def
X
X		    0 0 moveto 2 2 scale
X		    TmpCan MakeBangPath
X		    reshapecanvas
X
X		    gsave framebuffer setcanvas
X			50 50 TmpCan movecanvas
X		    grestore
X
X		    TmpCan /Retained true put
X		    TmpCan /Mapped true put
X		    TmpCan setcanvas
X
X		    1 1 1 rgbcolor FillCanvas pause pause pause
X		    .9 .2 .2 rgbcolor FillCanvas pause pause pause
X		    1 1 1 rgbcolor FillCanvas pause pause pause
X		    .9 .2 .2 rgbcolor FillCanvas pause pause pause
X		    .9 .9 0 rgbcolor FillCanvas % a strong yellow
X		    pause pause pause
X		    % draw a red border
X		    .9 .2 .2 rgbcolor setcolor 10 setlinewidth
X		    MakeBangPath stroke
X
X		    % 120 150 moveto too low
X		    110 160 moveto
X		    /Rockwell-Bold findfont 70 scalefont setfont
X		    (B A N G !) show
X
X		    % x y
X		    pop pop
X		    [0 500000] sleep
X
X		    % TmpCan /Mapped false put
X
X		    pause pause pause
X		grestore
X	    end
X	} fork
X	% give the child a chance to run:
X	pause pause pause
X    } def
X
X    /StepGingerly {  % x y StepGingerly -
X	self setcanvas
X	gsave
X	    % Draw a flat (2D) hex here:
X	    FindHexWestPoint
X	    2 copy % x y x y 
X	    PreviewFootstep % side effect: flattens the hex (but no glyph drawn)
X	    OldX OldY PointToCoords % x y r c
X	    2 copy IsThereAMineHere? { % x y r c
X		StopTimer
X		VisualEffectForLosing
X		pop pop % x y
X		DoBang
X		ShowMines
X		-10000 -10007 /SetOldXY self send
X	    } {
X		% x y r c
X		2 copy % x y r c r c
X		GetNearbyMines % x y r c n
X		dup 0 eq {
X		    % x y r c n
X		    pop 4 2 roll pop pop
X		    % r c
X		    unblockinputqueue
X		    DoAutoWalk
X		} {
X		    % x y r c n
X		    5 1 roll pop pop
X		    % n x y
X		    2 copy 5 -1 roll % x y x y n
X		    DrawHexGlyphAt
X		    % x y
X		    PointToCoords (%-%) sprintf PlacesBeen exch true put % -
X		} ifelse
X
X		MineDict /Counting get not {
X		    StartTimer
X		} if
X
X	    } ifelse
X	grestore
X	-10000 -10003 /SetOldXY self send
X    } readonly def
X
X    /CancelPreviewFootstep { % - -> -
X	OldX -1000 ge {
X	    OldX OldY PointToCoords (%-%) sprintf
X	    PlacesBeen exch known not {
X		OldX OldY Draw3DHexAt % restore old hex
X	    } if
X	    -10000 -10000 /SetOldXY self send
X	} if
X    } def
X
X    /PreviewFootstep {  % x y PreviewFootstep -
X	% x y of western point
X	2 copy PointToCoords (%-%) sprintf
X	% x y name
X	PlacesBeen exch known not {
X	    2 copy Draw2DHexAt
X	} if
X	% x y
X	2 copy % x y x y
X	OldY ne % x y x bool
X	exch OldX ne % x y bool bool
X	or { % x y
X	    CancelPreviewFootstep
X	    % x y
X	    /SetOldXY canvas1 send
X	} {
X	    pop pop
X	} ifelse
X    } def
X
X    /TrackStart {
X	/E exch def
X	self setcanvas
X	E /Name get dup (LeftMouseButton) eq exch (MiddleMouseButton) eq or {
X	    -10001 -10002 /SetOldXY self send
X	    MineDict /GameInProgress get {
X		E /Coordinates get aload pop CheckInRange {
X		    E /Coordinates get aload pop
X		    FindHexWestPoint PreviewFootstep
X		    [/TrackCrossing /TrackMotion /TrackStop] true
X		} {
X		    nullarray true
X		} ifelse
X	    } {
X		(Use n to start a new game)() /setfooter window1 send
X		nullarray true
X	    } ifelse
X	} {
X	    false
X	} ifelse
X    } def
X
X    /TrackCrossing {
X	/TrackCancel self send
X    } def
X
X    /TrackMotion {
X	dup /E exch def begin
X	    E /Coordinates get aload pop
X	    2 copy CheckInRange {
X		self setcanvas
X		gsave
X		    FindHexWestPoint PreviewFootstep
X		grestore
X	    } {
X		self setcanvas
X		gsave
X		    CancelPreviewFootstep
X		grestore
X	    } ifelse
X	end
X	% /TrackMotion super send
X    } def
X
X    /TrackStop {
X	/E exch def
X	mark
X	self setcanvas
X	E /Coordinates get aload pop CheckInRange {
X	    E /Name get (LeftMouseButton) eq {
X		E /Coordinates get aload pop
X		2 copy FindHexWestPoint
X		PointToCoords (%-%) sprintf
X		PlacesBeen exch known {
X		    pop pop %% beep % bebop pebop bepop
X		} {
X		    StepGingerly
X		} ifelse
X	    } {
X		E /Name get (MiddleMouseButton) eq {
X		    E /Coordinates get aload pop 2 copy CheckInRange {
X			FindHexWestPoint
X			2 copy PointToCoords (%-%) sprintf
X			PlacesBeen exch known {
X			    beep pop pop
X			} {
X			    MarkHex
X			} ifelse
X		    } {
X			pop pop
X		    } ifelse
X		} {
X		    (Unknown Event) E /Name get /setfooter window1 send
X		} ifelse
X	    } ifelse
X	} {
X	    CancelPreviewFootstep
X	} ifelse
X	E /TrackStop super send
X	cleartomark
X    } def
X
X    /TrackCancel {
X	/E exch def
X	CancelPreviewFootstep
X	E /TrackCancel super send
X    } def
X
X    %% Input events (key presses):
X    /StandardKeyUp {
X	/E exch def
X	self setcanvas
X	E /Name get {
X	    12 18 {  % control-L, control-R --> redraw
X		/Paint self send
X	    }
X	    8 72 104 56 77 28 { % h, ? = help
X		ShowHelp
X	    }
X	    77 109 { % M, m = mark
X		E /Coordinates get aload pop
X		FindHexWestPoint
X		2 copy PointToCoords (%-%) sprintf PlacesBeen exch known {
X		    beep pop pop
X		} {
X		    MineDict /GameInProgress get {
X			MarkHex
X		    } {
X			pop pop beep
X		    } ifelse
X		} ifelse
X	    }
X	    78 110 { % N, n - new game
X		MineDict /MineRows get
X		MineDict /MineCols get
X		NewGame
X	    }
X	    17 81 113 { % ^Q, Q, q --> quit
X		/QuitFromUser window1 send
X	    }
X	    19 83 115 { % ^S, s, S - show high scores
X		ShowHighScores
X		% Note: control-s to toggle cheat mode has been removed!
X	    }
X	    % p, properties
X	    16 {
X		pstack
X	    }
X	    32 { % space --> StepGingerly
X		E /Coordinates get aload pop
X		FindHexWestPoint 2 copy
X		PointToCoords (%-%) sprintf PlacesBeen exch known {
X		    beep pop pop
X		} {
X		    MineDict /GameInProgress get {
X			StepGingerly
X		    } {
X			pop pop beep
X		    } ifelse
X		} ifelse
X	    }
X	    /Default {
X		beep
X	    }
X	} case
X    } def
X    
X    /FunctionKeyUp {
X	/Name get /FunctionL3 eq {
X	    % Props. I wish I got a "Properties" event instead, though.
X	    % But you need to have selections if you do that.
X	    /ShowProps self send
X	} if
X    } def
X
X    /KeyStart { pop [ /StandardKeyUp /FunctionKeyUp ] true} def
X
X    %% Startup code:
X    /NewInit {
X	/OldX -10341 promote
X	/OldY -10342 promote % unusual numbers for easy spotting...
X
X	% Arrange to be allowed focus:
X	MineFont /setfont self send
X
X        /NewInit super send
X    } def
X
X    %% The hexes...
X    /Paint {
X	% self setcanvas initclip
X
X	gsave
X	    BG FillCanvas
X	grestore
X
X	(Drawing...) ( ) /setfooter window1 send
X	/Busy /setvisualstate window1 send
X
X	% canvas size -- TNT 3.0 Ref. p. 49
X	bbox /canvasHeight exch def /canvasWidth exch def pop pop
X	/Rows canvasHeight HexDHeight 2 div sub HexHeight div cvi def
X	/Cols canvasWidth HexHDelta div cvi def
X
X	Rows Cols NewGame
X
X	(Type h for help...) ( ) /setfooter window1 send
X
X	/Active /setvisualstate window1 send
X    } def
X
Xclassend def
X
X/canvas1 framebuffer /new HexCanvas send def
X/window1 canvas1 framebuffer /new ClassBaseWindow send def
XMyName /setlabel window1 send
X{
X    /PaintIcon {
X	HexHWidth % save so we can restore it later...
X
X	25 SetHexSizeFromFlat
X
X	20 dict begin
X	    gsave
X		IconFont setfont
X
X		0 0 moveto
X		/s (SWEEPER) def
X		/t [
X		    (HEX)
X		    IconFont 2 scalefont
X		    0 0.5 0.5 rgbcolor
X		] def
X		s show
X		t DisplayItemSize /ty exch def /tx exch def
X
X		% Move above the icon name
X		0
X		s DisplayItemSize exch pop % y
X		translate
X
X		% Draw a hex
X		0 HexDHeight Draw3DHexAt
X
X		% move to middle of bottom left diagonal:
X		HexDWidth 2 div HexDHeight 2 div translate
X
X		% draw the word HEX
X
X		30 rotate
X		
X		0 0 moveto
X		% centre of the hex is at (HexHWidth) * sqrt3 / 2, 0
X		HexHWidth sqrt3 mul 2 div  0
X
X		% centre of hex on stack...
X		tx 2 div neg  ty 2 div neg xyadd
X
X		moveto
X		t DisplayItemPaint
X	    grestore
X	end
X	% used the saved size on the stack:
X	SetHexSizeFromFlat
X    } def
X
X    /QuitFromUser {
X	/EndTimer canvas1 send
X	currentprocess killprocess
X    } def
X
X} window1 send
X
X/new ClassEventMgr send dup /ProcessName (Hex) put
X
X/help_can framebuffer /new HelpCanvas send def
X/help_win help_can framebuffer /new ClassPopupWindow send def
Xhelp_win /addsubwindow window1 send
X(HexSweeper Help) /setlabel help_win send
X  
X/highscore_can framebuffer /new HighScoreCanvas send def
X/highscore_win highscore_can framebuffer /new ClassPopupWindow send def
Xhighscore_win /addsubwindow window1 send
X(HexSweeper High Scores) /setlabel highscore_win send
X 
X/nFonts 0 def
X
X/menu /Grid framebuffer /new ClassMenu send def
X[
X    [
X	(New game) {
X	    pop pop
X	    /PaintAll canvas1 send
X	}
X    ]
X    [ (Properties...) { pop pop beep } ]
X
X    [
X	(Difficulty)
X
X	/Grid framebuffer /new ClassMenu send
X	dup
X	[
X	    [
X		(Suicide) {
X		    pop pop
X		    .5 /SetDifficulty canvas1 send
X		    /PaintAll canvas1 send
X		}
X	    ]
X	    [
X		(Very Difficult) {
X		    pop pop
X		    .3 /SetDifficulty canvas1 send
X		    /PaintAll canvas1 send
X		}
X	    ]
X	    [
X		(Hard) {
X		    pop pop
X		    1 4.5 div /SetDifficulty canvas1 send
X		    /PaintAll canvas1 send
X		}
X	    ]
X	    [
X		(Normal) {
X		    pop pop
X		    1 6 div /SetDifficulty canvas1 send
X		    /PaintAll canvas1 send
X		}
X	    ]
X	    [
X		(Easy) {
X		    pop pop
X		    1 12 div /SetDifficulty canvas1 send
X		    /PaintAll canvas1 send
X		}
X	    ]
X	    [
X		(Dan Quayle) {
X		    pop pop
X		    1 100 div /SetDifficulty canvas1 send
X		    /PaintAll canvas1 send
X		}
X	    ]
X	]
X	exch /setitemlist exch send
X    ]
X
X    [
X	(HexFont)
X	/Grid framebuffer /new ClassMenu send
X	[
X	    FontDirectory {
X		type /nametype eq {
X		    pop
X		} {
X		    255 string cvs
X		    % exclude this font if it has OpenLook in the name.
X		    (OpenLook) search { pop pop pop } {
X			% or if it is the olgx font.
X			(olglyph) search { pop pop pop } {
X			    % or if it is a bogus Xt+ font.
X			    (12) search { pop pop pop } {
X				% or if it has an XLFD long name.
X				dup length 30 gt { pop } {
X				    /nFonts nFonts 1 add store
X				} ifelse
X			    } ifelse
X			} ifelse
X		    } ifelse
X		} ifelse
X	    } forall
X	] /gt quicksort /setitemlist 2 index send
X	/ChangeFont /setnotifier 2 index send
X	[ true nFonts 3 add 4 idiv 4 ] /setlayoutparameters 2 index send
X	/textfont 1 index send /FontName get
X	findfont 11 scalefont /settextfont 2 index send
X	true /setpinnable 2 index send
X    % @@
X    ]
X
X    [
X	(Scale)
X
X	/Grid framebuffer /new ClassMenu send
X	dup [
X	    [
X		(Texas) {
X		    pop pop % 300 was too big...
X		    200 /SetHexSizeFromFlat canvas1 send
X		    /PaintAll canvas1 send
X		}
X	    ]
X	    [
X		(Huge) {
X		    pop pop % 300 was too big...
X		    60 /SetHexSizeFromFlat canvas1 send
X		    /PaintAll canvas1 send
X		}
X	    ]
X	    [
X		(Big) {
X		    pop pop 40 /SetHexSizeFromFlat canvas1 send
X		    /PaintAll canvas1 send
X		}
X	    ]
X	    [
X		(Large) {
X		    pop pop 30 /SetHexSizeFromFlat canvas1 send
X		    /PaintAll canvas1 send
X		}
X	    ]
X	    [
X		(Normal) {
X		    pop pop 25 /SetHexSizeFromFlat canvas1 send
X		    /PaintAll canvas1 send
X		}
X	    ]
X	    [
X		(Smallish) {
X		    pop pop 20 /SetHexSizeFromFlat canvas1 send
X		    /PaintAll canvas1 send
X		}
X	    ]
X	    [
X		(Tiny) {
X		    pop pop 14 /SetHexSizeFromFlat canvas1 send
X		    /PaintAll canvas1 send
X		}
X	    ]
X	    [
X		(Welsh Cottage) {
X		    pop pop 7 /SetHexSizeFromFlat canvas1 send
X		    /PaintAll canvas1 send
X		}
X	    ]
X	] exch /setitemlist exch send
X    ]
X    [ (Quit) { pop pop /QuitFromUser window1 send } ]
X] /setitemlist menu send
Xtrue /setpinnable menu send
Xmenu /setmenu canvas1 send
Xtrue /setmenuable canvas1 send
Xtrue /setkeyable canvas1 send
Xtrue /settrackable canvas1 send
Xcanvas1 /Retained true put
Xwindow1 /Retained true put
X
X% .65 1 .1 hsbcolor  .65 .3 .9 hsbcolor /setcolors window1 send
X
X/activate window1 send
X/place window1 send
X/map window1 send
Xpause pause pause
X
X
Xbarefoot_boy
@@@End of hexsweeper
chmod +x hexsweeper
echo x - hexkill 1>&2
sed 's/^X//' >hexkill <<'@@@End of hexkill'
X#!/bin/sh
X
X# hexkill
X# modified version of pskill by Liam Quin
X
X# pskill
X#From: ks@cs.tut.fi (Syst{ Kari)
X# Newsgroups: comp.windows.news
X# Subject: A script for killing a ps-process
X# Message-ID: <KS.92May6132749@karikukko.cs.tut.fi>
X# Date: 6 May 92 11:27:49 GMT
X# Organization: Tampere Univ. of Technology, Finland.
X
X
X# If your application leaves looping processes, this is a script for you.
X# First, check the id with 'psps' and give it to this 'pskill' as an
X# argument.
X
Xpsh << %EOF
X%
X% pskill - kills a NeWS process
X% code is based on command 'psps'
X%
X% Kari Systa (ks@cs.tut.fi) 1992
X%
X%
X
X/NeWS 3 0 findpackage beginpackage
X
Xcurrentprocess /ProcessName (psps) put
X
Xdebugdict /getprocesses get exec {			% [process ...]
X    {							% > proc
X	dup 100 string cvs
X	(Hex) search {
X		pop pop pop
X		dup killprocess
X		(Killed: ) 1 index 100 string cvs append (\n) append print
X	} if
X	% pause
X    } forall
X    pop
X} forall
X
Xendpackage
X%EOF
X
Xexit $?
X
X--
X% This article represents my personal views.
X% Kari Systa, Tampere Univ. Technology, Box 553, 33101 Tampere, Finland
X% work: +358 31 162585      fax: +358 31 162913      home: +358 31 177412
X% Internet: ks@cs.tut.fi    X.400: C=fi ADMD=fumail O=TUT OU=CS S=ks
X
X
@@@End of hexkill
chmod +x hexkill
echo end of archive
exit 0
-- 
Liam Quin, lee@sq.com, SoftQuad, Toronto, 416 239-4801; the barefoot programmer
  lq-text (Unix text retrieval package) mailing list: lq-text-request@sq.com

Newsgroups: comp.windows.news