

--
-- Copyright (C) 2023  <fastrgv@gmail.com>
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-- GNU General Public License for more details.
--
-- You may read the full text of the GNU General Public License
-- at <http://www.gnu.org/licenses/>.
--





with snd4ada;

with gl, gl.binding, gl.pointers;
with glu, glu.binding, glu.pointers;
with glext, glext.binding, glext.pointers;

-------------------------------------------------------------
with System;
with Interfaces.C;
use  type interfaces.c.unsigned;
with Interfaces.C.Pointers;
with interfaces.c.strings;


----------------------------------------------------------------

with glfw3;		use glfw3;
with zoomwheel; use zoomwheel;

----------------------------------------------------------------

with matutils;
with stex;

with ada.numerics.generic_elementary_functions;

with Ada.Strings.Fixed;
with Ada.Strings.Unbounded;
use Ada.Strings.Unbounded;
with Ada.Strings.Unbounded.Text_IO;
use Ada.Strings.Unbounded.Text_IO;



with unchecked_deallocation;

with text_io;
with pngloader;
with gametypes;
with matutils;

with pictobj;
with pictobj2;

with shader;  use shader;



with Ada.Command_Line;
with Ada.Directories;
with SysUtils;

with gameutils; use gameutils;

----------------------------------------------------------------




procedure tomb5 is -- 4x5x4 with skull

	dirname: constant string := ada.directories.current_directory;
	onMac : boolean := (ada.strings.fixed.index( dirname, "MacOS", 1 ) > 1);
	onLinux : boolean := (ada.strings.fixed.index( dirname, "gnu", 1 ) > 1);



	prerestoreBuf, restoreBuf: unbounded_string;

	sel: array(1..9999) of integer;
	dir: array(1..9999) of character;
	nmoves: integer := 0;
	playscript : boolean := false;

	package myint_io is new text_io.integer_io(integer);


------- begin game specific code -------------------

mx, mz : constant integer := 4;
my     : constant integer := 5;


ncubes  : constant integer := mx*my*mz; -- total space volume: 80 cubelets

subtype rngm is integer range 1..ncubes;


empty : array(1..mx,1..my,1..mz) of boolean;



-- overall object drawing centroid (move to origin):
xxcc : constant float := float(mx)/2.0;
yycc : constant float := float(my)/2.0;
zzcc : constant float := float(mz)/2.0;

------- end game specific code -------------------



use text_io;
use gametypes;
use pngloader;
use matutils;
use gametypes.fmath;

use interfaces.c;
use interfaces.c.strings;
use glext;
use glext.pointers;
use glext.binding;
use gl;
use gl.binding;
use gl.pointers;



	origskin : boolean := true; -- false => Vadasz colors



procedure initEmptyMid is
begin

	for ix in 1..mx loop
		for iz in 1..mz loop
			for iy in 1..my loop
				empty(ix,iy,iz) := false;
			end loop;
		end loop;
	end loop;

	-- top layer is blank:
	for ix in 1..mx loop
	for iz in 1..mz loop
		empty(ix,my,iz):=true;
	end loop;
	end loop;

	-- middle of each face is blank:

	-- bottom face:
	for ix in 2..3 loop
	for iz in 2..3 loop
		empty(ix,1,iz):=true;
		empty(ix,1,iz):=true;
	end loop;
	end loop;

	-- top face:
	for ix in 2..3 loop
	for iz in 2..3 loop
		empty(ix,4,iz):=true;
		empty(ix,4,iz):=true;
	end loop;
	end loop;

	-- front face:
	for ix in 2..3 loop
	for iy in 2..3 loop
		empty(ix,iy,mz):=true;
		empty(ix,iy,mz):=true;
	end loop;
	end loop;

	-- rear face:
	for ix in 2..3 loop
	for iy in 2..3 loop
		empty(ix,iy,1):=true;
		empty(ix,iy,1):=true;
	end loop;
	end loop;

	-- left face:
	for iz in 2..3 loop
	for iy in 2..3 loop
		empty(1,iy,iz):=true;
		empty(1,iy,iz):=true;
	end loop;
	end loop;

	-- right face:
	for iz in 2..3 loop
	for iy in 2..3 loop
		empty(mx,iy,iz):=true;
		empty(mx,iy,iz):=true;
	end loop;
	end loop;



end initEmptyMid;





-- normal starting config: skull on top:
procedure initEmptyHi is
begin

	empty := (others=>(others=>(others=>false)));


	-- middle layer (y=3) is blank:
	for ix in 1..mx loop
	for iz in 1..mz loop
		empty(ix,3,iz):=true;
	end loop;
	end loop;

	-- top 2 edges all blank:
	for ix in 1..mx loop
	for iz in 1..mz loop
	if (ix=1) or (ix=mx) or (iz=1) or (iz=mz) then
		empty(ix,5,iz):=true;
		empty(ix,4,iz):=true;
	end if;
	end loop;
	end loop;

end initEmptyHi;





















-- define 9 puzzle pieces here, and initialize:
mp : constant integer := 9;
subtype rngp is integer range 1..mp;
subtype fparray is gfparray(rngp);
subtype iparray is giparray(rngp);

movedelay : constant float := 0.25; -- seconds to move a block
movebegin : float := 0.0;
oxc,oyc,ozc : integer;
grinding : array(rngp) of boolean := ( others=>false );
anyGrinding: boolean := false;


nun_texid : gluint;
num_texid : array(rngp) of gluint;
box_texid : gluint;



-- normal starting config: skull hi
centroidHi : constant iparray :=
-- piece-centroids initialization:
( 
		1=>(1,1,1), --
		2=>(1,1,3), --
		3=>(3,1,3), --
		4=>(3,1,1), --

		5=>(3,1,1), --
		6=>(3,1,3), --
		7=>(1,1,3), --
		8=>(1,1,1), --

		9=>(2,4,2)  --to be entombed in center
);


-- 1of2 possible solved positions:
centroidMidLo : constant iparray :=
-- piece-centroids initialization:
( 
		1=>(1,3,1), --ulp
		2=>(3,3,1), --urp
		3=>(1,3,3), --ula
		4=>(3,3,3), --ura

		5=>(1,1,1), --llp
		6=>(3,1,1), --lrp

		7=>(1,1,3), --lla
		8=>(3,1,3), --lra

		9=>(2,2,2)  --to be entombed in center
);

-- 2of2 possible solved positions:
centroidMidHi : constant iparray :=
-- piece-centroids initialization:
( 
		1=>(1,4,1), --ulp
		2=>(3,4,1), --urp
		3=>(1,4,3), --ula
		4=>(3,4,3), --ura

		5=>(1,2,1), --llp
		6=>(3,2,1), --lrp
		7=>(1,2,3), --lla
		8=>(3,2,3), --lra

		9=>(2,3,2)  --to be entombed in center
);





--Note that for each piece, its full extent is:
-- (p.x,p.y,p.z)...(p.x+1,p.y+1,p.z+1)

centroid : iparray;


--offsets from piece-centroid to space-centroid:
space : constant iparray :=
( 
		1=>(1,0,1), --ulp
		2=>(0,0,1), --urp
		3=>(1,0,0), --ula
		4=>(0,0,0), --ura

		5=>(1,1,1), --llp
		6=>(0,1,1), --lrp

		7=>(1,1,0), --lla
		8=>(0,1,0), --lra

		9=>(0,0,0)  --unused
);







windelay : constant float := 1.0;
testime : float := 0.0;

procedure xtest4winner is
	oktop, okbot : boolean := true;
begin

	for ix in 1..mx loop
	for iz in 1..mz loop
		oktop := oktop and empty(ix,my,iz);
	end loop;
	end loop;

	oktop := oktop and (centroid(9)(2)=2);

	for ix in 1..mx loop
	for iz in 1..mz loop
		okbot := okbot and empty(ix,1,iz);
	end loop;
	end loop;

	okbot := okbot and (centroid(9)(2)=3);

	winner := oktop or okbot;

	if winner then
		testime := float(glfwGetTime);
	end if;

end xtest4winner;


normalMode : boolean := true;

procedure test4winner is
begin

	if normalMode then
		winner := 
			(centroid=centroidMidLo)
			or (centroid=centroidMidHi);
	else
		winner := (centroid=centroidHi);
	end if;

	if winner then
		testime := float(glfwGetTime);
	end if;

end test4winner;









mxskin: constant integer := 4;
skin: integer := mxskin-1;

procedure setNextSkin is
	macpath: string := "../../../data/"; -- osx
	xinpath: string := "../../data/"; -- windows or linux
	nopath: string := "./data/"; --below current dir
	path: unbounded_string;
begin


	if onmac then
		append(path,macpath);
	elsif ada.directories.exists(nopath) then
		append(path,nopath);
	else
		append(path,xinpath);
	end if;



	skin := (1+skin) mod mxskin; --0..3
	myassert( (skin < mxskin) and (skin>=0) );

	if skin=0 then --Original colors

		nun_texid    := loadPng(mirror,to_string(path)&"none.png");

		num_texid(1) := loadPng(mirror,to_string(path)&"one.png");
		num_texid(2) := loadPng(mirror,to_string(path)&"two.png");
		num_texid(3) := loadPng(mirror,to_string(path)&"three.png");
		num_texid(4) := loadPng(mirror,to_string(path)&"four.png");
		num_texid(5) := loadPng(mirror,to_string(path)&"five.png");
		num_texid(6) := loadPng(mirror,to_string(path)&"six.png");
		num_texid(7) := loadPng(mirror,to_string(path)&"seven.png");
		num_texid(8) := loadPng(mirror,to_string(path)&"eight.png");

	elsif skin=1 then --wornRock

		nun_texid    := loadPng(mirror,to_string(path)&"worn.png");

		num_texid(1) := loadPng(mirror,to_string(path)&"worn1.png");
		num_texid(2) := loadPng(mirror,to_string(path)&"worn2.png");
		num_texid(3) := loadPng(mirror,to_string(path)&"worn3.png");
		num_texid(4) := loadPng(mirror,to_string(path)&"worn4.png");

		num_texid(5) := loadPng(mirror,to_string(path)&"worn5.png");
		num_texid(6) := loadPng(mirror,to_string(path)&"worn6.png");
		num_texid(7) := loadPng(mirror,to_string(path)&"worn7.png");
		num_texid(8) := loadPng(mirror,to_string(path)&"worn8.png");

	elsif skin=2 then --wood

		nun_texid    := loadPng(mirror,to_string(path)&"wood.png");

		num_texid(1) := loadPng(mirror,to_string(path)&"w1.png");
		num_texid(2) := loadPng(mirror,to_string(path)&"w2.png");
		num_texid(3) := loadPng(mirror,to_string(path)&"w3.png");
		num_texid(4) := loadPng(mirror,to_string(path)&"w4.png");

		num_texid(5) := loadPng(mirror,to_string(path)&"w5.png");
		num_texid(6) := loadPng(mirror,to_string(path)&"w6.png");
		num_texid(7) := loadPng(mirror,to_string(path)&"w7.png");
		num_texid(8) := loadPng(mirror,to_string(path)&"w8.png");

	elsif skin=3 then --granite

		nun_texid    := loadPng(mirror,to_string(path)&"gran.png");

		num_texid(1) := loadPng(mirror,to_string(path)&"g1.png");
		num_texid(2) := loadPng(mirror,to_string(path)&"g2.png");
		num_texid(3) := loadPng(mirror,to_string(path)&"g3.png");
		num_texid(4) := loadPng(mirror,to_string(path)&"g4.png");

		num_texid(5) := loadPng(mirror,to_string(path)&"g5.png");
		num_texid(6) := loadPng(mirror,to_string(path)&"g6.png");
		num_texid(7) := loadPng(mirror,to_string(path)&"g7.png");
		num_texid(8) := loadPng(mirror,to_string(path)&"g8.png");

	end if;

end setNextSkin;








procedure checkfile is
	ifil: file_type;
	i: integer;
	ch,junk: character;
	use myint_io;
begin

	set_unbounded_string(prerestoreBuf, "");

	if ada.directories.Exists("t5restore.txt") then

		text_io.open(ifil, in_file, "t5restore.txt");

		nmoves:=0;
		loop
			get(ifil, i);
			exit when i<0 or i>10;
			get(ifil, junk);
			get(ifil, ch);
			nmoves:=nmoves+1;
			sel(nmoves) := i;
			dir(nmoves) := ch;
			append(prerestoreBuf, integer'image(i) & " " & ch &" ");
			exit when nmoves>9_999;
		end loop;

		text_io.close(ifil);

		--put(integer'image(nmoves)); new_line;
		--if nmoves<10 then
		--for i in 1..nmoves loop
		--	put( integer'image( sel(i) ) );
		--	put(" "&dir(i));
		--	new_line;
		--end loop;
		--end if;

		playscript:=true;
	end if;


end checkfile;














procedure first_prep is -- main program setup
	macpath: string := "../../../data/"; -- osx
	xinpath: string := "../../data/"; -- windows or linux
	nopath: string := "./data/"; --below current dir
	path: unbounded_string;
	fontcol: constant vec4 := (0.0,0.0,0.0,1.0); --black

	fontfile: constant string := "data/NotoSans-Regular.ttf";
	annex: constant string := "../../";
	nerr: integer;
begin


	if onmac then
		append(path,macpath);
	elsif ada.directories.exists(nopath) then
		append(path,nopath);
	else
		append(path,xinpath);
	end if;

	snd4ada.initSnds;

	brick := snd4ada.initSnd(
		Interfaces.C.Strings.New_String(to_string(path)&"concrete_third.wav"));
	
	whoosh := snd4ada.initSnd(
		Interfaces.C.Strings.New_String(to_string(path)&"whoosh_4th.wav"));
	
	fanfare := snd4ada.initSnd(
		Interfaces.C.Strings.New_String(to_string(path)&"fanfare.wav"));
	
	shriek := snd4ada.initSnd(
		Interfaces.C.Strings.New_String(to_string(path)&"medusa.wav"));
	
	clap := snd4ada.initSnd(
		Interfaces.C.Strings.New_String(to_string(path)&"applause.wav"));
	

	if brick<0 or whoosh<0 or fanfare<0 or shriek<0 or clap<0 then
		put_line("snd4ada.initSnds ERROR");
		raise program_error;
	end if;


------- begin GLFW prep ---------------------------------------------------


	gameutils.InitGlfw( wwid,whit,fwid,fhit,"Reliquary5 - CrystalSkull");
	zoomwheel.enable(mainWin);

	-- prepare font -------------
	if ada.directories.exists(fontfile) then
		stex.InitFont ( fontfile );
	else
		stex.InitFont ( annex&fontfile );
	end if;

	stex.setColor( fontcol );
	stex.reSize(wwid,whit);

	glViewport(0,0,Fwid,Fhit);



	glgenvertexarrays(1, vertexarrayid'address );
	glbindvertexarray(vertexarrayid);

	glactivetexture(gl_texture0); -- moved here 5nov14 (outside main loop)

	glgenbuffers(1, vertbuff'address);
	glgenbuffers(1, rgbbuff'address);
	glgenbuffers(1, uvbuff'address);
	glgenbuffers(1, elembuff'address);


	glenable(gl_depth_test);
	gldepthfunc( gl_lequal );
	glenable( gl_cull_face );


	-- theoretically reduces aliasing (can't tell for sure):
	glEnable(GL_MULTISAMPLE);
	glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
	glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);

	glClearColor(0.4,0.4,0.4,1.0);


	nerr:=dumpGLerrorQueue("main 1"); 
	--prevents misleading messages in pngloader or loadshaders


--put_line("==1");

	box_texid := loadPng(mirror,to_string(path)&"fence.png");
	setNextSkin;


--put_line("==2");

	num_texid(9) := loadPng(mirror,to_string(path)&"tskull.png");

--put_line("==3");

	wall_texid := loadPng(mirror,to_string(path)&"granite.png");


	pgmTexShadID := loadshaders(to_string(path)&"texobj.vs",to_string(path)&"texobj.fs");
	matrixid := glgetuniformlocation(pgmtexshadid, pmvp);
	uniftex  := glgetuniformlocation(pgmtexshadid, pmyts);

	pgmTexID := loadshaders(to_string(path)&"otexobj.vs",to_string(path)&"otexobj.fs");
	matid := glgetuniformlocation(pgmtexid, pmvp);
	unitex  := glgetuniformlocation(pgmtexid, pmyts);


	-- note:  deep copies of structures are automatic in Ada
	--        (unless we use pointer assignments)
	if normalMode then
		centroid:=centroidHi;
		initEmptyHi;
	else
		centroid:=centroidMidLo;
		initEmptyMid;
	end if;

end first_prep;















-- the enclosing chainlink box:
procedure drawBigCube( po: pictobj2.pictangle ) is

	xr, zr : constant float := 2.02;
	    yr : constant float := 2.52;

	xc : constant float := xr - xxcc;
	yc : constant float := yr - yycc;
	zc : constant float := zr - zzcc;

	r,g,b : constant float := 0.5;
begin
	pictobj2.setrect( po, xc,yc,zc, xr,yr,zr, r,g,b);
	pictobj2.draw( po, vertbuff, uvbuff, elembuff );
end drawBigCube;












-- this is the 9th puzzle piece (skull)...double size: 2x2x2
procedure draw9( po: pictobj.pictangle; nowTime: float ) is
	tt, r,g,b, xc,yc,zc, xo,yo,zo, xt,yt,zt : float;
	ix,iy,iz: integer;
begin

	ix:=centroid(9)(1);
	iy:=centroid(9)(2);
	iz:=centroid(9)(3);

	xc:=float(ix)-xxcc;
	yc:=float(iy)-yycc;
	zc:=float(iz)-zzcc;

	xo:=float(oxc)-xxcc;
	yo:=float(oyc)-yycc;
	zo:=float(ozc)-zzcc;

	r:=0.6; g:=0.6; b:=0.6;

	if grinding(9) then
		tt := (nowTime-movebegin)/movedelay;
		if tt>1.0 then
			pictobj.setrect( po, xc,yc,zc, 0.95,0.95,0.95, r,g,b);
			grinding(9):=false;
		else
			xt := xo + tt*(xc-xo);
			yt := yo + tt*(yc-yo);
			zt := zo + tt*(zc-zo);
			pictobj.setrect( po, xt,yt,zt, 0.95,0.95,0.95, r,g,b);
		end if;
	else
		pictobj.setrect( po, xc,yc,zc, 0.95,0.95,0.95, r,g,b);
	end if;


	--pictobj.draw( po, vertbuff, rgbbuff, uvbuff, elembuff );
	pictobj.draw( po, vertbuff, uvbuff, elembuff );

end draw9;










-- these are individual 1x1 parts of each of corner pieces,
-- where the 8 corners have 4 cubelets each:
procedure drawCube( 
	po: pictobj.pictangle; 	ii, 
	cx,cy,cz, -- indexes of corner cubelet
	i,j,k, 
	ixc,iyc,izc : integer; nowTime: float ) is

	-- (xxcc,yycc,zzcc)==(2,3,2) : centroid of whole puzzle...

	-- (ixc,iyc,izc) = centroid of the current puzzle piece = PP,
	-- (i,j,k) = offset from PP-centroid to current cubelet
	-- (cx,cy,cz) = offset from PP-centroid to corner cubelet

	xc : float := float(ixc+i) -0.5 - xxcc;
	yc : float := float(iyc+j) -0.5 - yycc;
	zc : float := float(izc+k) -0.5 - zzcc;

	xo : float := float(oxc+i) -0.5 - xxcc;
	yo : float := float(oyc+j) -0.5 - yycc;
	zo : float := float(ozc+k) -0.5 - zzcc;

----------- begin addendum -------------------------

	-- cubelet centroid before offset to puzzle center:
	xcc : float := float(ixc+i) -0.5;
	ycc : float := float(iyc+j) -0.5;
	zcc : float := float(izc+k) -0.5;

	fr : float := 0.06; -- move cubelet-center toward corner cubelet
	dx : float := fr*(float(ixc+cx) - xcc);
	dy : float := fr*(float(iyc+cy) - ycc);
	dz : float := fr*(float(izc+cz) - zcc);

	-- this is to slightly separate the puzzle pieces
	-- but not their constituent cubelets.

----------- end addendum -------------------------


	sc: float := 0.47; --reduce radius from 0.5


	r,g,b, tt, xt,yt,zt : float;

begin

	if ii=1 then
		r:=0.2; g:=1.0; b:=0.2;
	elsif ii=2 then
		r:=1.0; g:=1.0; b:=0.2;
	elsif ii=3 then
		r:=0.2; g:=1.0; b:=1.0;
	elsif ii=4 then
		r:=1.0; g:=1.0; b:=1.0;
	elsif ii=5 then
		r:=0.2; g:=0.2; b:=0.2;
	elsif ii=6 then
		r:=1.0; g:=0.2; b:=0.3;
	elsif ii=7 then
		r:=0.2; g:=0.2; b:=1.0;
	elsif ii=8 then
		r:=1.0; g:=0.2; b:=1.0;
	elsif ii=9 then
		r:=0.6; g:=0.6; b:=0.6;
	end if;

	if grinding(ii) then
		tt := (nowTime-movebegin)/movedelay;
		if tt>1.0 then
			pictobj.setrect( po, xc+dx,yc+dy,zc+dz, sc,sc,sc, r,g,b);
			grinding(ii):=false;
		else
			xt := xo + tt*(xc-xo);
			yt := yo + tt*(yc-yo);
			zt := zo + tt*(zc-zo);
			pictobj.setrect( po, xt+dx,yt+dy,zt+dz, sc,sc,sc, r,g,b);
		end if;
	else
		pictobj.setrect( po, xc+dx,yc+dy,zc+dz, sc,sc,sc, r,g,b);
	end if;

	pictobj.draw( po, vertbuff, rgbbuff, uvbuff, elembuff );

end drawCube;






--------------------------------------------------------------------------

type vtype is array(0..1,0..1,0..1) of boolean;
wake, probe : vtype;
-- "wake" holds the locations to be vacated by next move
-- "probe" hold the locations to be occupied by next move
-- Both used to update the "empty" array.


function trynear(ii: rngp) return boolean is -- +Z
	ix,iy,iz : integer;
	ox,oy,oz : integer;
	sx,sy,sz : integer;
	ok, leadingVoid : boolean;
begin
	ox:=centroid(ii)(1);
	oy:=centroid(ii)(2);
	oz:=centroid(ii)(3);

	sx:=space(ii)(1);
	sy:=space(ii)(2);
	sz:=space(ii)(3);

	leadingVoid := (sz=1);



	for i in 0..1 loop
	for j in 0..1 loop
	for k in 0..1 loop
	if leadingVoid then -- (sz=1)

		if    i=sx and j/=sy and k/=sz then probe(i,j,k):=true;
		elsif i/=sx and j=sy and k/=sz then probe(i,j,k):=true;
		elsif i/=sx and j/=sy and k=sz then probe(i,j,k):=true;
		else probe(i,j,k):=false;
		end if;

	else -- trailing void (sz=0)

		if   i/=sx and j/=sy and k/=sz then probe(i,j,k):=true;
		elsif i=sx and j/=sy and k/=sz then probe(i,j,k):=true;
		elsif i/=sx and j=sy and k/=sz then probe(i,j,k):=true;
		--elsif i/=sx and j/=sy and k=sz then probe(i,j,k):=true;
		else probe(i,j,k):=false;
		end if;

	end if;
	end loop;
	end loop;
	end loop;



	-- next centroid:
	ix:=ox;
	iy:=oy;
	iz:=oz+1;

	-- next test location
	--iz:=iz+1;

	if iz+1>mz then
		return false;

	elsif ii/=9  then

		ok:=true;
		for i in 0..1 loop
		for j in 0..1 loop
		for k in 0..1 loop
			if probe(i,j,k) and not empty(ix+i,iy+j,iz+k) then
				ok:=false;
			end if;
		end loop;
		end loop;
		end loop;

		return ok;

	else -- ii=9

		if
			empty( ix+0,iy+0,iz+1 ) and
			empty( ix+1,iy+0,iz+1 ) and
			empty( ix+1,iy+1,iz+1 ) and
			empty( ix+0,iy+1,iz+1 )
		then
			return true;
		else
			return false;
		end if;

	end if; -- leadingVoid

end trynear;









function tryaway(ii: rngp) return boolean is -- -Z
	ix,iy,iz : integer;
	ox,oy,oz : integer;
	sx,sy,sz : integer;
	ok, leadingVoid : boolean;
begin
	ox:=centroid(ii)(1);
	oy:=centroid(ii)(2);
	oz:=centroid(ii)(3);

	sx:=space(ii)(1);
	sy:=space(ii)(2);
	sz:=space(ii)(3);

	leadingVoid := (sz=0);



	for i in 0..1 loop
	for j in 0..1 loop
	for k in 0..1 loop
	if leadingVoid then -- (sz=0)

		if    i=sx and j/=sy and k/=sz then probe(i,j,k):=true;
		elsif i/=sx and j=sy and k/=sz then probe(i,j,k):=true;
		elsif i/=sx and j/=sy and k=sz then probe(i,j,k):=true;
		else probe(i,j,k):=false;
		end if;

	else -- trailing void (sz=1)

		if   i/=sx and j/=sy and k/=sz then probe(i,j,k):=true;
		elsif i=sx and j/=sy and k/=sz then probe(i,j,k):=true;
		elsif i/=sx and j=sy and k/=sz then probe(i,j,k):=true;
		--elsif i/=sx and j/=sy and k=sz then probe(i,j,k):=true;
		else probe(i,j,k):=false;
		end if;

	end if;
	end loop;
	end loop;
	end loop;




	-- next centroid:
	ix:=ox;
	iy:=oy;
	iz:=oz-1;

	-- next test location
	--iz:=iz+0;


	if iz<1 then
		return false;

	elsif ii/=9  then

		ok:=true;
		for i in 0..1 loop
		for j in 0..1 loop
		for k in 0..1 loop
			if probe(i,j,k) and not empty(ix+i,iy+j,iz+k) then
				ok:=false;
			end if;
		end loop;
		end loop;
		end loop;

		return ok;

	else -- ii=9

		if
			empty( ix+0,iy+0,iz ) and
			empty( ix+1,iy+0,iz ) and
			empty( ix+1,iy+1,iz ) and
			empty( ix+0,iy+1,iz )
		then
			return true;
		else
			return false;
		end if;

	end if;

end tryaway;














function tryup(ii: rngp) return boolean is -- +Y
	ix,iy,iz : integer;
	ox,oy,oz : integer;
	sx,sy,sz : integer;
	ok, leadingVoid : boolean;
begin
	ox:=centroid(ii)(1);
	oy:=centroid(ii)(2);
	oz:=centroid(ii)(3);

	sx:=space(ii)(1);
	sy:=space(ii)(2);
	sz:=space(ii)(3);

	leadingVoid := (sy=1);



	for i in 0..1 loop
	for j in 0..1 loop
	for k in 0..1 loop
	if leadingVoid then -- (sy=1)

		if    i=sx and j/=sy and k/=sz then probe(i,j,k):=true;
		elsif i/=sx and j=sy and k/=sz then probe(i,j,k):=true;
		elsif i/=sx and j/=sy and k=sz then probe(i,j,k):=true;
		else probe(i,j,k):=false;
		end if;

	else -- trailing void (sy=0)

		if   i/=sx and j/=sy and k/=sz then probe(i,j,k):=true;
		elsif i=sx and j/=sy and k/=sz then probe(i,j,k):=true;
		--elsif i/=sx and j=sy and k/=sz then probe(i,j,k):=true;
		elsif i/=sx and j/=sy and k=sz then probe(i,j,k):=true;
		else probe(i,j,k):=false;
		end if;

	end if;
	end loop;
	end loop;
	end loop;




	-- next centroid:
	ix:=ox;
	iy:=oy+1;
	iz:=oz;

	-- next test location
	--iy:=iy+1;


	if iy+1>my then
		return false;

	elsif ii/=9  then

		ok:=true;
		for i in 0..1 loop
		for j in 0..1 loop
		for k in 0..1 loop
			if probe(i,j,k) and not empty(ix+i,iy+j,iz+k) then
				ok:=false;
			end if;
		end loop;
		end loop;
		end loop;

		return ok;

	else -- ii=9

		if
			empty( ix+0,iy+1,iz+0 ) and
			empty( ix+1,iy+1,iz+0 ) and
			empty( ix+1,iy+1,iz+1 ) and
			empty( ix+0,iy+1,iz+1 )
		then
			return true;
		else
			return false;
		end if;

	end if;

end tryup;












function trydown(ii: rngp) return boolean is -- -Y
	ix,iy,iz : integer;
	ox,oy,oz : integer;
	sx,sy,sz : integer;
	ok, leadingVoid : boolean;
begin
	ox:=centroid(ii)(1);
	oy:=centroid(ii)(2);
	oz:=centroid(ii)(3);

	sx:=space(ii)(1);
	sy:=space(ii)(2);
	sz:=space(ii)(3);

	leadingVoid := (sy=0);



	for i in 0..1 loop
	for j in 0..1 loop
	for k in 0..1 loop
	if leadingVoid then -- (sy=0)

		if    i=sx and j/=sy and k/=sz then probe(i,j,k):=true;
		elsif i/=sx and j=sy and k/=sz then probe(i,j,k):=true;
		elsif i/=sx and j/=sy and k=sz then probe(i,j,k):=true;
		else probe(i,j,k):=false;
		end if;

	else -- trailing void (sy=1)

		if   i/=sx and j/=sy and k/=sz then probe(i,j,k):=true;
		elsif i=sx and j/=sy and k/=sz then probe(i,j,k):=true;
		--elsif i/=sx and j=sy and k/=sz then probe(i,j,k):=true;
		elsif i/=sx and j/=sy and k=sz then probe(i,j,k):=true;
		else probe(i,j,k):=false;
		end if;

	end if;
	end loop;
	end loop;
	end loop;





	-- next centroid:
	ix:=ox;
	iy:=oy-1;
	iz:=oz;

	-- next test location
	--iy:=iy+0;


	if iy<1 then

		return false;

	elsif ii/=9  then

		ok:=true;
		for i in 0..1 loop
		for j in 0..1 loop
		for k in 0..1 loop
			if probe(i,j,k) and not empty(ix+i,iy+j,iz+k) then
				ok:=false;
			end if;
		end loop;
		end loop;
		end loop;

		return ok;

	else -- ii=9

		if
			empty( ix+0,iy,iz+0 ) and
			empty( ix+1,iy,iz+0 ) and
			empty( ix+1,iy,iz+1 ) and
			empty( ix+0,iy,iz+1 )
		then
			return true;
		else
			return false;
		end if;

	end if; -- leadingVoid

end trydown;

















function tryright(ii: rngp) return boolean is -- +X
	ix,iy,iz : integer;
	ox,oy,oz : integer;
	sx,sy,sz : integer;
	ok, leadingVoid : boolean;
begin
	ox:=centroid(ii)(1);
	oy:=centroid(ii)(2);
	oz:=centroid(ii)(3);

	sx:=space(ii)(1);
	sy:=space(ii)(2);
	sz:=space(ii)(3);

	leadingVoid := (sx=1);



	for i in 0..1 loop
	for j in 0..1 loop
	for k in 0..1 loop
	if leadingVoid then -- (sx=1)

		if    i=sx and j/=sy and k/=sz then probe(i,j,k):=true;
		elsif i/=sx and j=sy and k/=sz then probe(i,j,k):=true;
		elsif i/=sx and j/=sy and k=sz then probe(i,j,k):=true;
		else probe(i,j,k):=false;
		end if;

	else -- trailing void (sx=0)

		if   i/=sx and j/=sy and k/=sz then probe(i,j,k):=true;
		--elsif i=sx and j/=sy and k/=sz then probe(i,j,k):=true;
		elsif i/=sx and j=sy and k/=sz then probe(i,j,k):=true;
		elsif i/=sx and j/=sy and k=sz then probe(i,j,k):=true;
		else probe(i,j,k):=false;
		end if;

	end if;
	end loop;
	end loop;
	end loop;





	-- next centroid:
	ix:=ox+1;
	iy:=oy;
	iz:=oz;

	-- next test location
	--ix:=ix+1;


	if ix+1>mx then
		return false;

	elsif ii/=9  then

		ok:=true;
		for i in 0..1 loop
		for j in 0..1 loop
		for k in 0..1 loop
			if probe(i,j,k) and not empty(ix+i,iy+j,iz+k) then
				ok:=false;
			end if;
		end loop;
		end loop;
		end loop;

		return ok;

	else -- ii=9

		if
			empty( ix+1,iy+0,iz+0 ) and
			empty( ix+1,iy+1,iz+0 ) and
			empty( ix+1,iy+1,iz+1 ) and
			empty( ix+1,iy+0,iz+1 )
		then
			return true;
		else
			return false;
		end if;

	end if;

end tryright;
















function tryleft(ii: rngp) return boolean is -- -X
	ix,iy,iz : integer;
	ox,oy,oz : integer;
	sx,sy,sz : integer;
	ok, leadingVoid : boolean;
begin
	ox:=centroid(ii)(1);
	oy:=centroid(ii)(2);
	oz:=centroid(ii)(3);

	sx:=space(ii)(1);
	sy:=space(ii)(2);
	sz:=space(ii)(3);

	leadingVoid := (sx=0);



	for i in 0..1 loop
	for j in 0..1 loop
	for k in 0..1 loop
	if leadingVoid then -- (sx=0)

		if    i=sx and j/=sy and k/=sz then probe(i,j,k):=true;
		elsif i/=sx and j=sy and k/=sz then probe(i,j,k):=true;
		elsif i/=sx and j/=sy and k=sz then probe(i,j,k):=true;
		else probe(i,j,k):=false;
		end if;

	else -- trailing void (sx=1)

		if   i/=sx and j/=sy and k/=sz then probe(i,j,k):=true;
		--elsif i=sx and j/=sy and k/=sz then probe(i,j,k):=true;
		elsif i/=sx and j=sy and k/=sz then probe(i,j,k):=true;
		elsif i/=sx and j/=sy and k=sz then probe(i,j,k):=true;
		else probe(i,j,k):=false;
		end if;

	end if;
	end loop;
	end loop;
	end loop;





	-- next centroid:
	ix:=ox-1;
	iy:=oy;
	iz:=oz;

	-- next test location
	--ix:=ix+0;


	if ix<1 then
		return false;

	elsif ii/=9  then

		ok:=true;
		for i in 0..1 loop
		for j in 0..1 loop
		for k in 0..1 loop
			if probe(i,j,k) and not empty(ix+i,iy+j,iz+k) then
				ok:=false;
			end if;
		end loop;
		end loop;
		end loop;

		return ok;

	else -- ii=9

		if
			empty( ix,iy+0,iz+0 ) and
			empty( ix,iy+1,iz+0 ) and
			empty( ix,iy+1,iz+1 ) and
			empty( ix,iy+0,iz+1 )
		then
			return true;
		else
			return false;
		end if;

	end if;

end tryleft;


---------------------------------------------------------------------------




procedure movenear( kk: in out integer; nowTime: float ) is -- +Z
	ix,iy,iz : integer;
	sx,sy,sz : integer;
	leadingVoid : boolean;
begin

if not trynear(kk) then -- pick one that might make sense
	for i in 1..9 loop
		if trynear(i) then
			kk:=i;
			exit;
		end if;
	end loop;
end if;


if trynear(kk) then

	append(restoreBuf, integer'image(kk) & " n ");

	oxc:=centroid(kk)(1);
	oyc:=centroid(kk)(2);
	ozc:=centroid(kk)(3);
 
	sx:=space(kk)(1);
	sy:=space(kk)(2);
	sz:=space(kk)(3);

	ix:=oxc;
	iy:=oyc;
	iz:=ozc;

	leadingVoid := (sz=1);

	for i in 0..1 loop
	for j in 0..1 loop
	for k in 0..1 loop
	if leadingVoid then -- (sz=1)

		if   i/=sx and j/=sy and k/=sz then 
			probe(i,j,k):=false;
			wake(i,j,k):=true;
		elsif i=sx and j/=sy and k/=sz then 
			probe(i,j,k):=true;
			wake(i,j,k):=true;
		elsif i/=sx and j=sy and k/=sz then 
			probe(i,j,k):=true;
			wake(i,j,k):=true;
		elsif i/=sx and j/=sy and k=sz then 
			probe(i,j,k):=true;
			wake(i,j,k):=false;
		else 
			probe(i,j,k):=false;
			wake(i,j,k):=false;
		end if;

	else -- trailing void (sz=0)

		if   i/=sx and j/=sy and k/=sz then 
			probe(i,j,k):=true;
			wake(i,j,k):=false;
		elsif i=sx and j/=sy and k/=sz then 
			probe(i,j,k):=true;
			wake(i,j,k):=true;
		elsif i/=sx and j=sy and k/=sz then 
			probe(i,j,k):=true;
			wake(i,j,k):=true;
		elsif i/=sx and j/=sy and k=sz then 
			probe(i,j,k):=false;
			wake(i,j,k):=true;
		else 
			probe(i,j,k):=false;
			wake(i,j,k):=false;
		end if;

	end if;
	end loop;
	end loop;
	end loop;




	if kk=9 then -- (easy)

		-- trailing face:
		empty( ix+0,iy+0,iz+0 ):=true;
		empty( ix+1,iy+0,iz+0 ):=true;
		empty( ix+1,iy+1,iz+0 ):=true;
		empty( ix+0,iy+1,iz+0 ):=true;

		-- make the move:
		centroid(kk)(3):=centroid(kk)(3)+1;
		iz:=centroid(kk)(3);

		-- leading face:
		empty( ix+0,iy+0,iz+1 ):=false;
		empty( ix+1,iy+0,iz+1 ):=false;
		empty( ix+1,iy+1,iz+1 ):=false;
		empty( ix+0,iy+1,iz+1 ):=false;

	else

		-- trailing face:
		for i in 0..1 loop
			for j in 0..1 loop
				for k in 0..1 loop
					if wake(i,j,k) then
						empty(ix+i,iy+j,iz+k):=true;
					end if;
				end loop;
			end loop;
		end loop;

		-- make the move:
		centroid(kk)(3):=centroid(kk)(3)+1;
		iz:=centroid(kk)(3);

		-- leading face:
		for i in 0..1 loop
			for j in 0..1 loop
				for k in 0..1 loop
					if probe(i,j,k) then
						empty(ix+i,iy+j,iz+k):=false;
					end if;
				end loop;
			end loop;
		end loop;

	end if;

	test4winner;

	if not mute then 
	snd4ada.playSnd(whoosh); 
	end if;

	grinding(kk):=true;
	movebegin:=nowTime;

end if; --trynear

end movenear;
-----------------------------------------------------------



procedure moveaway( kk: in out integer; nowTime: float ) is -- -Z
	ix,iy,iz : integer;
	sx,sy,sz : integer;
	leadingVoid : boolean;
begin
 
if not tryaway(kk) then -- pick one that might make sense
	for i in 1..9 loop
		if tryaway(i) then
			kk:=i;
			exit;
		end if;
	end loop;
end if;



if tryaway(kk) then

	append(restoreBuf, integer'image(kk) & " a ");

	oxc:=centroid(kk)(1);
	oyc:=centroid(kk)(2);
	ozc:=centroid(kk)(3);
 
	sx:=space(kk)(1);
	sy:=space(kk)(2);
	sz:=space(kk)(3);

	ix:=oxc;
	iy:=oyc;
	iz:=ozc;

	leadingVoid := (sz=0);


	for i in 0..1 loop
	for j in 0..1 loop
	for k in 0..1 loop
	if leadingVoid then -- (sz=0)

		if   i/=sx and j/=sy and k/=sz then 
			probe(i,j,k):=false;
			wake(i,j,k):=true;
		elsif i=sx and j/=sy and k/=sz then 
			probe(i,j,k):=true;
			wake(i,j,k):=true;
		elsif i/=sx and j=sy and k/=sz then 
			probe(i,j,k):=true;
			wake(i,j,k):=true;
		elsif i/=sx and j/=sy and k=sz then 
			probe(i,j,k):=true;
			wake(i,j,k):=false;
		else 
			probe(i,j,k):=false;
			wake(i,j,k):=false;
		end if;

	else -- trailing void (sz=1)

		if   i/=sx and j/=sy and k/=sz then 
			probe(i,j,k):=true;
			wake(i,j,k):=false;
		elsif i=sx and j/=sy and k/=sz then 
			probe(i,j,k):=true;
			wake(i,j,k):=true;
		elsif i/=sx and j=sy and k/=sz then 
			probe(i,j,k):=true;
			wake(i,j,k):=true;
		elsif i/=sx and j/=sy and k=sz then 
			probe(i,j,k):=false;
			wake(i,j,k):=true;
		else 
			probe(i,j,k):=false;
			wake(i,j,k):=false;
		end if;

	end if;
	end loop;
	end loop;
	end loop;




	if kk=9 then -- (easy)

		-- trailing face:
		empty( ix+0,iy+0,iz+1 ):=true;
		empty( ix+1,iy+0,iz+1 ):=true;
		empty( ix+1,iy+1,iz+1 ):=true;
		empty( ix+0,iy+1,iz+1 ):=true;

		-- make the move:
		centroid(kk)(3):=centroid(kk)(3)-1;
		iz:=centroid(kk)(3);

		-- leading face:
		empty( ix+0,iy+0,iz+0 ):=false;
		empty( ix+1,iy+0,iz+0 ):=false;
		empty( ix+1,iy+1,iz+0 ):=false;
		empty( ix+0,iy+1,iz+0 ):=false;

	else

		-- trailing face:
		for i in 0..1 loop
			for j in 0..1 loop
				for k in 0..1 loop
					if wake(i,j,k) then
						empty(ix+i,iy+j,iz+k):=true;
					end if;
				end loop;
			end loop;
		end loop;

		-- make the move:
		centroid(kk)(3):=centroid(kk)(3)-1;
		iz:=centroid(kk)(3);

		-- leading face:
		for i in 0..1 loop
			for j in 0..1 loop
				for k in 0..1 loop
					if probe(i,j,k) then
						empty(ix+i,iy+j,iz+k):=false;
					end if;
				end loop;
			end loop;
		end loop;

	end if;


	test4winner;

	if not mute then 
	snd4ada.playSnd(whoosh); 
	end if;

	grinding(kk):=true;
	movebegin:=nowTime;

end if; --tryaway


end moveaway;




procedure moveleft( kk: in out integer; nowTime: float ) is -- -X
	ix,iy,iz : integer;
	sx,sy,sz : integer;
	leadingVoid : boolean;
begin
 
if not tryleft(kk) then -- pick one that might make sense
	for i in 1..9 loop
		if tryleft(i) then
			kk:=i;
			exit;
		end if;
	end loop;
end if;



if tryleft(kk) then

	append(restoreBuf, integer'image(kk) & " l ");

	oxc:=centroid(kk)(1);
	oyc:=centroid(kk)(2);
	ozc:=centroid(kk)(3);
 
	sx:=space(kk)(1);
	sy:=space(kk)(2);
	sz:=space(kk)(3);

	ix:=oxc;
	iy:=oyc;
	iz:=ozc;

	leadingVoid := (sx=0);


	for i in 0..1 loop
	for j in 0..1 loop
	for k in 0..1 loop
	if leadingVoid then -- (sx=0)

		if   i/=sx and j/=sy and k/=sz then 
			probe(i,j,k):=false;
			wake(i,j,k):=true;
		elsif i=sx and j/=sy and k/=sz then 
			probe(i,j,k):=true;
			wake(i,j,k):=false;
		elsif i/=sx and j=sy and k/=sz then 
			probe(i,j,k):=true;
			wake(i,j,k):=true;
		elsif i/=sx and j/=sy and k=sz then 
			probe(i,j,k):=true;
			wake(i,j,k):=true;
		else 
			probe(i,j,k):=false;
			wake(i,j,k):=false;
		end if;

	else -- trailing void (sx=1)

		if   i/=sx and j/=sy and k/=sz then 
			probe(i,j,k):=true;
			wake(i,j,k):=false;
		elsif i=sx and j/=sy and k/=sz then 
			probe(i,j,k):=false;
			wake(i,j,k):=true;
		elsif i/=sx and j=sy and k/=sz then 
			probe(i,j,k):=true;
			wake(i,j,k):=true;
		elsif i/=sx and j/=sy and k=sz then 
			probe(i,j,k):=true;
			wake(i,j,k):=true;
		else 
			probe(i,j,k):=false;
			wake(i,j,k):=false;
		end if;

	end if;
	end loop;
	end loop;
	end loop;




	if kk=9 then -- (easy)

		-- trailing face:
		empty( ix+1,iy+0,iz+0 ):=true;
		empty( ix+1,iy+0,iz+1 ):=true;
		empty( ix+1,iy+1,iz+0 ):=true;
		empty( ix+1,iy+1,iz+1 ):=true;

		-- make the move:
		centroid(kk)(1):=centroid(kk)(1)-1;
		ix:=centroid(kk)(1);

		-- leading face:
		empty( ix+0,iy+0,iz+0 ):=false;
		empty( ix+0,iy+0,iz+1 ):=false;
		empty( ix+0,iy+1,iz+0 ):=false;
		empty( ix+0,iy+1,iz+1 ):=false;

	else

		-- trailing face:
		for i in 0..1 loop
			for j in 0..1 loop
				for k in 0..1 loop
					if wake(i,j,k) then
						empty(ix+i,iy+j,iz+k):=true;
					end if;
				end loop;
			end loop;
		end loop;

		-- make the move:
		centroid(kk)(1):=centroid(kk)(1)-1;
		ix:=centroid(kk)(1);

		-- leading face:
		for i in 0..1 loop
			for j in 0..1 loop
				for k in 0..1 loop
					if probe(i,j,k) then
						empty(ix+i,iy+j,iz+k):=false;
					end if;
				end loop;
			end loop;
		end loop;

	end if;


	test4winner;

	if not mute then 
	snd4ada.playSnd(whoosh); 
	end if;

	grinding(kk):=true;
	movebegin:=nowTime;

end if; --tryleft


end moveleft;




procedure moveright( kk: in out integer; nowTime: float ) is -- +X
	ix,iy,iz : integer;
	sx,sy,sz : integer;
	leadingVoid : boolean;
begin

if not tryright(kk) then -- pick one that might make sense
	for i in 1..9 loop
		if tryright(i) then
			kk:=i;
			exit;
		end if;
	end loop;
end if;



if tryright(kk) then

	append(restoreBuf, integer'image(kk) & " r ");

	oxc:=centroid(kk)(1);
	oyc:=centroid(kk)(2);
	ozc:=centroid(kk)(3);
 
	sx:=space(kk)(1);
	sy:=space(kk)(2);
	sz:=space(kk)(3);

	ix:=oxc;
	iy:=oyc;
	iz:=ozc;

	leadingVoid := (sx=1);


	for i in 0..1 loop
	for j in 0..1 loop
	for k in 0..1 loop
	if leadingVoid then -- (sx=1)

		if   i/=sx and j/=sy and k/=sz then 
			probe(i,j,k):=false;
			wake(i,j,k):=true;
		elsif i=sx and j/=sy and k/=sz then 
			probe(i,j,k):=true;
			wake(i,j,k):=false;
		elsif i/=sx and j=sy and k/=sz then 
			probe(i,j,k):=true;
			wake(i,j,k):=true;
		elsif i/=sx and j/=sy and k=sz then 
			probe(i,j,k):=true;
			wake(i,j,k):=true;
		else 
			probe(i,j,k):=false;
			wake(i,j,k):=false;
		end if;

	else -- trailing void (sx=0)

		if   i/=sx and j/=sy and k/=sz then 
			probe(i,j,k):=true;
			wake(i,j,k):=false;
		elsif i=sx and j/=sy and k/=sz then 
			probe(i,j,k):=false;
			wake(i,j,k):=true;
		elsif i/=sx and j=sy and k/=sz then 
			probe(i,j,k):=true;
			wake(i,j,k):=true;
		elsif i/=sx and j/=sy and k=sz then 
			probe(i,j,k):=true;
			wake(i,j,k):=true;
		else 
			probe(i,j,k):=false;
			wake(i,j,k):=false;
		end if;

	end if;
	end loop;
	end loop;
	end loop;




	if kk=9 then -- (easy)

		empty( ix+0,iy+0,iz+0 ):=true;
		empty( ix+0,iy+0,iz+1 ):=true;
		empty( ix+0,iy+1,iz+0 ):=true;
		empty( ix+0,iy+1,iz+1 ):=true;

		-- make the move:
		centroid(kk)(1):=centroid(kk)(1)+1;
		ix:=centroid(kk)(1);

		empty( ix+1,iy+0,iz+0 ):=false;
		empty( ix+1,iy+0,iz+1 ):=false;
		empty( ix+1,iy+1,iz+0 ):=false;
		empty( ix+1,iy+1,iz+1 ):=false;

	else

		-- trailing face:
		for i in 0..1 loop
			for j in 0..1 loop
				for k in 0..1 loop
					if wake(i,j,k) then
						empty(ix+i,iy+j,iz+k):=true;
					end if;
				end loop;
			end loop;
		end loop;

		-- make the move:
		centroid(kk)(1):=centroid(kk)(1)+1;
		ix:=centroid(kk)(1);

		-- leading face:
		for i in 0..1 loop
			for j in 0..1 loop
				for k in 0..1 loop
					if probe(i,j,k) then
						empty(ix+i,iy+j,iz+k):=false;
					end if;
				end loop;
			end loop;
		end loop;

	end if;



	test4winner;

	if not mute then 
	snd4ada.playSnd(whoosh); 
	end if;

	grinding(kk):=true;
	movebegin:=nowTime;

end if; --tryright


end moveright;






procedure movedown( kk: in out integer; nowTime: float ) is -- -Y
	ix,iy,iz : integer;
	sx,sy,sz : integer;
	leadingVoid : boolean;
begin

if not trydown(kk) then -- pick one that might make sense
	for i in 1..9 loop
		if trydown(i) then
			kk:=i;
			exit;
		end if;
	end loop;
end if;



if trydown(kk) then

	append(restoreBuf, integer'image(kk) & " d ");

	oxc:=centroid(kk)(1);
	oyc:=centroid(kk)(2);
	ozc:=centroid(kk)(3);
 
	sx:=space(kk)(1);
	sy:=space(kk)(2);
	sz:=space(kk)(3);

	ix:=oxc;
	iy:=oyc;
	iz:=ozc;

	leadingVoid := (sy=0);


	for i in 0..1 loop
	for j in 0..1 loop
	for k in 0..1 loop
	if leadingVoid then -- (sy=0)

		if   i/=sx and j/=sy and k/=sz then 
			probe(i,j,k):=false;
			wake(i,j,k):=true;
		elsif i=sx and j/=sy and k/=sz then 
			probe(i,j,k):=true;
			wake(i,j,k):=true;
		elsif i/=sx and j=sy and k/=sz then 
			probe(i,j,k):=true;
			wake(i,j,k):=false;
		elsif i/=sx and j/=sy and k=sz then 
			probe(i,j,k):=true;
			wake(i,j,k):=true;
		else 
			probe(i,j,k):=false;
			wake(i,j,k):=false;
		end if;

	else -- trailing void (sy=1)

		if   i/=sx and j/=sy and k/=sz then 
			probe(i,j,k):=true;
			wake(i,j,k):=false;
		elsif i=sx and j/=sy and k/=sz then 
			probe(i,j,k):=true;
			wake(i,j,k):=true;
		elsif i/=sx and j=sy and k/=sz then 
			probe(i,j,k):=false;
			wake(i,j,k):=true;
		elsif i/=sx and j/=sy and k=sz then 
			probe(i,j,k):=true;
			wake(i,j,k):=true;
		else 
			probe(i,j,k):=false;
			wake(i,j,k):=false;
		end if;

	end if;
	end loop;
	end loop;
	end loop;




	if kk=9 then -- (easy)

		empty( ix+0,iy+1,iz+0 ):=true;
		empty( ix+0,iy+1,iz+1 ):=true;
		empty( ix+1,iy+1,iz+0 ):=true;
		empty( ix+1,iy+1,iz+1 ):=true;

		-- make the move:
		centroid(kk)(2):=centroid(kk)(2)-1;
		iy:=centroid(kk)(2);

		empty( ix+0,iy+0,iz+0 ):=false;
		empty( ix+0,iy+0,iz+1 ):=false;
		empty( ix+1,iy+0,iz+0 ):=false;
		empty( ix+1,iy+0,iz+1 ):=false;

	else

		-- trailing face:
		for i in 0..1 loop
			for j in 0..1 loop
				for k in 0..1 loop
					if wake(i,j,k) then
						empty(ix+i,iy+j,iz+k):=true;
					end if;
				end loop;
			end loop;
		end loop;

		-- make the move:
		centroid(kk)(2):=centroid(kk)(2)-1;
		iy:=centroid(kk)(2);

		-- leading face:
		for i in 0..1 loop
			for j in 0..1 loop
				for k in 0..1 loop
					if probe(i,j,k) then
						empty(ix+i,iy+j,iz+k):=false;
					end if;
				end loop;
			end loop;
		end loop;

	end if;




	test4winner;

	if not mute then 
	snd4ada.playSnd(whoosh); 
	end if;

	grinding(kk):=true;
	movebegin:=nowTime;

end if; --trydown


end movedown;



procedure moveup( kk: in out integer; nowTime: float ) is -- +Y
	ix,iy,iz : integer;
	sx,sy,sz : integer;
	leadingVoid : boolean;
begin

if not tryup(kk) then -- pick one that might make sense
	for i in 1..9 loop
		if tryup(i) then
			kk:=i;
			exit;
		end if;
	end loop;
end if;



if tryup(kk) then

	append(restoreBuf, integer'image(kk) & " u ");

	oxc:=centroid(kk)(1);
	oyc:=centroid(kk)(2);
	ozc:=centroid(kk)(3);
 
	sx:=space(kk)(1);
	sy:=space(kk)(2);
	sz:=space(kk)(3);

	ix:=oxc;
	iy:=oyc;
	iz:=ozc;

	leadingVoid := (sy=1);



	for i in 0..1 loop
	for j in 0..1 loop
	for k in 0..1 loop
	if leadingVoid then -- (sy=1)

		if   i/=sx and j/=sy and k/=sz then 
			probe(i,j,k):=false;
			wake(i,j,k):=true;
		elsif i=sx and j/=sy and k/=sz then 
			probe(i,j,k):=true;
			wake(i,j,k):=true;
		elsif i/=sx and j=sy and k/=sz then 
			probe(i,j,k):=true;
			wake(i,j,k):=false;
		elsif i/=sx and j/=sy and k=sz then 
			probe(i,j,k):=true;
			wake(i,j,k):=true;
		else 
			probe(i,j,k):=false;
			wake(i,j,k):=false;
		end if;

	else -- trailing void (sy=0)

		if   i/=sx and j/=sy and k/=sz then 
			probe(i,j,k):=true;
			wake(i,j,k):=false;
		elsif i=sx and j/=sy and k/=sz then 
			probe(i,j,k):=true;
			wake(i,j,k):=true;
		elsif i/=sx and j=sy and k/=sz then 
			probe(i,j,k):=false;
			wake(i,j,k):=true;
		elsif i/=sx and j/=sy and k=sz then 
			probe(i,j,k):=true;
			wake(i,j,k):=true;
		else 
			probe(i,j,k):=false;
			wake(i,j,k):=false;
		end if;

	end if;
	end loop;
	end loop;
	end loop;




	if kk=9 then -- (easy)

		-- trailing face:
		empty( ix+0,iy+0,iz+0 ):=true;
		empty( ix+0,iy+0,iz+1 ):=true;
		empty( ix+1,iy+0,iz+0 ):=true;
		empty( ix+1,iy+0,iz+1 ):=true;

		-- make the move:
		centroid(kk)(2):=centroid(kk)(2)+1;
		iy:=centroid(kk)(2);

		-- leading face:
		empty( ix+0,iy+1,iz+0 ):=false;
		empty( ix+0,iy+1,iz+1 ):=false;
		empty( ix+1,iy+1,iz+0 ):=false;
		empty( ix+1,iy+1,iz+1 ):=false;

	else

		-- trailing face:
		for i in 0..1 loop
			for j in 0..1 loop
				for k in 0..1 loop
					if wake(i,j,k) then
						empty(ix+i,iy+j,iz+k):=true;
					end if;
				end loop;
			end loop;
		end loop;

		-- make the move:
		centroid(kk)(2):=centroid(kk)(2)+1;
		iy:=centroid(kk)(2);

		-- leading face:
		for i in 0..1 loop
			for j in 0..1 loop
				for k in 0..1 loop
					if probe(i,j,k) then
						empty(ix+i,iy+j,iz+k):=false;
					end if;
				end loop;
			end loop;
		end loop;

	end if;




	test4winner;

	if not mute then 
	snd4ada.playSnd(whoosh); 
	end if;

	grinding(kk):=true;
	movebegin:=nowTime;

end if; --tryup


end moveup;













	playedonce, userexit : boolean := false;
	wintime, currentTime : float;

	v4, vcc : vec4;
	--mzndc : float;


	keydlay : constant float := 0.25;

	otitle : constant interfaces.c.char_array 
		:= value( new_string("Ada7") );
	vtitle : constant interfaces.c.char_array 
		:= value( new_string("Vadasz") );



	ix,iy,iz, sx,sy,sz, cx,cy,cz : integer := 1;

	xize: float := 0.25;

	-- I shall first attempt to treat OS-X the same as GNU-Linux
	-- given that like-binaries will be together in same directory:
	--dirname: constant string := ada.directories.current_directory;
	--nexname: constant string := dirname & "/reliquarium";
	--Ok: boolean;


	ixsel: integer:=1;
	pik: boolean := false;


	hc: boolean := true; --HighContrast


	rfile: file_type;
	char: character;


	procedure shutdown is
	begin

		text_io.create(rfile,out_file,"t5restore.txt");
		put( rfile, restoreBuf );
		put( rfile, " -1 ");
		new_line(rfile);
		text_io.close(rfile);
		put_line(" Saved config to t5restore.txt");

		glext.binding.glDeleteProgram(pgmtexshadid);

		glext.binding.glDeleteBuffers(1, vertbuff'address);
		glext.binding.glDeleteBuffers(1, rgbbuff'address);
		glext.binding.glDeleteBuffers(1, elembuff'address);
		glext.binding.glDeleteBuffers(1, uvbuff'address);

		glext.binding.glDeleteVertexArrays(1, vertexarrayid'address);

		stex.CloseFont;

		snd4ada.termSnds;

		glfwdestroywindow(mainWin);
		glfwTerminate;

	end shutdown;



	procedure replay is
	begin

		for i in 1..nmoves loop
			ixsel:= sel(i);
			char := dir(i);

			currentTime := float(glfwGetTime);

			case char is
				when 'n' => movenear(ixsel,currentTime);
				when 'a' => moveaway(ixsel,currentTime);
				when 'u' => moveup(ixsel,currentTime);
				when 'd' => movedown(ixsel,currentTime);
				when 'l' => moveleft(ixsel,currentTime);
				when 'r' => moveright(ixsel,currentTime);
				when others => null;
			end case;
		end loop;

	end replay;




----------------- main program begin ==========================
begin --tomb

	checkfile; --see if restore file exists; sets preRestoreBuf


normalMode:=false; --displays goal cfg
	first_prep;  -- main program setup

	show_axes:=true;



	degRotate( mm, 20.0, 1.0, 0.0, 0.0 );



	-- note:  only mm changes:
	updateMVP( float(wwid), float(whit) );




	-- main event loop begin: ------------------------------------------
   while not userexit loop

------- begin response to keys ------------------------------------------

		currentTime := float(glfwGetTime);


		glfwPollEvents;



		--check for <esc>,<q>:
		if glfwgetkey( mainWin, glfw_key_escape ) = Glfw_Press then
				userexit:=true;

		elsif glfwgetkey( mainWin, glfw_key_q ) = Glfw_Press then
				userexit:=true;

		end if;

		exit when glfwWindowShouldClose(mainWin) /= 0; --19oct21


		if not normalMode then
			if glfwgetkey( mainWin, glfw_key_equal ) = Glfw_Press then
				normalMode:=true;
				centroid:=centroidHi;
				initEmptyHi;
				if playscript then
					replay;
				end if;

				set_unbounded_string(restoreBuf, to_string(prerestoreBuf) );

			end if;
		end if;




		anyGrinding:=false;
		for i in rngp loop
			anyGrinding := anyGrinding or grinding(i);
		end loop;

		if not anyGrinding then

			if normalMode then
				gameutils.getKeyInputs(
					mainWin,
					rngp'first, rngp'last,
					ixsel,pik);
			end if;

			if goUp then
				goUp:=false;
				moveUp(ixsel,currentTime);
			elsif goDown then
				goDown:=false;
				moveDown(ixsel,currentTime);
			elsif goLeft then
				goLeft:=false;
				moveLeft(ixsel,currentTime);
			elsif goRight then
				goRight:=false;
				moveRight(ixsel,currentTime);
			elsif goAway then
				goAway:=false;
				moveAway(ixsel,currentTime);
			elsif goNear then
				goNear:=false;
				moveNear(ixsel,currentTime);
			elsif doRestart then
				set_unbounded_string(restoreBuf, "");
				doRestart:=false;
				centroid:=centroidHi;
				initEmptyHi;
			elsif tryNextSkin then
				tryNextSkin:=false;
				setNextSkin;
			end if;


			gameutils.handle_mouse(
				pik, 
				rngp'first, rngp'last, 
				ixsel,
				centroid,
				xxcc,yycc,zzcc
				);

		end if;




----///////////////////// end response to key/mouse


		updateMVP( float(wwid), float(whit) );


-------- here we should handle resized window ----------------------


		glfwGetWindowSize( mainWin, Nwid'access, Nhit'access );
		if( (Nwid /= wwid) or (Nhit /= whit) ) then
			wwid:=Nwid;  whit:=Nhit;

			glfwGetFramebufferSize(mainwin, fwid'access, fhit'access);
			glViewport(0,0,Fwid,Fhit);

		end if;



--------- begin drawing ===============================================

		glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);


	if not help then --normal draw 23jun23



------ draw here ----------------------

		-- now, the 8 puzzle pieces:
		glUseProgram( pgmTexShadID );
		gluniformmatrix4fv( matrixid, 1, gl_false, mvp(1,1)'address );
		gluniform1i(uniftex,0);

		for ii in rngp loop -- 8 corners + 1 egg


			if numerals then
				glBindTexture(gl_texture_2d, num_texid(ii) );
			else
				glBindTexture(gl_texture_2d, nun_texid );
			end if;



			ix:=centroid(ii)(1);
			iy:=centroid(ii)(2);
			iz:=centroid(ii)(3);


			if ii = rngp'last then --egg

				--draw9(ppo, currentTime);
				null;

			else -- one of 8 corner pieces

				sx:=space(ii)(1);
				sy:=space(ii)(2);
				sz:=space(ii)(3);

				cx:=1-sx;
				cy:=1-sy;
				cz:=1-sz; --corner cubelet indexes

				for i in 0..1 loop
				for j in 0..1 loop
				for k in 0..1 loop
					-- this is a 4-cubelet-corner:
					if i/=sx and j/=sy and k/=sz then --corner cubelet
						drawCube(ppo, ii, cx,cy,cz, i,j,k, ix, iy, iz, currentTime );
					elsif i=sx and j/=sy and k/=sz then
						drawCube(ppo, ii, cx,cy,cz, i,j,k, ix, iy, iz, currentTime );
					elsif i/=sx and j=sy and k/=sz then
						drawCube(ppo, ii, cx,cy,cz, i,j,k, ix, iy, iz, currentTime );
					elsif i/=sx and j/=sy and k=sz then
						drawCube(ppo, ii, cx,cy,cz, i,j,k, ix, iy, iz, currentTime );
					else -- empty space
						null;
					end if;
				end loop;
				end loop;
				end loop;

			end if;


		end loop; --ii


		glUseProgram( pgmTexID );
		gluniformmatrix4fv( matid, 1, gl_false, mvp(1,1)'address );
		gluniform1i(unitex,0);
		if not winner then
			glBindTexture(gl_texture_2d, box_texid ); 
			drawBigCube(ppo2); --bounding chainlink box
		end if;

		glBindTexture(gl_texture_2d, num_texid(rngp'last) );
		draw9(ppo, currentTime); --skull






		if show_axes then

			v4 := (+2.0, -2.5, -2.0, 1.0);
			matXvec(mvp, v4, vcc);
			stex.print3d("+X", vcc(1), vcc(2), vcc(3), vcc(4), 1.0, 1.0);

			v4 := (-2.2, +2.5, -2.2, 1.0);
			matXvec(mvp, v4, vcc);
			stex.print3d("+Y", vcc(1), vcc(2), vcc(3), vcc(4), 1.0, 1.0);

			v4 := (-2.0, -2.5, +2.0, 1.0);
			matXvec(mvp, v4, vcc);
			stex.print3d("+Z", vcc(1), vcc(2), vcc(3), vcc(4), 1.0, 1.0);

			v4 := (-2.0, -2.5, -2.0, 1.0);
			matXvec(mvp, v4, vcc);
			stex.print3d("O", vcc(1), vcc(2), vcc(3), vcc(4), 1.0, 1.0);

		end if;



		xize:=0.25;

		-- fixed 2d location text:

		stex.print2d("(spc)=>Restart", 0.02, 0.05, xize );
		stex.print2d("(i,o,mousewheel)=>Zoom", 0.36, 0.05, xize);
		stex.print2d("(esc)=>exit",    0.78, 0.05, xize );
		stex.print2d("1-8=>pick",      0.02, 0.02, xize );
		stex.print2d("s=>skull",        0.20, 0.02, xize );
		stex.print2d("n=>nums",        0.40, 0.02, xize ); --8oct21
		stex.print2d("c=>nextColor",        0.58, 0.02, xize );
		stex.print2d("h=>help",        0.85, 0.02, xize );


	end if; --not help (normal draw) 23jun23



		if help then
			xize:=0.4; hc:=false;
			stex.print2d("Reckless raiders have plundered a reliquary",0.02,0.90,xize,hc);
			stex.print2d("...and displaced an ancient Crystal Skull !",0.02,0.85,xize,hc);

			stex.print2d("Return the Skull to its proper position", 0.02, 0.80, xize,hc);
			stex.print2d("Centered within its Cubical Frame.", 0.02, 0.75, xize,hc);

			stex.print2d("With X rightward, Y upward, and Z outward,", 0.02, 0.70, xize,hc);
			stex.print2d("use the keys:  u/d  l/r  f/b", 0.02, 0.65, xize,hc);
			stex.print2d("(Up/Down Left/Right Forward/Backward)", 0.02, 0.60, xize,hc);

			stex.print2d("Select a block by number or mouse-click...", 0.02, 0.50, xize,hc);
			stex.print2d("Laptop users can place cursor on block", 0.02, 0.45, xize,hc);
			stex.print2d("then hit <enter>-key to select", 0.02, 0.40, xize,hc);

			stex.print2d("Zoom keys:   i/o = In/Out", 0.02, 0.35, xize,hc);

			stex.print2d("V-key to mute moves", 0.02, 0.30, xize,hc);

			xize:=0.25;
		else
			if normalMode then
			stex.print2d("Medium:   Move the skull into the center of its cubical tomb.",0.10,0.95,xize);
			else
			stex.print2d("This is the goal configuration...Press  =  to begin",0.10,0.95,xize);
			end if;

		end if;

		if winner and (currentTime-testime>windelay) then
			stex.print2d("Correct!", 0.19, 0.83, 1.0 );

			if not playedonce then
		 		snd4ada.playSnd(clap); --clapping
				playedonce:=true;
				wintime:=currentTime;
			end if;

			if( currentTime-wintime > 5.0 ) then 
				winner:=false;
			end if;

		else
			playedonce:=false;
		end if;


--------- end drawing =================================================



		glflush;
		glfwSwapBuffers( mainWin );


   end loop; ----------------- main event loop end -------------------


	shutdown;



exception
	when others=>
		shutdown;

end tomb5;



