
--
-- Copyright (C) 2019  <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/>.
--




-- crush.adb : ColorTerminalRush = traffic-rush in a terminal window
--
-- Build instructions (may need further 'adjustments' on Windows):
-- 1) Manually install GNAT GPL and GNATCOLL from libre.adacore.com/download/
-- 2) Build gnatcoll, but do not install.
-- 3) under ./src/lib/gnatcoll/relocatable/ you will find libgnatcoll.so*
-- 4) copy them into ./libs/<sys> where <sys> = gnu or osx or win, 
--    according to your system.  When copying, you must use the "-a" flag 
--    for cp to preserve softlinks.
-- 5) insure the script ccmp.sh correctly sets the path to gnatmake;
-- 6) compile crush by typing "ccmp.sh <sys>" where <sys> = gnu or osx or win
--    depending on your system.
--
-- using aa=exitCar, bbb=truck
-- <up>='A', <rt>='C', etc


with tput00_h;


with gnat.os_lib;
with ada.characters.handling;

with Interfaces.C;
use type interfaces.c.int;



with Text_IO;
with SysUtils;  use SysUtils;
with ada.directories;
with Ada.Strings.Unbounded;
with Ada.Strings.Unbounded.Text_IO;
with fbfsr;

with GNATCOLL.Terminal;  use GNATCOLL.Terminal;
with realtime_hpp;




procedure crush is

use Ada.Strings.Unbounded;
use Ada.Strings.Unbounded.Text_IO;
use ada.directories;
use text_io;

	mswin: constant boolean := (gnat.os_lib.directory_separator='\');

	search : search_type;
	directory_entry : directory_entry_type;
	totgame, nlevels : integer := 0;



	ch: character;

	erase, changed,
	userexit, help, vertical, Ok, winner, speedup : boolean := false;

	solutionPath: unbounded_string;

	movesrem, nMoves, mxpuz, npuz : integer := 0;
	maxNpuz: constant integer := 99;

	gamefiles, shortname : array(1..maxNpuz) of unbounded_string;
	infilname : unbounded_string;
	savename : unbounded_string := to_unbounded_string("puzzles/resume.txt");

	objectiveText : string(1..40);
	movesText: string(1..9);

-----------------------------------------------------------------
-- maximum # cars/trucks:
	maxcar: constant integer := 16; -- allow a..p

-- maximum # cars/trucks/blanks
	maxblk: constant integer := 36;

-- car centers:
	rowcen, colcen : array(1..maxblk) of float;
	idchar : array(1..maxblk) of character := (others=>' ');
	bshape : array(1..maxblk) of integer; -- 12,21, 13,31

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

	grow, gcol : float; -- goal pos

	dblk, nblk, gblk, selBlock, nrow,ncol: integer:=1;

	blank : array(1..maxblk) of integer;
	br,bc,obr,obc: array(1..maxblk) of float;








	package myint_io is new text_io.integer_io(integer);
	package myfloat_io is new text_io.float_io(float);


procedure test4winner is
	epsilon : constant float := 0.1;
begin
	winner := 
		(abs(rowcen(1)-grow) < epsilon )
		and
		(abs(colcen(1)-gcol) < epsilon );
end test4winner;





procedure myassert( condition : boolean;  flag: integer:=0 ) is
begin
  if condition=false then
  		put("ASSERTION Failed!  ");
		if flag /= 0 then
			put_line( "@ " & integer'image(flag) );
		end if;
		new_line;
  		raise program_error;
  end if;
end myassert;




procedure dumpSol(moves: integer; sol: unbounded_string) is
	idch, ckch, mvch: character;
	fileid : text_io.file_type;
begin

   text_io.Create
      (File => FileId,
       Mode => text_io.Out_File,
       Name => "sol.txt");

	for i in 1..moves loop
		idch := element(sol,3*(i-1)+1);
		ckch := element(sol,3*(i-1)+2);
		mvch := element(sol,3*(i-1)+3);
		myassert(ckch='-', 9898);
		put_line(fileid, idch&ckch&mvch);
	end loop;

   text_io.Close (File => FileId);

end dumpSol;


procedure dumpGameState(fnam: string) is
	fileid : text_io.file_type;
begin

   text_io.Create
      (File => FileId,
       Mode => text_io.Out_File,
       Name => fnam);

	put_line(fileid, "move Red car to edge");
	myint_io.put(fileid, nrow);
	new_line(fileid);
	myint_io.put(fileid, ncol);
	new_line(fileid);
	myint_io.put(fileid, dblk);
	new_line(fileid);
	myint_io.put(fileid, gblk);
	new_line(fileid);
		myfloat_io.put(fileid, grow);
		myfloat_io.put(fileid, gcol);
	new_line(fileid);

	for i in 1..dblk loop
		myint_io.put(fileid, bshape(i));
		put(fileid," ");
		myfloat_io.put(fileid, rowcen(i));
		put(fileid," ");
		myfloat_io.put(fileid, colcen(i));
		put(fileid," ");
		put_line(fileid, "black");
	end loop;

	myint_io.put(fileid, nblk);
	new_line(fileid);

	for i in dblk+1..dblk+nblk loop
		myint_io.put(fileid, bshape(i));
		put(fileid," ");
		myfloat_io.put(fileid, br(i-dblk));
		put(fileid," ");
		myfloat_io.put(fileid, bc(i-dblk));
		put(fileid," ");
		put_line(fileid, "white");
	end loop;

   text_io.Close (File => FileId);

end dumpGameState;


procedure init( fname: string ) is
	fileid : text_io.file_type;
	len: natural;
	clrstr: string(1..40);
	--ich: character;
begin

   text_io.Open
      (File => FileId,
       Mode => text_io.In_File,
       Name => fname);


	text_io.get_line(fileid, objectiveText, len);
	movesText := objectiveText(len-8..len);


	-- (nrow,ncol) = outer dimension
	-- dblk = # non-blank rectangles
	-- nblk = # blanks
	-- gblk = # goal positions that must be attained
	-- (grow,gcol) = goal position[s]
	-- bshape = 11 or 12 or 21 or 13 or 31 = block shape

	myint_io.get(fileid, nrow);
	myint_io.get(fileid, ncol);
	myint_io.get(fileid, dblk);
	myint_io.get(fileid, gblk); -- gblk=1 in traffic-rush

	myassert( gblk = 1 );
	myassert( dblk <= maxcar ); -- allow labels a..p for vehicles

	myfloat_io.get(fileid, grow);
	myfloat_io.get(fileid, gcol);


	for i in 1..dblk loop
		myint_io.get(fileid, bshape(i));
		myfloat_io.get(fileid, rowcen(i));
		myfloat_io.get(fileid, colcen(i));
		text_io.get_line(fileid, clrstr, len); --ignore
		idchar(i):=character'val( 96+i ); --a=97...z=122
	end loop;



	myassert( (bshape(1)=21) or (bshape(1)=12) );
	vertical:=false; -- redcar exits at right
	if( bshape(1)=21 ) then
		vertical:=true; -- redcar exits at top
	end if;

	myint_io.get(fileid, nblk);
	for i in dblk+1..dblk+nblk loop

		myint_io.get(fileid, bshape(i));
		myfloat_io.get(fileid, rowcen(i));
		myfloat_io.get(fileid, colcen(i));
		text_io.get_line(fileid, clrstr, len); --ignore

		blank(i-dblk) := i;
		br(i-dblk) := rowcen(i);
		bc(i-dblk) := colcen(i);

	end loop;

--CAUTION:  br & bc for 1..nblk are updated to match current state
--				but rowcen,colcen for dblk+1...dblk+nblk are NOT !!!

   text_io.Close (File => FileId);

	winner:=false;
	nMoves:=0;

end init;







-- 11jul16 fix
function same( a, b : float ) return boolean is
	epsilon : constant float := 0.1;
begin
	if abs(b-a) < epsilon then
		return true;
	else
		return false;
	end if;
end same;



function moveleft return integer is
	sr,sc: float;
	shape, ret: integer := 0;
begin


	for i in 1..nblk loop
		obr(i) := br(i);
		obc(i) := bc(i);
	end loop;

	myassert( selBlock>=1, -1 );
	myassert( selBlock<=dblk, -2 );

	sr   :=rowcen(selBlock);
	sc   :=colcen(selBlock);
	shape:=bshape(selBlock);


	if( shape=13 ) then

		for i in 1..nblk loop
			if same(br(i),sr) and same(bc(i),sc-2.0)  --swap b,sel
			then
				colcen(selBlock) := sc-1.0;
				bc(i) := bc(i)+3.0;
			end if;
		end loop;

	elsif( shape=12 ) then

		for i in 1..nblk loop
			if same(br(i),sr) and same(bc(i),sc-1.5) --swap b,sel
			then
				colcen(selBlock) := sc-1.0;
				bc(i) := bc(i)+2.0;
			end if;
		end loop;

	elsif( shape=11 ) then

		for i in 1..nblk loop
			if same(br(i),sr) and same(bc(i),sc-1.0) --swap b,sel
			then
				colcen(selBlock) := sc-1.0;
				bc(i) := bc(i)+1.0;
			end if;
		end loop;

	end if;



	for i in 1..nblk loop
		if not same(obr(i), br(i)) or not same(obc(i), bc(i))  then
			ret:=1;
		end if;
	end loop;

	if( ret > 0 )	
	then
		changed:=true;
		if winner then erase:=true; end if;
		nMoves:=nMoves+1;
		test4winner;
	end if;

	return ret;

end moveleft;










function moveright return integer is
	sr,sc: float;
	shape,ret: integer:=0;
begin


	for i in 1..nblk loop
		obr(i) := br(i);
		obc(i) := bc(i);
	end loop;

	myassert( selBlock>=1, -3 );
	myassert( selBlock<=dblk, -4 );

	sr   :=rowcen(selBlock);
	sc   :=colcen(selBlock);
	shape:=bshape(selBlock);


	if( shape=13 ) then
		for i in 1..nblk loop
			if same(br(i),sr) and same(bc(i),sc+2.0)  --swap b,sel
			then
				colcen(selBlock) := sc+1.0;
				bc(i) := bc(i)-3.0;
			end if;
		end loop;

	elsif( shape=12 ) then
		for i in 1..nblk loop
			if same(br(i),sr) and same(bc(i),sc+1.5)  --swap b,sel
			then
				colcen(selBlock) := sc+1.0;
				bc(i) := bc(i)-2.0;
			end if;
		end loop;

	elsif( shape=11 ) then
		for i in 1..nblk loop
			if same(br(i),sr) and same(bc(i),sc+1.0)  --swap b,sel
			then
				colcen(selBlock) := sc+1.0;
				bc(i) := bc(i)-1.0;
			end if;
		end loop;

	end if;


	for i in 1..nblk loop
		if not same(obr(i), br(i)) or not same(obc(i), bc(i))  then
			ret:=1;
		end if;
	end loop;

	if( ret > 0 )
	then
		changed:=true;
		if winner then erase:=true; end if;
		nMoves:=nMoves+1;
		test4winner;
	end if;


	return ret;


end moveright;








function moveup return integer is
	sr,sc: float;
	shape, ret : integer:=0;
begin

	for i in 1..nblk loop
		obr(i) := br(i);
		obc(i) := bc(i);
	end loop;

	myassert( selBlock>=1, -5 );
	myassert( selBlock<=dblk, -6 );

	sr   :=rowcen(selBlock);
	sc   :=colcen(selBlock);
	shape:=bshape(selBlock);


	if( shape=31 ) then

		for i in 1..nblk loop
			if same(bc(i),sc) and same(br(i),sr-2.0)  --swap b,sel
			then
				rowcen(selBlock) := sr-1.0;
				br(i) := br(i)+3.0;
			end if;
		end loop;

	elsif( shape=21 ) then

		for i in 1..nblk loop
			if same(bc(i),sc) and same(br(i),sr-1.5)  --swap b,sel
			then
				rowcen(selBlock) := sr-1.0;
				br(i) := br(i)+2.0;
			end if;
		end loop;

	elsif( shape=11 ) then

		for i in 1..nblk loop
			if same(bc(i),sc) and same(br(i),sr-1.0)  --swap b,sel
			then
				rowcen(selBlock) := sr-1.0;
				br(i) := br(i)+1.0;
			end if;
		end loop;

	end if;



	for i in 1..nblk loop
		if not same(obr(i), br(i)) or not same(obc(i), bc(i))  then
			ret:=1;
		end if;
	end loop;

	if( ret > 0 )	
	then
		changed:=true;
		if winner then erase:=true; end if;
		nMoves:=nMoves+1;
		test4winner;
	end if;

	return ret;

end moveup;






function movedown return integer is
	sr,sc: float;
	shape, ret: integer := 0;
begin


	for i in 1..nblk loop
		obr(i) := br(i);
		obc(i) := bc(i);
	end loop;

	myassert( selBlock>=1, -7 );
	myassert( selBlock<=dblk, -8 );

	sr   :=rowcen(selBlock);
	sc   :=colcen(selBlock);
	shape:=bshape(selBlock);


	if( shape=31 ) then

		for i in 1..nblk loop
			if same(bc(i),sc) and same(br(i),sr+2.0)  --swap b,sel
			then
				rowcen(selBlock) := sr+1.0;
				br(i) := br(i)-3.0;
			end if;
		end loop;

	elsif( shape=21 ) then

		for i in 1..nblk loop
			if same(bc(i),sc) and same(br(i),sr+1.5)  --swap b,sel
			then
				rowcen(selBlock) := sr+1.0;
				br(i) := br(i)-2.0;
			end if;
		end loop;

	elsif( shape=11 ) then

		for i in 1..nblk loop
			if same(bc(i),sc) and same(br(i),sr+1.0)  --swap b,sel
			then
				rowcen(selBlock) := sr+1.0;
				br(i) := br(i)-1.0;
			end if;
		end loop;

	end if;

	for i in 1..nblk loop
		if not same(obr(i), br(i)) or not same(obc(i), bc(i))  then
			ret:=1;
		end if;
	end loop;

	if( ret > 0 )	
	then
		changed:=true;
		if winner then erase:=true; end if;
		nMoves:=nMoves+1;
		test4winner;
	end if;

	return ret;

end movedown;















procedure Draw is
	info: terminal_info;
	Ok: boolean;
	ch: character;
	rc,cc: float;
	ulr, ulc : integer;
	tj : array(1..6,1..6) of character := (others=>(others=>' '));
	ts : array(1..6,1..6) of integer := (others=>(others=>11));
	goalcol : integer := integer(float'rounding(gcol));
	goalrow : integer := integer(float'rounding(grow));

	-- m=magenta, y=yellow, r=red, g=grey, 
	-- b=blue, k=black, n=green, c=cyan
	type enum is (m,y,r,g,b,k,n,c,x); -- x => not yet set
	colr : enum := x;
begin
if changed or erase then

	changed:=false;

	--16oct17 redundant
	--tj := (others=>(others=>' '));
	--ts := (others=>(others=>11));

	info.init_for_stdout(auto);


if erase then

	if mswin then
		SysUtils.Shell("cls", Ok); -- erase-terminal
	else
		SysUtils.Shell("clear", Ok); -- erase-terminal
	end if;
	erase:=false;

else

	if mswin then
		--SysUtils.Shell("tput00", Ok); -- erase-terminal
		--ret:=tput00_h.tput00;
		tput00_h.cursorHome;
	else
		SysUtils.Shell("tput cup 0 0", Ok); -- erase-terminal
	end if;

end if;


if help then

	put_line(" CoTerminalRush--help-screen");
	put_line(" q,x => quit");
	put_line(" ? => toggle-help");
	put_line(" r => restart");
	put_line(" s => toggle colors for Speed");
	put_line(" The strings of letters represent cars and trucks");
	put_line(" in a crowded parking lot.  The objective is to");
	put_line(" move them lengthwise to get red car 'a' to the exit.");
	--put_line(" Note: last # in puzzle name is minimum moves.");
	put_line("=======================================");
	put_line(" Select vehicle first, using keys a..m");
	put_line(" Then use arrow-keys to move");
	put_line(" Keys: <+>, <-> => next, prev puzzle.");
	put_line("==============================");

else

	put_line(" CoTerminalRush");

	--put_line(objectiveText);
	put_line(" minimum: " & movesText );

	put_line(" move the red 'a' vehicle to exit");
	put_line(" q = quit,  ? = toggle-help,  + = next");
	new_line;

	for i in 1..dblk loop
		ch := idchar(i);
		rc := rowcen(i);
		cc := colcen(i);
		case bshape(i) is

			--when 11 => 
				--ulr := integer(float'rounding(+0.5+rc));
				--ulc := integer(float'rounding(+0.5+cc));
				--tj(ulr+0,ulc+0):=ch;

			when 12 => 
				ulr := integer(float'rounding(+0.5+rc));
				ulc := integer(float'rounding(+0.0+cc));
				tj(ulr+0,ulc+0):=ch;
				tj(ulr+0,ulc+1):=ch;

				if i=1 then
					ts(ulr+0,ulc+0):=0;
					ts(ulr+0,ulc+1):=0; -- red
				else
					ts(ulr+0,ulc+0):=12;
					ts(ulr+0,ulc+1):=12; --magenta
				end if;

			when 21 =>
				ulr := integer(float'rounding(+0.0+rc));
				ulc := integer(float'rounding(+0.5+cc));
				tj(ulr+0,ulc+0):=ch;
				tj(ulr+1,ulc+0):=ch;

				if i=1 then
					ts(ulr+0,ulc+0):=0;
					ts(ulr+1,ulc+0):=0; --red
				else
					ts(ulr+0,ulc+0):=21;
					ts(ulr+1,ulc+0):=21; --green
				end if;

			when 13 =>
				ulr := integer(float'rounding(+0.5+rc));
				ulc := integer(float'rounding(-0.5+cc));
				tj(ulr+0,ulc+0):=ch;
				tj(ulr+0,ulc+1):=ch;
				tj(ulr+0,ulc+2):=ch;

				ts(ulr+0,ulc+0):=13;
				ts(ulr+0,ulc+1):=13; --yellow
				ts(ulr+0,ulc+2):=13;

			when 31 =>
				ulr := integer(float'rounding(-0.5+rc));
				ulc := integer(float'rounding(+0.5+cc));
				tj(ulr+0,ulc+0):=ch;
				tj(ulr+1,ulc+0):=ch;
				tj(ulr+2,ulc+0):=ch;

				ts(ulr+0,ulc+0):=31;
				ts(ulr+1,ulc+0):=31; --cyan
				ts(ulr+2,ulc+0):=31;

			when others => null;
		end case;
	end loop;


-- begin draw puzzle--------------------

   Info.Set_Color (style=>bright);
	if speedup then
	Info.Set_Bg(magenta);
	Info.Set_Fg(yellow); colr:=y;
	else
   Info.Set_Color (background=>black);
	info.set_color(foreground=>red); colr:=r;
	end if;

	if vertical then
		put("#");
		for c in 1..6 loop
			if c/=goalcol then
				put("##");
			else
				put("# ");
			end if;
		end loop;
		put_line("##");
	else
		put_line("###############");
	end if;


	for row in 1..6 loop
		put("#");
		for col in 1..6 loop
			if not speedup then
			case ts(row,col) is
				when  0 => if colr/=r then info.set_color(foreground=>red); colr:=r; end if;
				when 12 => if colr/=m then info.set_color(foreground=>magenta); colr:=m; end if;
				when 21 => if colr/=n then info.set_color(foreground=>green); colr:=n; end if;
				when 13 => if colr/=y then info.set_color(foreground=>yellow); colr:=y; end if;
				when 31 => if colr/=c then info.set_color(foreground=>cyan); colr:=c; end if;
				when others => null;
			end case;
			end if;
			put( ' ' & tj(row,col) );
		end loop;

		if not speedup and colr/=r then
		info.set_color(foreground=>red); colr:=r;
		end if;

		if vertical then
			put(" #");
		else
			if row=goalrow then
				put("  ");
			else
				put(" #");
			end if;
		end if;
		new_line;
	end loop;


	put_line("###############");
   Info.Set_Color (Standard_Output, Style => Reset_All);

-- end draw puzzle----------------------

	put("Press = to solve...");
	if movesrem>0 then
		put_line(integer'image(movesrem)&" steps remain");
	else
		--new_line;
		put_line("                  ");
	end if;


	put_line( to_string(infilname) );



	if winner then
		put_line("Correct !");
		put_line("Solved in "&integer'image(nMoves)&" steps");
	end if;

end if;
end if; --changed
end Draw;








function goodChar(ch: character) return boolean is
begin
	if ada.characters.handling.is_letter(ch) then
		return true;

	elsif 
		(ch='?') or (ch='=') or (ch='+') or (ch='-')
	then
		return true;

	else
		return false;

	end if;
end;




procedure handle_key_down( ch: character; puzdir: unbounded_string ) is
	ret : integer;
	idch, ckch, mvch : character;

begin


-- note that arrow keys typically produce chars
-- preceded by 1 or 2 non-printable chars.
--
-- on Linux:		<home>='H'	<end>='F'
--   A		
-- D B C
--
-- or on MSWin:	<home>='G'	<end>='O'
--   H
-- K P M


if goodChar(ch) then


	case ch is

		when '=' =>

		if not winner then

			if movesrem>0 then

				idch := element(solutionPath,1);
				ckch := element(solutionPath,2);
				mvch := element(solutionPath,3);
				myassert(ckch='-', -999);
				delete(solutionPath,1,3);
				movesrem := length(solutionPath)/3;
				selBlock := character'pos(idch) - character'pos('a') + 1;

				myassert( selBlock>=1, -11 );
				myassert( selBlock<=dblk, -12 );

				if    mvch='u' then ret:=moveup;
				elsif mvch='d' then ret:=movedown;
				elsif mvch='l' then ret:=moveleft;
				elsif mvch='r' then ret:=moveright;
				else raise program_error; end if;

				myassert( ret>0, 999 );

			else -- initiate solver

				dumpGameState("rush.txt");
				fbfsr.bfsr( to_unbounded_string("rush.txt"), solutionPath);
				movesrem := length(solutionPath)/3;
				changed:=true;

				--debug only
				--dumpSol(movesrem,solutionPath);

			end if;

		end if; --not winner



		when 'a'..'p' =>  -- manually select block to move next
			selBlock:= character'pos(ch) - character'pos('a') + 1;
			movesrem:=0;
			myassert( selBlock>=1, -13 );
			myassert( selBlock<=dblk, -14 );

		when 'x' | 'q' =>	
			userexit:=true;

		when '?'  => 
			help := not help; 
			erase:=true;

		when 'r' =>
			movesrem:=0;
			Init( to_string(infilname) );
			erase:=true;

		when 's' => speedup:= not speedup;

		when 'H'|'A' =>	
			movesrem:=0;
			ret:=moveup;
			if ret=0 then --try autoselect
				selBlock:=0;
				while ret=0 loop
					selBlock:=selBlock+1;
					ret:=moveup;
					exit when selBlock=dblk;
				end loop;
			end if;

		when 'P'|'B' =>	
			movesrem:=0;
			ret:=movedown;
			if ret=0 then --try autoselect
				selBlock:=0;
				while ret=0 loop
					selBlock:=selBlock+1;
					ret:=movedown;
					exit when selBlock=dblk;
				end loop;
			end if;


		when 'M'|'C' =>	
			movesrem:=0;
			ret:=moveright;
			if ret=0 then --try autoselect
				selBlock:=0;
				while ret=0 loop
					selBlock:=selBlock+1;
					ret:=moveright;
					exit when selBlock=dblk;
				end loop;
			end if;


		when 'K'|'D' =>	
			movesrem:=0;
			ret:=moveleft;
			if ret=0 then --try autoselect
				selBlock:=0;
				while ret=0 loop
					selBlock:=selBlock+1;
					ret:=moveleft;
					exit when selBlock=dblk;
				end loop;
			end if;


		when '+' => 
			movesrem:=0;
			npuz:=npuz+1;
			if npuz>totgame then npuz:=1; end if;
			infilname := puzdir & shortname(npuz);
			Init( to_string(infilname) );
			erase:=true;

		when '-' => 
			movesrem:=0;
			npuz:=npuz-1;
			if npuz<1 then npuz:=totgame; end if;
			infilname := puzdir & shortname(npuz);
			Init( to_string(infilname) );
			erase:=true;


		when others => changed:=false;

	end case;

end if;
end handle_key_down;











gfil: text_io.file_type;

surchdir : unbounded_string := to_unbounded_string("puzzles/");
up2 : constant string := "../../";


	--linestr: string(1..9);
	--last: natural;



	rtime: interfaces.c.int;


begin --crush


	if mswin then
		rtime:=realtime_hpp.hiPriority;
		-- note:  this seems necessary because some, 
		-- but not all, windows commandline terminals 
		-- seem to randomly freeze at normal priority.
	else
		rtime:=1;
	end if;





	if not ada.directories.exists( to_string(surchdir) ) then
		surchdir := up2 & surchdir;
		savename := up2 & savename;
	end if;



------- begin dynamic read of ./puzzles/ directory --------------------------------

	-- find *.rush files under ./puzzles/
	put_line("Here are the rush files found under ./puzzles/ :");
	totgame:=0;
	start_search( search, to_string(surchdir), "*.rush" );
	while more_entries( search ) loop

		get_next_entry( search, directory_entry );
		totgame:=totgame+1;

		gamefiles(totgame)  := to_unbounded_string( full_name( directory_entry ) );
		shortName(totgame):= to_unbounded_string( simple_name(directory_entry) );
		put_line( shortName(totgame) );

	end loop; -- while more_entries
	--fmax:=totgame;
	put_line("...for a total of totgame="&integer'image(totgame));
	new_line;


------- end dynamic read of ./puzzles/ directory --------------------------------



	npuz:=1; -- default to easiest

	if( ada.directories.exists( to_string(savename) ) ) then
		text_io.open(gfil, text_io.in_file, to_string(savename) );

		myint_io.get(gfil, npuz);
		--linestr := (others=>' ');
		--text_io.get_line(gfil,linestr,last);
		--myint_io.get(linestr,npuz,last);

		text_io.close(gfil);
		if npuz<1 then npuz:=1; end if;
		if npuz>totgame then npuz:=totgame; end if;
	end if;

	infilname := surchdir & shortname(npuz);
	Init( to_string(infilname) ); --// define puzzle parameters here



	if mswin then
		SysUtils.Shell("cls", Ok); -- erase-terminal
	else
		SysUtils.Shell("clear", Ok); -- erase-terminal
	end if;


-- begin main event loop:

	changed:=true;
	Draw;
	while not userexit loop
		get_immediate(ch);
		handle_key_down( ch, surchdir );
		Draw;
	end loop;

-- end main event loop:

	-- save current state:
	text_io.create(gfil, text_io.out_file, to_string(savename) );
	myint_io.put(gfil, npuz);
	text_io.close(gfil);


end crush;

