
--
-- Copyright (C) 2022  <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 utiltypes;
with splaytree;
with splaypq;
with text_io;

with interfaces.c;
with Ada.Strings.Unbounded;
with Ada.Strings.Unbounded.Text_IO;

with ada.command_line;
with ada.calendar;


package utils is


use Ada.Strings.Unbounded;
use Ada.Strings.Unbounded.Text_IO;


	package myint_io is new text_io.integer_io(integer);

	package myfloat_io is new text_io.float_io(float);

	procedure myassert( 
		condition : boolean;  
		flag: integer:=0;
		msg: string := "");


	type dirtype is (no,so,ea,we,any);



	tsec0, tsec1 : ada.calendar.day_duration;



	skip3: boolean := false;


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

	--type ubyte is range 0..255; --(1-byte)
	--type ushort is range 0..2**32-1; -- (4-bytes)
	-- note that 8-byte integers may not be defined in above fashion.

	-- Be careful with these modular types because subtraction
	-- and division do not function normally.  The usage here 
	-- only requires addition & multiplication.  Only
	-- ulong MUST be defined this way.  The others are
	-- defined similarly due only to aesthetics.
	type ubyte is mod 2**8;   --(1-byte)  0..255
	type ushort is mod 2**16; --(2-bytes) 0..65535
	type ulong is mod 2**64;  --(8-bytes)

	usmx : constant ushort := 65535;
	ubmx : constant ubyte := 255;

	maxrows : constant ushort := 22; --20; 23jan21 bump
	maxcols : constant ushort := 25;
	maxsize : constant ushort := maxrows*maxcols;


	type puzarray is array(1..maxrows,1..maxcols) of character;
	--type puzarray is array(ushort range<>, ushort range<>) of character;
	-- for passing into modified readPuz.



	nbvalid: ushort;

	subtype interange is ushort range 1..maxsize;

	type booltype is array(interange) of boolean;

	--type vfstype is array(ubyte) of ubyte;
	type vfstype is array(ubyte) of boolean;
	--pragma pack(vfstype);

	type vftype is array(interange) of ubyte;
	type vustype is array(interange) of ushort;

	type keytype is 
	record
		suma, sumb, sumc : ulong; --box_layout
		pulkey     : ubyte;       --puller corral ULcorner
	end record;
	--pragma pack(keytype);

	type hashrectype is
	record
		--boxpull, ngoals,
		brsave, bcsave,
		prsave, pcsave, prevmove : ubyte := 0;
		totpulz,totmovz : ushort := 0;
		vfsave : vfstype := (others=>false);
		prevkey : keytype;
	end record; -- 297 bytes (default)
	for hashrectype'size use 2400; --300*8 (Faster than default)
	--pragma pack(hashrectype); --even slower using this



	function "<" (k1, k2: in keytype ) return boolean;
	function ">" (k1, k2: in keytype ) return boolean;




	package mysplaytype is new splaytree( keytype, hashrectype, "<", ">" );

	explored : mysplaytype.treetype;
	status : mysplaytype.statustype; -- Ok, found, ...


	--this version allows duplicate priorities;
	--We always allow adding keys:
	package mypqtype is new splaypq(keytype, hashrectype, "<",">");

	frontier : mypqtype.listtype;
	pqstatus : mypqtype.statustype; -- Ok, found, ...


	package mypqtype1 is new splaypq(keytype, hashrectype, "<",">");
	frontier1 : mypqtype1.listtype;

	package mypqtype2 is new splaypq(keytype, hashrectype, "<",">");
	frontier2 : mypqtype2.listtype;

	package mypqtype3 is new splaypq(keytype, hashrectype, "<",">");
	frontier3 : mypqtype3.listtype;

	package mypqtype4 is new splaypq(keytype, hashrectype, "<",">");
	frontier4 : mypqtype4.listtype;



	--pragma default_storage_pool(splaytypes.splaypool); ineffective


------- end parallel priority queue --------------------





	bestnk: ushort := 0;


	-- now use this to overwrite previous winners with shorter ones:
	minBoxPulls: ushort := usmx;

	careful,
	relent,urgent,desperate,dying, pwin, winner : boolean := false;

	pvalid,bvalid: booltype:=(others=>false); 
	--30oct18 to hold validCell flag

	ff, vf, off,ovf : vftype; --ovf=Original box pos = pusher-goal

	-- structs for Dynamic Programming relaxation [flood-fill]
	fff, bestpred, bestcost0, bestcost, nappch : vftype;

	pviano, pviaso, pviaea, pviawe,
	hviano, hviaso, hviaea, hviawe : booltype;
	pfff,hfff, hbestpred, hnappch : vftype;

	pbestcost,hbestcost: vustype;

	htunl,vtunl, xtunn, bnexus,enexus, nexus : booltype := (others=>false);
	corral,
		viano, viaso, viaea, viawe,
		cviano, cviaso, cviaea, cviawe : booltype;

	usinf  : constant ushort := usmx-1; --9999;
	ubinf  : constant ubyte := ubmx-1; 
	--254 (ubinf+1 must be a valid ubyte)

	fromno: constant ubyte := 0;
	fromso: constant ubyte := 1;
	fromea: constant ubyte := 2;
	fromwe: constant ubyte := 3;
	none  : constant ubyte := ubinf; --254


	depth: integer := 0;
	increment, level, maxlevel : integer;

	outfilname,infilname : unbounded_string;


	win_suma, win_sumb, win_sumc : ulong := 0;
	pwin_pulkey, win_pulkey : ubyte := 0;
	pwin_key, win_key : keytype;

	ncols, nrows : ushort;

	savefp, gngoals, pfmax : ushort := 0;

	grow,gcol,
	prfinal, pcfinal : array(interange) of ushort;

-------------------------------------------------------------
--used in splaypq
	maxbx : constant ushort := ushort(utiltypes.imaxboxes);
---------------------------------------------------------------

	nboxes : ushort:=0; --actual # (<=25)

	type etype is array(1..maxbx) of ubyte;

	-- interange=1..500
	--type vustype is array(interange) of ushort;

	ee : vustype := (others=>usmx);
	-- ee in 0..255 for feasible box positions...
	-- ee=usmx elsewhere.  This array is defined
	-- in readpuzzle to define a maximum of 255
	-- VALID INTERIOR positions.


	subtype boxrng is ushort range 1..maxbx;

	subtype rowrng is ushort range 1..maxrows;
	subtype colrng is ushort range 1..maxcols;

	boxrow, goalrow : array(boxrng) of rowrng;
	boxcol, goalcol : array(boxrng) of colrng;

	dist2goal: array(boxrng) of ushort;

	type permutetype is array(boxrng) of boxrng;
	permute: permutetype;


	gpr, gpc : ushort := usmx;


function manhattan(r1,c1,r2,c2: integer) return integer;



procedure bitrep(
	nb : ushort; -- 1..24
	e  : etype; -- 1..255
	suma, sumb, sumc : in out ulong );

function indx(r,c : ushort) return ushort;


ppath : array(1..ubmx) of character;

-- test to see whether puller has a clear path
-- to (r1,c1) assuming current box layout:
function dppathexists(r1,c1: ushort; bestcost:vftype ) return boolean;
function dppathexists(r1,c1: ushort; bestcost:vftype ) return ushort;

procedure dppath( 
	r1,c1 : ushort;  
	np: out ubyte;
	bestcost, bestpred: vftype
	);

procedure initwdpcorral;
procedure dpcorral(
	r0,c0 : ushort; --puller.pos
	ulkey : out ubyte -- 3rd component of keytype
	);
procedure dpwcorral(
	r0,c0 : ushort; --puller.pos
	ulkey : out ubyte -- 3rd component of keytype
	);
procedure dppathprep(
	r0,c0 : ushort; --puller.pos
	bestcost, bestpred: out vftype
	);

function setwinkey( wpkey: ubyte ) return keytype;


function testleft(br,bc:ushort) return boolean;
function testright(br,bc:ushort) return boolean;
function testdown(br,bc:ushort) return boolean;
function testup(br,bc:ushort) return boolean;








function ignore_this_line( line : string; len:natural ) return boolean;

procedure readPuzzle( lvl1: integer );

procedure checkForUserFile( 
	ok: out boolean; 
	uMaxGb: in out float;
	pushOpt: in out boolean;
	omitHungarian: in out boolean
	);

procedure checkForUserFile( 
	ok: out boolean
	);




procedure restore2(
	vf: in out vftype; rec : hashrectype;  pr,pc : out ushort );

function trimmed_int( i: integer ) return unbounded_string;

procedure swinnertest( 
	solutionPath: in out unbounded_string;
	key: keytype; 
	rec: hashrectype);





function min(a,b: ushort) return ushort;


procedure saveifnew4e(
	rec:  hashrectype; 	
	key:  keytype;
	pmove: ushort;
	tboxpulls, tmoves : ushort;
	pr,pc, 			   --new puller pos
	br,bc            --prev puller pos = new box pos
		: ushort );


procedure hsaveifnew4e(
	rec:  hashrectype; 	
	key:  keytype;
	pmove: ushort;
	tboxpulls, tmoves : ushort;
	pr,pc, 			   --new puller pos
	br,bc            --prev puller pos = new box pos
		: ushort );


procedure hsaveifnew4(
	rec:  hashrectype; 	
	key:  keytype;
	pmove: ushort;
	tboxpulls, tmoves : ushort;
	pr,pc, 			   --new puller pos
	br,bc            --prev puller pos = new box pos
		: ushort );


procedure hsave0(
vf,ff:vftype; 
nrows,ncols: ushort;
ee:vustype; pvalid:booltype;
omitHung: boolean
);




procedure dpbox;
procedure dppuller;


procedure remdead;

procedure findnexii;




	function citrim( i: interfaces.c.int ) return string;
	function itrim( i: integer ) return string;
	function utrim( i: ushort ) return string;
	function ubtrim( i: ubyte ) return string;


function fcountBlockedBoxes return integer;
function fcountRoomBlocks return integer;
function fcountCorrals(vf:vftype) return integer;

procedure rdump0(vf: vftype; pr,pc: ushort);


procedure dump2arr(
	nrows, ncols: ushort;
	ipr,ipc: ubyte;
	puzz: out puzarray;
	switch : boolean := true );

procedure readArr(
	puzz: puzarray);






end utils; --package

