
with splaypq0;
with splaytree;


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

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


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 ada.characters.latin_1;

with unchecked_deallocation;

with text_io;
with ada.integer_text_io;
with io_exceptions;

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;

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



package utils4 is

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



	bfsWorking: boolean := false; 
	--extra safeguard to preclude junk in restoreBuf

	prerestoreBuf, restoreBuf, saveBuf: unbounded_string;

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


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

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


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

	subtype rngm is integer range 1..ncubes;


	--lempty, --version local to solver modules
	type emptytype is array(1..mx,1..my,1..mz) of boolean;
	empty : emptytype;
	--carefully track location of empty spaces



	-- 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 -------------------


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



-- define 11 puzzle pieces here, and initialize:
mp : constant integer := 10;
subtype rngp is integer range 0..mp;
subtype fparray is gfparray(rngp);
subtype iparray is giparray(rngp); --array of int-coords: (ix,iy,iz)








--------------- begin types for hashtable --------------------------

subtype keytype is iparray;
key0: constant keytype := (others=>(others=>0));


function key2str( key: keytype ) return string;

--------------- end types for hashtable --------------------------


	trailmax: constant integer := 300; --max #moves to solve
	ntrail : integer := 0; --path length of current config
	trailchr : array(1..trailmax) of character := (others=>'X');
	trailsel : array(1..trailmax) of integer := (others=>99);
	trailenc : array(1..trailmax) of keytype := (others=>key0);




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







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:
( 
-- pieces below are: 4-cubelet = 1/2 of a 2x2x2; location=center of 2x2x2
		0=>(1,1,1), --ULP
		1=>(3,1,1), --URP (posterior)
		2=>(3,1,3), --ULA
		3=>(1,1,3), --URA (upper right anterior)

		4=>(1,1,3), --LLP
		5=>(3,1,3), --LRP
-- above pieces are all: 4-cubelet corners = 1/2 of a 2x2x2

		6=>(3,1,1), -- 3 cubelets in an L shape 
		7=>(4,1,2), -- 1x1 block (6+7 = 1/2 cube = LLA)

		8=>(1,1,2), -- 1x1 block (8+9 = 1/2 cube = LRA)
		9=>(2,1,1), -- 3 cubelets in an L shape

		10=>(2,3,2)  --skull to be entombed in center = 2x2x2 cube
); --------------------------------------------------------------

-- solved configuration:
centroidMid : constant iparray :=
-- piece-centroids initialization:
( 
		0=>(1,3,1), --ulp (UpperLeftPosterior)
		1=>(3,3,1), --urp
		2=>(1,3,3), --ula
		3=>(3,3,3), --ura (UpperRightAnterior)

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

		6=>(1,1,3), --lla
		7=>(2,1,4), -- 1x1 block

		8=>(3,1,4), -- 1x1 block
		9=>(4,1,3), --lra

		10=>(2,2,2)  --[skull=s] to be entombed in center
);




-- Note that for each normal piece, its full envelope is:
-- (p.x,p.y,p.z)...(p.x+1,p.y+1,p.z+1)
-- x/y/z in 1..3
-- [centroid := inside vertex of the corner cubelet]
-- 	or you might say
-- [centroid := pos of "missing" cubelet]
--
--
-- For 6,9 (L-shaped): x in 1..4, y/z in 1..3
-- [centroid := inside vertex of corner cubelet]
-- 	or you might say
-- [centroid := pos of "missing" cubelet]
-- 	or you might say
-- [centroid := pos of bottom-rear-cubelet]
--
-- For 7,8 (1x1): x,y,z is in 1..4


centroid : iparray; --used as a global (sloppy)



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

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

----------- unused below here --------------

		6=>(1,1,0), --lla

		7=>(0,0,0),
		8=>(0,0,0),

		9=>(0,1,0), --lra

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






normalMode : boolean := true;
windelay : constant float := 1.0;
testime : float := 0.0;


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

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

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 empty locations to be occupied by next move
-- Both used to update the "empty" array...
-- but ONLY for typical 4-cubelet pieces!

procedure test4winner( icentro: in iparray );

function movenear( ikk: in integer; centro: in out iparray; empt:in out emptytype; track:boolean:=false ) return boolean;
function moveaway( ikk: in integer; centro: in out iparray; empt:in out emptytype; track:boolean:=false ) return boolean;
function moveup  ( ikk: in integer; centro: in out iparray; empt:in out emptytype; track:boolean:=false ) return boolean;
function movedown( ikk: in integer; centro: in out iparray; empt:in out emptytype; track:boolean:=false ) return boolean;
function moveright( ikk: in integer; centro: in out iparray; empt:in out emptytype; track:boolean:=false ) return boolean;
function moveleft( ikk: in integer; centro: in out iparray; empt:in out emptytype; track:boolean:=false ) return boolean;


end utils4;


