

--
-- Copyright (C) 2024  <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 gl, gl.binding, gl.pointers;
with glu, glu.binding, glu.pointers;
with glext, glext.binding, glext.pointers;



with glfw3; use glfw3;



with matutils;

with gtex;


with shader;  use shader;
with pictobj;
with pngloader;

with ada.calendar;
with ada.characters.handling;
with ada.strings.fixed;

with ada.directories;

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

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


with ada.unchecked_conversion;
with Ada.Command_Line;
with Ada.Strings.Unbounded;
with Ada.Strings.Unbounded.Text_IO;
with ada.numerics.generic_elementary_functions;

with text_io;
with ada.float_text_io;
with ada.integer_text_io;

with ada.calendar;
with unchecked_deallocation;

with ada.strings.fixed;

with gnat.os_lib;



procedure asud is


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

	use text_io;
	use pngloader;
	use matutils;

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



	mainWindow :  access GLFWwindow;
	Nwid,Nhit,Mwid,Mhit,Wwid,Whit,  Fwid, Fhit : aliased interfaces.c.int;


	pmvp : chars_ptr := new_string("MVP"&ascii.nul);
	pmyts : chars_ptr := new_string("myTextureSampler"&ascii.nul);


	vertbuff, uvbuff, elembuff, rgbbuff, vertexarrayid : gluint;

	matrixid, uniftex : glint;
	ol1_texid, ol2_texid, 
	ol3_texid, ol4_texid, 
	ol5_texid, ol6_texid, 
	ol7_texid, ol8_texid,  ol9_texid,
	pink_texid,
	blu_texid,
	floor_texid, space_texid, box_texid, red_texid,
		black_texid, gray_texid, pic_texid, picttexshadid : gluint := 0;

	opict: pictobj.pictangle;




	crlf: constant string := Character'Val(13)&Character'Val(10); 
	--CR+LF(msWin) (new_line)

	--used for delayed write to console, if and when a contradiction arises:
	consoleBuf: unbounded_string;

	restoredPuzzle,
	wasDeletion,
	showK, showKsel,
	showBrute,
	showLP,
	showy, --Ywing
	shoXwing, --Xwing
	show3n, show3h, --triples
	show4n, show4h, --quads
	show2n, show2h, --pairs
	bmode,rmode,cmode,
	overlay1, overlay2,
	overlay3, overlay4,
	overlay5, overlay6,
	overlay7, overlay8, overlay9,
	manualmode: boolean := false; -- toggles De-cluttered screen

	rowPairs, 
	colPairs,
	boxPairs,
	boxPairsNa,
	boxPairsAl
		: boolean := false;

	nrows, ncols : constant integer := 9;
	subtype entryrange is integer range 1..9;
	type flagtypes is array(entryrange) of boolean;

----------------------------------------------------
	subtype i9 is integer range 1..9;
	subtype s9 is integer range 0..9;
	-- zero indicates indeterminate digit

	type pinktype is array(i9,i9) of boolean; --8may24 addendum for manual mode only
	pinkcell : pinktype := (others=>(others=>false));
	shopink: boolean := false;

	nu,n0: s9 := 0; --track numbered saves for Erase ftn (key_e)

	s99mx: constant integer := 12;
	subtype s99 is integer range 0..s99mx;
	seechain, nchains : array(i9) of s99;
	none: array(i9) of boolean;
	subtype s3 is integer range 0..3;

	digBuf: array(i9,s99) of unbounded_string; --for replay of LinkedPairs logic


	--struct for linkedPairs:
	colorL2: array(i9,s99,entryrange,entryrange) of s3;
	-- 1st index is digitSelect
	-- 2nd index is simply the chain number...
	-- hopefully there are fewer than s99mx=12...
	-- 1 => Red; 2 => Green [colors apply to digSelect only]
	-- tracks color of linked-pairs
	--
	-- plan: choose a digit "d", 
	-- then set all linked-pairs as
	-- 2 alternating colors Red/Green...
	-- helpful rules:
	-- a) if any house has 2 d's of same color, that color means OFF
	-- b) if any OTHER d can see both colors, it must be OFF.


	type candidatetype is array(entryrange,entryrange) of flagtypes;

	hiliteKdel, --KeyCell-deleted

	hiliteXcDel, --XCycle-deletables
	hilite1,  --lone block digits
	hilite3,  --lone digits

	hiliteHQ, --hiddenQuads
	hiliteHP, --hiddenPairs
	hiliteHT, --hiddenTriples
	
	--removables...
	hiliteHQrem, --hiddenQuads
	hiliteHPrem, --hiddenPairs
	hiliteHTrem, --hiddenTriples

	hiliteNQrem, hiliteNTrem, hiliteNPrem, --naked removables 15aug23
	
	--hiliteRC, --row/col digit pairs
	hiliteRow, hiliteCol,
	hiliteRowRem,
	hiliteColRem,

	hiliteBoxRem,
	hiliteBPna, -- non-aligned BoxPairs
	hiliteBP,  -- aligned block-pairs

	candidate, drawnYet
		:  candidatetype
			:= (others=>(others=>(others=>true)));

	mandidate
		:  candidatetype
			:= (others=>(others=>(others=>false)));

	boxrem: boolean := false;


	remEmpty
		:  constant candidatetype
			:= (others=>(others=>(others=>false)));


	--naked pairs, Quads, Triples
	hiliteNP, hiliteNQ, hiliteNT : array(entryrange,entryrange) of boolean;



	pr,pc: integer := 0; --picked row, col (by getmouse)

	rowPair, colPair, BoxPair : array(i9,i9,i9) of s9;

	tr0,tc0, tdig, ypr,ypc: s9; -- Ywing


	type m9type is array(i9,i9) of s9;

	--yel9, --for showK: flags house doubles in "blu9" array
	blu9, --for showK: holds contents of m9 after "kram" has exitted
	om9, m9, sol: m9type := (others=>(others=>0));
	--a structure to hold the array
	--that represents the current singletons, if known,
	--and zeros if not known.

	package purtex is new gtex; -- initialize to purple
	package cyatex is new gtex; -- initialize to cyan
	package blutex is new gtex; -- initialize to blue
	package blktex is new gtex; -- initialize to black
	package grytex is new gtex; -- initialize to grey
	package ltgtex is new gtex; -- initialize to LtGrey
	package gr2tex is new gtex; -- initialize to grey
	package whitex is new gtex; -- initialize to white
	package redtex is new gtex; -- initialize to red
	package magtex is new gtex; -- initialize to magenta
	package orntex is new gtex; -- initialize to orange
	package yebtex is new gtex; -- initialize to bright-yellow
	package grntex is new gtex; -- initialize to green


function i2st( i: integer ) return string is
begin
	if i>=0 and i<=9 then
		return ada.strings.fixed.trim( integer'image(i), ada.strings.left);
	else
		return "";
	end if;
end i2st;




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;





--check for empty cell; return coords of last one found:
function emptycell( r,c: out s9 ) return boolean is
	empty, found: boolean := false;
begin
	r:=0; c:=0;
	for row in 1..9 loop
	for col in 1..9 loop --test each cell

		empty:=true;
		for dig in 1..9 loop --test each digit
		if candidate(row,col)(dig) then
			empty := false;
		end if;
		end loop; --dig

		if empty then 
			found:=true;
			r:=row;
			c:=col;
		end if;

	end loop; --col
	end loop; --row
	return found;
end emptycell;


--check all houses for missing candidate digits:
function missingDigit( bno, rno, cno: out s9 ) return boolean is
	empty, found: boolean := false;
begin

	bno:=0;
	rno:=0;
	cno:=0;
------------------------------------------------------------

	--check blocks
	for br in 0..2 loop
	for bc in 0..2 loop

	for d in 1..9 loop

		found:=false;
		for r in 0..2 loop
		for c in 0..2 loop
			if candidate(br*3+r+1,bc*3+c+1)(d) then 
				found:=true; 
			end if;
		end loop; --c
		end loop; --r
		if not found then
			empty:=true;
			bno := br*3+bc+1;
		end if;

	end loop; --d

	end loop; --bc
	end loop; --br

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

	--check rows
	for r in 1..9 loop
	for d in 1..9 loop

		found:=false;
		for c in 1..9 loop
			if candidate(r,c)(d) then found:=true; end if;
		end loop; --c
		if not found then
			empty:=true;
			rno:=r;
		end if;

	end loop; --d
	end loop; --r

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

	--check cols
	for c in 1..9 loop
	for d in 1..9 loop

		found:=false;
		for r in 1..9 loop
			if candidate(r,c)(d) then found:=true; end if;
		end loop; --c
		if not found then
			empty:=true;
			cno:=c;
		end if;

	end loop; --d
	end loop; --c

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

	return empty;

end missingDigit;


function numZeros return integer is
	nz: integer := 0;
begin
	for r in 1..9 loop
	for c in 1..9 loop
	if m9(r,c)=0 then 
		nz:=nz+1; 
	end if;
	end loop; --c
	end loop; --r
	return nz;
end numZeros;





procedure susolve is separate;



subtype coorng is integer range 1..9;
type coords is array(1..2) of coorng;
type cellseq is array(1..29) of coords;


subtype ocoorng is integer range 0..9;
--type ocoords is array(1..2) of ocoorng;
type ocoords is array(0..2) of ocoorng;
type xcycletype is array(1..9,1..9) of ocoords;
type xoncycletype is array(1..9,1..9) of boolean;
xcycle: xcycletype;
xoncycle, xoffcycle: xoncycletype;
ca, cz : ocoords; -- beginning & end of a bad Xcycle
badXc, showX : boolean := false; --Xcycle


digSelect: s9;


rx1,cx1, rx2,cx2, rx3,cx3,
rx4,cx4, xdig, --Xwing stuff
ry1,cy1, ry2,cy2, ry3,cy3 : s9 := 0; --coorng;



-- returns cell coords of a Ywing triple
procedure yWing(
	r1,c1, r2,c2, r3,c3, tr0,tc0, dig, pvr,pvc: out s9; 
	found: out boolean) is separate;


xcd: cellseq;
xcn: integer;
procedure Xwing(
	r1,c1, r2,c2, r3,c3, r4,c4, dig: out s9;
	cdelete: out cellseq; cdn: out integer;
	found: out boolean) is separate;



-- returns 1st bad Xcycle
procedure badXcycle(
	xcycle: in out xcycletype;
	ca, cz: out ocoords;
	odig : out i9;
	found: out boolean ) is separate;


procedure goodXcycle(
	xcycle: in out xcycletype;
	ca, cz: out ocoords;
	odig : out i9;
	found, bad: out boolean;
	deletable: out candidatetype
	) is separate;





-- find hidden triples
procedure hiddenTriples( rcd: cellseq; 
	t1,t2,t3, dt1,dt2,dt3,
	s1,s2,s3, ds1,ds2,ds3: out coorng; 
	found, found2: out boolean) is separate;

-- find naked triples:
procedure nakedTriples( rcd: cellseq; 
	t1, t2, t3, s1,s2,s3: out coorng; 
	d1,d2,d3, d4,d5,d6: out i9;
	found, found2: out boolean) is separate;


-- find hidden Quads:
procedure hiddenQuads( rcd: cellseq; 
	t1,t2,t3,t4, dt1,dt2,dt3,dt4: out coorng; 
	found: out boolean) is separate;

procedure nakedQuads( rcd: cellseq; 
	t1, t2, t3, t4: out coorng; 
	d1,d2,d3,d4: out i9;
	found: out boolean) is separate;


-- find hidden pairs
procedure hiddenPairs( rcd: cellseq; 
	t1,t2, dt1,dt2,
	s1,s2, ds1,ds2: out coorng; 
	found, found2: out boolean) is separate;


-- find naked pairs
procedure nakedPairs( rcd: cellseq; 
	t1,t2, s1,s2: out coorng;
	d1,d2, d3,d4: out i9;
	found, found2: out boolean) is separate;







procedure setNpairs is --Naked pairs
	rcd: cellseq;
	t1,t2, s1,s2: coorng;
	found, found2: boolean;
	k,row,col: integer;

	d1,d2, d3,d4 : i9; --digit pairs

	--flag for naked block-pairs::
	showbox : boolean := true; --adds clutter!

begin

	hiliteNP := (others=>(others=>false));
	hiliteNPrem := (others=>(others=>(others=>false)));

	--RowPairs:
	for row in 1..9 loop

		for col in 1..9 loop
			rcd(col):=(row,col);
		end loop; --col

		nakedPairs(rcd, t1,t2, s1,s2, d1,d2, d3,d4, found, found2);
		if found then
			hiliteNP( rcd(t1)(1), rcd(t1)(2) ) := true;
			hiliteNP( rcd(t2)(1), rcd(t2)(2) ) := true;

			--now ID like digits in OTHER cells of the house:
			myassert( rcd(t1)(1) = rcd(t2)(1) );
			for col in 1..9 loop
			if col/=rcd(t1)(2) and col/=rcd(t2)(2) then
				if candidate(row,col)(d1) then
					hiliteNPrem(row,col)(d1):=true;
				end if;
				if candidate(row,col)(d2) then
					hiliteNPrem(row,col)(d2):=true;
				end if;
			end if;
			end loop;

		end if;
		if found2 then
			hiliteNP( rcd(s1)(1), rcd(s1)(2) ) := true;
			hiliteNP( rcd(s2)(1), rcd(s2)(2) ) := true;

			--now ID like digits in OTHER cells of the house:
			myassert( rcd(s1)(1) = rcd(s2)(1) );
			for col in 1..9 loop
			if col/=rcd(s1)(2) and col/=rcd(s2)(2) then
				if candidate(row,col)(d3) then
					hiliteNPrem(row,col)(d3):=true;
				end if;
				if candidate(row,col)(d4) then
					hiliteNPrem(row,col)(d4):=true;
				end if;
			end if;
			end loop;

		end if;

	end loop; --row


	--ColPairs:
	for col in 1..9 loop

		for row in 1..9 loop
			rcd(row):=(row,col);
		end loop; --col

		nakedPairs(rcd, t1,t2, s1,s2, d1,d2, d3,d4, found, found2);
		if found then
			hiliteNP( rcd(t1)(1), rcd(t1)(2) ) := true;
			hiliteNP( rcd(t2)(1), rcd(t2)(2) ) := true;

			--now ID like digits in OTHER cells of the house:
			myassert( rcd(t1)(2) = rcd(t2)(2) );
			for row in 1..9 loop
			if row/=rcd(t1)(1) and row/=rcd(t2)(1) then
				if candidate(row,col)(d1) then
					hiliteNPrem(row,col)(d1):=true;
				end if;
				if candidate(row,col)(d2) then
					hiliteNPrem(row,col)(d2):=true;
				end if;
			end if;
			end loop;


		end if;
		if found2 then
			hiliteNP( rcd(s1)(1), rcd(s1)(2) ) := true;
			hiliteNP( rcd(s2)(1), rcd(s2)(2) ) := true;

			--now ID like digits in OTHER cells of the house:
			myassert( rcd(s1)(2) = rcd(s2)(2) );
			for row in 1..9 loop
			if row/=rcd(s1)(1) and row/=rcd(s2)(1) then
				if candidate(row,col)(d3) then
					hiliteNPrem(row,col)(d3):=true;
				end if;
				if candidate(row,col)(d4) then
					hiliteNPrem(row,col)(d4):=true;
				end if;
			end if;
			end loop;


		end if;

	end loop; --col


if showbox then

	--BlockPairs:
	for blkrow in 0..2 loop
	for blkcol in 0..2 loop

		k:=0;
		for r in 0..2 loop
		for c in 0..2 loop
			k:=k+1;
			row:=blkrow*3+r+1;
			col:=blkcol*3+c+1;
			rcd(k):=(row,col);
		end loop; --c
		end loop; --r

		nakedPairs(rcd, t1,t2, s1,s2, d1,d2, d3,d4, found, found2);
		if found then
			hiliteNP( rcd(t1)(1), rcd(t1)(2) ) := true;
			hiliteNP( rcd(t2)(1), rcd(t2)(2) ) := true;

			--now ID like digits in OTHER cells of the house:
			for r in 0..2 loop
			for c in 0..2 loop
			row:=blkrow*3+r+1;
			col:=blkcol*3+c+1;
			if 
				(row/=rcd(t1)(1) or col/=rcd(t1)(2))
				and
				(row/=rcd(t2)(1) or col/=rcd(t2)(2))
			then
				if candidate(row,col)(d1) then
					hiliteNPrem(row,col)(d1):=true;
				end if;
				if candidate(row,col)(d2) then
					hiliteNPrem(row,col)(d2):=true;
				end if;
			end if;
			end loop;
			end loop;

		end if;

		if found2 then
			hiliteNP( rcd(s1)(1), rcd(s1)(2) ) := true;
			hiliteNP( rcd(s2)(1), rcd(s2)(2) ) := true;

			--now ID like digits in OTHER cells of the house:
			for r in 0..2 loop
			for c in 0..2 loop
			row:=blkrow*3+r+1;
			col:=blkcol*3+c+1;
			if 
				(row/=rcd(s1)(1) or col/=rcd(s1)(2))
				and
				(row/=rcd(s2)(1) or col/=rcd(s2)(2))
			then
				if candidate(row,col)(d3) then
					hiliteNPrem(row,col)(d3):=true;
				end if;
				if candidate(row,col)(d4) then
					hiliteNPrem(row,col)(d4):=true;
				end if;
			end if;
			end loop;
			end loop;

		end if;

	end loop; --blkcol
	end loop; --blkrow

end if; --showbox




end setNpairs;




procedure setHPairs is --Hidden pairs
	rcd: cellseq;
	dt1,dt2, ds1,ds2,
	t1,t2, s1,s2: coorng;
	found, found2: boolean;
	k,row,col: integer;
begin

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


if rmode then

	--RowPairs:
	for row in 1..9 loop
		for col in 1..9 loop
			rcd(col):=(row,col);
		end loop; --col

		hiddenPairs(rcd, t1,t2, dt1,dt2, s1,s2, ds1,ds2, found, found2);
		if found then
			hiliteHP( rcd(t1)(1), rcd(t1)(2) )(dt1) := true;
			hiliteHP( rcd(t2)(1), rcd(t2)(2) )(dt1) := true;

			hiliteHP( rcd(t1)(1), rcd(t1)(2) )(dt2) := true;
			hiliteHP( rcd(t2)(1), rcd(t2)(2) )(dt2) := true;

		end if;
		if found2 then
			hiliteHP( rcd(s1)(1), rcd(s1)(2) )(ds1) := true;
			hiliteHP( rcd(s2)(1), rcd(s2)(2) )(ds1) := true;

			hiliteHP( rcd(s1)(1), rcd(s1)(2) )(ds2) := true;
			hiliteHP( rcd(s2)(1), rcd(s2)(2) )(ds2) := true;

		end if;

	end loop; --row

end if; --rmode


if cmode then

	--ColPairs:
	for col in 1..9 loop
		for row in 1..9 loop
			rcd(row):=(row,col);
		end loop; --col

		hiddenPairs(rcd, t1,t2, dt1,dt2, s1,s2, ds1,ds2, found, found2);
		if found then
			hiliteHP( rcd(t1)(1), rcd(t1)(2) )(dt1) := true;
			hiliteHP( rcd(t2)(1), rcd(t2)(2) )(dt1) := true;

			hiliteHP( rcd(t1)(1), rcd(t1)(2) )(dt2) := true;
			hiliteHP( rcd(t2)(1), rcd(t2)(2) )(dt2) := true;

		end if;
		if found2 then
			hiliteHP( rcd(s1)(1), rcd(s1)(2) )(ds1) := true;
			hiliteHP( rcd(s2)(1), rcd(s2)(2) )(ds1) := true;

			hiliteHP( rcd(s1)(1), rcd(s1)(2) )(ds2) := true;
			hiliteHP( rcd(s2)(1), rcd(s2)(2) )(ds2) := true;

		end if;

	end loop; --col

end if; --cmode


if bmode then

	--BlockPairs:
	for blkrow in 0..2 loop
	for blkcol in 0..2 loop

		k:=0;
		for r in 0..2 loop
		for c in 0..2 loop
			k:=k+1;
			row:=blkrow*3+r+1;
			col:=blkcol*3+c+1;
			rcd(k):=(row,col);
		end loop; --c
		end loop; --r

		hiddenPairs(rcd, t1,t2, dt1,dt2, s1,s2, ds1,ds2, found, found2);
		if found then
			hiliteHP( rcd(t1)(1), rcd(t1)(2) )(dt1) := true;
			hiliteHP( rcd(t2)(1), rcd(t2)(2) )(dt1) := true;

			hiliteHP( rcd(t1)(1), rcd(t1)(2) )(dt2) := true;
			hiliteHP( rcd(t2)(1), rcd(t2)(2) )(dt2) := true;

		end if;
		if found2 then
			hiliteHP( rcd(s1)(1), rcd(s1)(2) )(ds1) := true;
			hiliteHP( rcd(s2)(1), rcd(s2)(2) )(ds1) := true;

			hiliteHP( rcd(s1)(1), rcd(s1)(2) )(ds2) := true;
			hiliteHP( rcd(s2)(1), rcd(s2)(2) )(ds2) := true;

		end if;

	end loop; --blkcol
	end loop; --blkrow

end if; --bmode


	--ID removable cellmates of hidden pairs
	hiliteHPrem := (others=>(others=>(others=>false)));
	for r in 1..9 loop
	for c in 1..9 loop
	for d in 1..9 loop
	if hiliteHP(r,c)(d) then
		for o in 1..9 loop
		if not hiliteHP(r,c)(o) and candidate(r,c)(o) then
			hiliteHPrem(r,c)(o):=true;
		end if;
		end loop; --o
	end if;
	end loop;
	end loop; --c
	end loop; --r

end setHPairs;





procedure setNtriples is --Naked pairs/triples
	rcd: cellseq;
	t1,t2,t3, s1,s2,s3: coorng;
	found, found2: boolean;
	k,row,col: integer;
	d1,d2,d3, d4,d5,d6: i9;

	--flag for naked block-triples::
	showbox : boolean := true; --adds clutter!
begin

	hiliteNT := (others=>(others=>false));
	hiliteNTrem := (others=>(others=>(others=>false)));



	--RowTriples:
	for row in 1..9 loop

		for col in 1..9 loop
			rcd(col):=(row,col);
		end loop; --col

		nakedTriples(rcd, t1,t2,t3, s1,s2,s3, d1,d2,d3, d4,d5,d6, found, found2);
		if found then
			hiliteNT( rcd(t1)(1), rcd(t1)(2) ) := true;
			hiliteNT( rcd(t2)(1), rcd(t2)(2) ) := true;
			hiliteNT( rcd(t3)(1), rcd(t3)(2) ) := true;

			--now ID like digits in OTHER cells of the house:
			for col in 1..9 loop
			if col/=rcd(t1)(2) and col/=rcd(t2)(2) and col/=rcd(t3)(2) then
				if candidate(row,col)(d1) then
					hiliteNTrem(row,col)(d1):=true;
				end if;
				if candidate(row,col)(d2) then
					hiliteNTrem(row,col)(d2):=true;
				end if;
				if candidate(row,col)(d3) then
					hiliteNTrem(row,col)(d3):=true;
				end if;
			end if;
			end loop;


		end if;
		if found2 then
			hiliteNT( rcd(s1)(1), rcd(s1)(2) ) := true;
			hiliteNT( rcd(s2)(1), rcd(s2)(2) ) := true;
			hiliteNT( rcd(s3)(1), rcd(s3)(2) ) := true;

			--now ID like digits in OTHER cells of the house:
			for col in 1..9 loop
			if col/=rcd(s1)(2) and col/=rcd(s2)(2) and col/=rcd(s3)(2) then
				if candidate(row,col)(d4) then
					hiliteNTrem(row,col)(d4):=true;
				end if;
				if candidate(row,col)(d5) then
					hiliteNTrem(row,col)(d5):=true;
				end if;
				if candidate(row,col)(d6) then
					hiliteNTrem(row,col)(d6):=true;
				end if;
			end if;
			end loop;


		end if;

	end loop; --row

	--ColTriples:
	for col in 1..9 loop

		for row in 1..9 loop
			rcd(row):=(row,col);
		end loop; --col

		nakedTriples(rcd, t1,t2,t3, s1,s2,s3, d1,d2,d3, d4,d5,d6,  found, found2);
		if found then
			hiliteNT( rcd(t1)(1), rcd(t1)(2) ) := true;
			hiliteNT( rcd(t2)(1), rcd(t2)(2) ) := true;
			hiliteNT( rcd(t3)(1), rcd(t3)(2) ) := true;

			--now ID like digits in OTHER cells of the house:
			for row in 1..9 loop
			if row/=rcd(t1)(1) and row/=rcd(t2)(1) and row/=rcd(t3)(1) then
				if candidate(row,col)(d1) then
					hiliteNTrem(row,col)(d1):=true;
				end if;
				if candidate(row,col)(d2) then
					hiliteNTrem(row,col)(d2):=true;
				end if;
				if candidate(row,col)(d3) then
					hiliteNTrem(row,col)(d3):=true;
				end if;
			end if;
			end loop;


		end if;
		if found2 then
			hiliteNT( rcd(s1)(1), rcd(s1)(2) ) := true;
			hiliteNT( rcd(s2)(1), rcd(s2)(2) ) := true;
			hiliteNT( rcd(s3)(1), rcd(s3)(2) ) := true;

			--now ID like digits in OTHER cells of the house:
			for row in 1..9 loop
			if row/=rcd(s1)(1) and row/=rcd(s2)(1) and row/=rcd(s3)(1) then
				if candidate(row,col)(d4) then
					hiliteNTrem(row,col)(d4):=true;
				end if;
				if candidate(row,col)(d5) then
					hiliteNTrem(row,col)(d5):=true;
				end if;
				if candidate(row,col)(d6) then
					hiliteNTrem(row,col)(d6):=true;
				end if;
			end if;
			end loop;


		end if;

	end loop; --col


if showbox then

	--BlockTriples:
	for blkrow in 0..2 loop
	for blkcol in 0..2 loop

		k:=0;
		for r in 0..2 loop
		for c in 0..2 loop
			k:=k+1;
			row:=blkrow*3+r+1;
			col:=blkcol*3+c+1;
			rcd(k):=(row,col);
		end loop; --c
		end loop; --r

		nakedTriples(rcd, t1,t2,t3, s1,s2,s3, d1,d2,d3, d4,d5,d6,  found, found2);
		if found then
			hiliteNT( rcd(t1)(1), rcd(t1)(2) ) := true;
			hiliteNT( rcd(t2)(1), rcd(t2)(2) ) := true;
			hiliteNT( rcd(t3)(1), rcd(t3)(2) ) := true;

			--now ID like digits in OTHER cells of the house:
			for r in 0..2 loop
			for c in 0..2 loop
			row:=blkrow*3+r+1;
			col:=blkcol*3+c+1;
			if 
				(row/=rcd(t1)(1) or col/=rcd(t1)(2))
				and
				(row/=rcd(t2)(1) or col/=rcd(t2)(2))
				and
				(row/=rcd(t3)(1) or col/=rcd(t3)(2))
			then
				if candidate(row,col)(d1) then
					hiliteNTrem(row,col)(d1):=true;
				end if;
				if candidate(row,col)(d2) then
					hiliteNTrem(row,col)(d2):=true;
				end if;
				if candidate(row,col)(d3) then
					hiliteNTrem(row,col)(d3):=true;
				end if;
			end if;
			end loop;
			end loop;


		end if;
		if found2 then
			hiliteNT( rcd(s1)(1), rcd(s1)(2) ) := true;
			hiliteNT( rcd(s2)(1), rcd(s2)(2) ) := true;
			hiliteNT( rcd(s3)(1), rcd(s3)(2) ) := true;

			--now ID like digits in OTHER cells of the house:
			for r in 0..2 loop
			for c in 0..2 loop
			row:=blkrow*3+r+1;
			col:=blkcol*3+c+1;
			if 
				(row/=rcd(s1)(1) or col/=rcd(s1)(2))
				and
				(row/=rcd(s2)(1) or col/=rcd(s2)(2))
				and
				(row/=rcd(s3)(1) or col/=rcd(s3)(2))
			then
				if candidate(row,col)(d4) then
					hiliteNTrem(row,col)(d4):=true;
				end if;
				if candidate(row,col)(d5) then
					hiliteNTrem(row,col)(d5):=true;
				end if;
				if candidate(row,col)(d6) then
					hiliteNTrem(row,col)(d6):=true;
				end if;
			end if;
			end loop;
			end loop;


		end if;

	end loop; --blkcol
	end loop; --blkrow

end if; --showbox

end setNtriples;




procedure setHtriples is --Hidden pairs/triples
	rcd: cellseq;
	t1,t2,t3, dt1,dt2,dt3,
	s1,s2,s3, ds1,ds2,ds3: coorng;
	found, found2: boolean;
	k,row,col: integer;
begin

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


if rmode then

	--RowTriples:
	for row in 1..9 loop
		for col in 1..9 loop
			rcd(col):=(row,col);
		end loop; --col

		hiddenTriples(rcd, 
			t1,t2,t3, dt1,dt2,dt3,
			s1,s2,s3, ds1,ds2,ds3, found, found2);
		if found then
			hiliteHT( rcd(t1)(1), rcd(t1)(2) )(dt1) := true;
			hiliteHT( rcd(t2)(1), rcd(t2)(2) )(dt1) := true;
			hiliteHT( rcd(t3)(1), rcd(t3)(2) )(dt1) := true;

			hiliteHT( rcd(t1)(1), rcd(t1)(2) )(dt2) := true;
			hiliteHT( rcd(t2)(1), rcd(t2)(2) )(dt2) := true;
			hiliteHT( rcd(t3)(1), rcd(t3)(2) )(dt2) := true;

			hiliteHT( rcd(t1)(1), rcd(t1)(2) )(dt3) := true;
			hiliteHT( rcd(t2)(1), rcd(t2)(2) )(dt3) := true;
			hiliteHT( rcd(t3)(1), rcd(t3)(2) )(dt3) := true;

		end if;
		if found2 then
			hiliteHT( rcd(s1)(1), rcd(s1)(2) )(ds1) := true;
			hiliteHT( rcd(s2)(1), rcd(s2)(2) )(ds1) := true;
			hiliteHT( rcd(s3)(1), rcd(s3)(2) )(ds1) := true;

			hiliteHT( rcd(s1)(1), rcd(s1)(2) )(ds2) := true;
			hiliteHT( rcd(s2)(1), rcd(s2)(2) )(ds2) := true;
			hiliteHT( rcd(s3)(1), rcd(s3)(2) )(ds2) := true;

			hiliteHT( rcd(s1)(1), rcd(s1)(2) )(ds3) := true;
			hiliteHT( rcd(s2)(1), rcd(s2)(2) )(ds3) := true;
			hiliteHT( rcd(s3)(1), rcd(s3)(2) )(ds3) := true;

		end if;

	end loop; --row

end if; --rmode


if cmode then

	--ColTriples:
	for col in 1..9 loop
		for row in 1..9 loop
			rcd(row):=(row,col);
		end loop; --col

		hiddenTriples(rcd, 
			t1,t2,t3, dt1,dt2,dt3,
			s1,s2,s3, ds1,ds2,ds3, found, found2);
		if found then
			hiliteHT( rcd(t1)(1), rcd(t1)(2) )(dt1) := true;
			hiliteHT( rcd(t2)(1), rcd(t2)(2) )(dt1) := true;
			hiliteHT( rcd(t3)(1), rcd(t3)(2) )(dt1) := true;

			hiliteHT( rcd(t1)(1), rcd(t1)(2) )(dt2) := true;
			hiliteHT( rcd(t2)(1), rcd(t2)(2) )(dt2) := true;
			hiliteHT( rcd(t3)(1), rcd(t3)(2) )(dt2) := true;

			hiliteHT( rcd(t1)(1), rcd(t1)(2) )(dt3) := true;
			hiliteHT( rcd(t2)(1), rcd(t2)(2) )(dt3) := true;
			hiliteHT( rcd(t3)(1), rcd(t3)(2) )(dt3) := true;

		end if;
		if found2 then
			hiliteHT( rcd(s1)(1), rcd(s1)(2) )(ds1) := true;
			hiliteHT( rcd(s2)(1), rcd(s2)(2) )(ds1) := true;
			hiliteHT( rcd(s3)(1), rcd(s3)(2) )(ds1) := true;

			hiliteHT( rcd(s1)(1), rcd(s1)(2) )(ds2) := true;
			hiliteHT( rcd(s2)(1), rcd(s2)(2) )(ds2) := true;
			hiliteHT( rcd(s3)(1), rcd(s3)(2) )(ds2) := true;

			hiliteHT( rcd(s1)(1), rcd(s1)(2) )(ds3) := true;
			hiliteHT( rcd(s2)(1), rcd(s2)(2) )(ds3) := true;
			hiliteHT( rcd(s3)(1), rcd(s3)(2) )(ds3) := true;

		end if;

	end loop; --col

end if; --cmode


if bmode then

	--BlockTriples:
	for blkrow in 0..2 loop
	for blkcol in 0..2 loop

		k:=0;
		for r in 0..2 loop
		for c in 0..2 loop
			k:=k+1;
			row:=blkrow*3+r+1;
			col:=blkcol*3+c+1;
			rcd(k):=(row,col);
		end loop; --c
		end loop; --r

		hiddenTriples(rcd, 
			t1,t2,t3, dt1,dt2,dt3,
			s1,s2,s3, ds1,ds2,ds3, found, found2);
		if found then
			hiliteHT( rcd(t1)(1), rcd(t1)(2) )(dt1) := true;
			hiliteHT( rcd(t2)(1), rcd(t2)(2) )(dt1) := true;
			hiliteHT( rcd(t3)(1), rcd(t3)(2) )(dt1) := true;

			hiliteHT( rcd(t1)(1), rcd(t1)(2) )(dt2) := true;
			hiliteHT( rcd(t2)(1), rcd(t2)(2) )(dt2) := true;
			hiliteHT( rcd(t3)(1), rcd(t3)(2) )(dt2) := true;

			hiliteHT( rcd(t1)(1), rcd(t1)(2) )(dt3) := true;
			hiliteHT( rcd(t2)(1), rcd(t2)(2) )(dt3) := true;
			hiliteHT( rcd(t3)(1), rcd(t3)(2) )(dt3) := true;

		end if;
		if found2 then
			hiliteHT( rcd(s1)(1), rcd(s1)(2) )(ds1) := true;
			hiliteHT( rcd(s2)(1), rcd(s2)(2) )(ds1) := true;
			hiliteHT( rcd(s3)(1), rcd(s3)(2) )(ds1) := true;

			hiliteHT( rcd(s1)(1), rcd(s1)(2) )(ds2) := true;
			hiliteHT( rcd(s2)(1), rcd(s2)(2) )(ds2) := true;
			hiliteHT( rcd(s3)(1), rcd(s3)(2) )(ds2) := true;

			hiliteHT( rcd(s1)(1), rcd(s1)(2) )(ds3) := true;
			hiliteHT( rcd(s2)(1), rcd(s2)(2) )(ds3) := true;
			hiliteHT( rcd(s3)(1), rcd(s3)(2) )(ds3) := true;

		end if;

	end loop; --blkcol
	end loop; --blkrow

end if; --bmode



	--ID removable cellmates of hidden triples
	hiliteHTrem := (others=>(others=>(others=>false)));
	for r in 1..9 loop
	for c in 1..9 loop
	for d in 1..9 loop
	if hiliteHT(r,c)(d) then
		for o in 1..9 loop
		if not hiliteHT(r,c)(o) and candidate(r,c)(o) then
			hiliteHTrem(r,c)(o):=true;
		end if;
		end loop; --o
	end if;
	end loop;
	end loop; --c
	end loop; --r


end setHtriples;


-- this prepares both hidden and naked quads:
procedure setQuads is
	rcd: cellseq;
	t1,t2,t3,t4, dt1,dt2,dt3,dt4: coorng;
	found: boolean;
	k,row,col: integer;
	d1,d2,d3,d4: i9;

	--flag for naked block-quads:
	showbox : boolean := true; --adds clutter!

begin


	hiliteHQ := (others=>(others=>(others=>false)));
	hiliteNQ := (others=>(others=>false));
	hiliteNQrem := (others=>(others=>(others=>false)));



	--RowQuads:
	for row in 1..9 loop

		for col in 1..9 loop
			rcd(col):=(row,col);
		end loop; --col


		hiddenQuads(rcd, t1,t2,t3,t4, dt1,dt2,dt3,dt4, found);

		if found and rmode then
			hiliteHQ( rcd(t1)(1), rcd(t1)(2) )(dt1) := true;
			hiliteHQ( rcd(t2)(1), rcd(t2)(2) )(dt1) := true;
			hiliteHQ( rcd(t3)(1), rcd(t3)(2) )(dt1) := true;
			hiliteHQ( rcd(t4)(1), rcd(t4)(2) )(dt1) := true;

			hiliteHQ( rcd(t1)(1), rcd(t1)(2) )(dt2) := true;
			hiliteHQ( rcd(t2)(1), rcd(t2)(2) )(dt2) := true;
			hiliteHQ( rcd(t3)(1), rcd(t3)(2) )(dt2) := true;
			hiliteHQ( rcd(t4)(1), rcd(t4)(2) )(dt2) := true;

			hiliteHQ( rcd(t1)(1), rcd(t1)(2) )(dt3) := true;
			hiliteHQ( rcd(t2)(1), rcd(t2)(2) )(dt3) := true;
			hiliteHQ( rcd(t3)(1), rcd(t3)(2) )(dt3) := true;
			hiliteHQ( rcd(t4)(1), rcd(t4)(2) )(dt3) := true;

			hiliteHQ( rcd(t1)(1), rcd(t1)(2) )(dt4) := true;
			hiliteHQ( rcd(t2)(1), rcd(t2)(2) )(dt4) := true;
			hiliteHQ( rcd(t3)(1), rcd(t3)(2) )(dt4) := true;
			hiliteHQ( rcd(t4)(1), rcd(t4)(2) )(dt4) := true;

		end if;


		nakedQuads(rcd, t1,t2,t3,t4, d1,d2,d3,d4, found);
		if found then
			hiliteNQ( rcd(t1)(1), rcd(t1)(2) ) := true;
			hiliteNQ( rcd(t2)(1), rcd(t2)(2) ) := true;
			hiliteNQ( rcd(t3)(1), rcd(t3)(2) ) := true;
			hiliteNQ( rcd(t4)(1), rcd(t4)(2) ) := true;

			--now ID like digits in OTHER cells of the house:
			for col in 1..9 loop
			if col/=rcd(t1)(2) and col/=rcd(t2)(2) and col/=rcd(t3)(2) and col/=rcd(t4)(2) then
				if candidate(row,col)(d1) then
					hiliteNQrem(row,col)(d1):=true;
				end if;
				if candidate(row,col)(d2) then
					hiliteNQrem(row,col)(d2):=true;
				end if;
				if candidate(row,col)(d3) then
					hiliteNQrem(row,col)(d3):=true;
				end if;
				if candidate(row,col)(d4) then
					hiliteNQrem(row,col)(d4):=true;
				end if;
			end if;
			end loop;

		end if;


	end loop; --row



	--ColQuads:
	for col in 1..9 loop

		for row in 1..9 loop
			rcd(row):=(row,col);
		end loop; --col

		hiddenQuads(rcd, t1,t2,t3,t4, dt1,dt2,dt3,dt4, found);
		if found and cmode then
			hiliteHQ( rcd(t1)(1), rcd(t1)(2) )(dt1) := true;
			hiliteHQ( rcd(t2)(1), rcd(t2)(2) )(dt1) := true;
			hiliteHQ( rcd(t3)(1), rcd(t3)(2) )(dt1) := true;
			hiliteHQ( rcd(t4)(1), rcd(t4)(2) )(dt1) := true;

			hiliteHQ( rcd(t1)(1), rcd(t1)(2) )(dt2) := true;
			hiliteHQ( rcd(t2)(1), rcd(t2)(2) )(dt2) := true;
			hiliteHQ( rcd(t3)(1), rcd(t3)(2) )(dt2) := true;
			hiliteHQ( rcd(t4)(1), rcd(t4)(2) )(dt2) := true;

			hiliteHQ( rcd(t1)(1), rcd(t1)(2) )(dt3) := true;
			hiliteHQ( rcd(t2)(1), rcd(t2)(2) )(dt3) := true;
			hiliteHQ( rcd(t3)(1), rcd(t3)(2) )(dt3) := true;
			hiliteHQ( rcd(t4)(1), rcd(t4)(2) )(dt3) := true;

			hiliteHQ( rcd(t1)(1), rcd(t1)(2) )(dt4) := true;
			hiliteHQ( rcd(t2)(1), rcd(t2)(2) )(dt4) := true;
			hiliteHQ( rcd(t3)(1), rcd(t3)(2) )(dt4) := true;
			hiliteHQ( rcd(t4)(1), rcd(t4)(2) )(dt4) := true;

		end if;

		nakedQuads(rcd, t1,t2,t3,t4, d1,d2,d3,d4, found);
		if found then
			hiliteNQ( rcd(t1)(1), rcd(t1)(2) ) := true;
			hiliteNQ( rcd(t2)(1), rcd(t2)(2) ) := true;
			hiliteNQ( rcd(t3)(1), rcd(t3)(2) ) := true;
			hiliteNQ( rcd(t4)(1), rcd(t4)(2) ) := true;

			--now ID like digits in OTHER cells of the house:
			for row in 1..9 loop
			if row/=rcd(t1)(1) and row/=rcd(t2)(1) and row/=rcd(t3)(1) and row/=rcd(t4)(1) then
				if candidate(row,col)(d1) then
					hiliteNQrem(row,col)(d1):=true;
				end if;
				if candidate(row,col)(d2) then
					hiliteNQrem(row,col)(d2):=true;
				end if;
				if candidate(row,col)(d3) then
					hiliteNQrem(row,col)(d3):=true;
				end if;
				if candidate(row,col)(d4) then
					hiliteNQrem(row,col)(d4):=true;
				end if;
			end if;
			end loop;

		end if;

	end loop; --col



	--BlockQuads:
	for blkrow in 0..2 loop
	for blkcol in 0..2 loop

		k:=0;
		for r in 0..2 loop
		for c in 0..2 loop
			k:=k+1;
			row:=blkrow*3+r+1;
			col:=blkcol*3+c+1;
			rcd(k):=(row,col);
		end loop; --c
		end loop; --r

		hiddenQuads(rcd, t1,t2,t3,t4, dt1,dt2,dt3,dt4, found);
		if found and bmode then --Hidden Quads
			hiliteHQ( rcd(t1)(1), rcd(t1)(2) )(dt1) := true;
			hiliteHQ( rcd(t2)(1), rcd(t2)(2) )(dt1) := true;
			hiliteHQ( rcd(t3)(1), rcd(t3)(2) )(dt1) := true;
			hiliteHQ( rcd(t4)(1), rcd(t4)(2) )(dt1) := true;

			hiliteHQ( rcd(t1)(1), rcd(t1)(2) )(dt2) := true;
			hiliteHQ( rcd(t2)(1), rcd(t2)(2) )(dt2) := true;
			hiliteHQ( rcd(t3)(1), rcd(t3)(2) )(dt2) := true;
			hiliteHQ( rcd(t4)(1), rcd(t4)(2) )(dt2) := true;

			hiliteHQ( rcd(t1)(1), rcd(t1)(2) )(dt3) := true;
			hiliteHQ( rcd(t2)(1), rcd(t2)(2) )(dt3) := true;
			hiliteHQ( rcd(t3)(1), rcd(t3)(2) )(dt3) := true;
			hiliteHQ( rcd(t4)(1), rcd(t4)(2) )(dt3) := true;

			hiliteHQ( rcd(t1)(1), rcd(t1)(2) )(dt4) := true;
			hiliteHQ( rcd(t2)(1), rcd(t2)(2) )(dt4) := true;
			hiliteHQ( rcd(t3)(1), rcd(t3)(2) )(dt4) := true;
			hiliteHQ( rcd(t4)(1), rcd(t4)(2) )(dt4) := true;

		end if;



if showbox then

-- Attenion: this may cause unnecessary clutter...
-- naked quads in boxes is seldom useful!

		nakedQuads(rcd, t1,t2,t3,t4, d1,d2,d3,d4, found);
		if found then --naked Quads
			hiliteNQ( rcd(t1)(1), rcd(t1)(2) ) := true;
			hiliteNQ( rcd(t2)(1), rcd(t2)(2) ) := true;
			hiliteNQ( rcd(t3)(1), rcd(t3)(2) ) := true;
			hiliteNQ( rcd(t4)(1), rcd(t4)(2) ) := true;

			--now ID like digits in OTHER cells of the house:
			for r in 0..2 loop
			for c in 0..2 loop
			row:=blkrow*3+r+1;
			col:=blkcol*3+c+1;
			if 
				(row/=rcd(t1)(1) or col/=rcd(t1)(2))
				and
				(row/=rcd(t2)(1) or col/=rcd(t2)(2))
				and
				(row/=rcd(t3)(1) or col/=rcd(t3)(2))
				and
				(row/=rcd(t4)(1) or col/=rcd(t4)(2))
			then
				if candidate(row,col)(d1) then
					hiliteNQrem(row,col)(d1):=true;
				end if;
				if candidate(row,col)(d2) then
					hiliteNQrem(row,col)(d2):=true;
				end if;
				if candidate(row,col)(d3) then
					hiliteNQrem(row,col)(d3):=true;
				end if;
				if candidate(row,col)(d4) then
					hiliteNQrem(row,col)(d4):=true;
				end if;
			end if;
			end loop;
			end loop;

		end if; --found

end if; --showbox


	end loop; --blkcol
	end loop; --blkrow




	--ID removable cellmates of hidden quads
	hiliteHQrem := (others=>(others=>(others=>false)));
	for r in 1..9 loop
	for c in 1..9 loop
	for d in 1..9 loop
	if hiliteHQ(r,c)(d) then
		for o in 1..9 loop
		if not hiliteHQ(r,c)(o) and candidate(r,c)(o) then
			hiliteHQrem(r,c)(o):=true;
		end if;
		end loop; --o
	end if;
	end loop;
	end loop; --c
	end loop; --r


end setQuads;







procedure flushBlock(rr,cc:i9) is
	mm,br0,bc0,r0,c0: s9;
begin

mm:=m9(rr,cc);
if mm>0 then

	br0:= (rr-1)/3; --0..2
	bc0:= (cc-1)/3; --0..2
	r0 := br0*3; --0..6
	c0 := bc0*3; --0..6

	for r in r0+1..r0+3 loop
	for c in c0+1..c0+3 loop
	if r/=rr or c/=cc then

--tedious, but easily followed:
if showK and candidate(r,c)(mm) then
	append(consoleBuf," -");
	append(consoleBuf,i2st(mm));
	append(consoleBuf,"@(");
	append(consoleBuf,i2st(r));
	append(consoleBuf,",");
	append(consoleBuf,i2st(c));
	append(consoleBuf,")");
	hiliteKdel(r,c)(mm):=true;
end if;

		candidate(r,c)(mm):=false;
		mandidate(r,c)(mm):=false;
	end if;
	end loop; --c
	end loop; --r

end if;

end flushBlock;


procedure flushRow(rr,cc:i9) is
	mm: s9;
begin

mm:=m9(rr,cc);
if mm>0 then

	for c in i9 loop
		if c/=cc then

--tedious, but easily followed:
if showK and candidate(rr,c)(mm) then
	append(consoleBuf," -");
	append(consoleBuf,i2st(mm));
	append(consoleBuf,"@(");
	append(consoleBuf,i2st(rr));
	append(consoleBuf,",");
	append(consoleBuf,i2st(c));
	append(consoleBuf,")");
	hiliteKdel(rr,c)(mm):=true;
end if;

			candidate(rr,c)(mm):=false;
			mandidate(rr,c)(mm):=false;
		end if;
	end loop;

end if;

end flushRow;


procedure flushCol(rr,cc:i9) is
	mm: s9;
begin

mm:=m9(rr,cc);
if mm>0 then

	for r in i9 loop
		if r/=rr then

--tedious, but easily followed:
if showK and candidate(r,cc)(mm) then
	append(consoleBuf," -");
	append(consoleBuf,i2st(mm));
	append(consoleBuf,"@(");
	append(consoleBuf,i2st(r));
	append(consoleBuf,",");
	append(consoleBuf,i2st(cc));
	append(consoleBuf,")");
	hiliteKdel(r,cc)(mm):=true;
end if;

			candidate(r,cc)(mm):=false;
			mandidate(r,cc)(mm):=false;
		end if;
	end loop;

end if;

end flushCol;



-- the intent here is to pick a cell
-- with a single digit showing,
-- then eliminate dups in that row, col, block.
procedure flushDups(r,c: i9) is
	ii,k: integer := 0;
	autopromote: constant boolean := true;
begin

	if autopromote and not manualmode then -- not official until m9 is set:

		if m9(r,c)=0 then
			k:=0;
			for dig in 1..9 loop
			if candidate(r,c)(dig) then k:=k+1; ii:=dig; end if;
			end loop;
			if k=1 then -- ii is only candidate
				m9(r,c):=ii;
			end if;
		end if;

	end if;

	if m9(r,c)>0 then
		flushBlock(r,c);
		flushRow(r,c);
		flushCol(r,c);
	end if;


end flushDups;

procedure flush is
begin
	for row in 1..9 loop
	for col in 1..9 loop
		flushDups(row,col);
	end loop; --col
	end loop; --row
end flush;




procedure findUniqueCol( changed: out boolean ) is
	type sumtype is array(i9) of s9;
	sum: integer;
	rr: s9;
begin
changed:=false;
for cc in i9 loop -- for each column...
	for dig in i9 loop -- for each digit...

		-- see if digit occurs only once in this column:

		sum:=0;
		for r in i9 loop
		if 
			m9(r,cc)=0 --not yet processed as singleton
			and 
			candidate(r,cc)(dig) 
		then
			sum:=sum+1;
			rr:=r;
		end if;
		end loop;

		if sum=1 then -- found a unique dig in col cc at row rr
			changed:=true;
			for j in i9 loop -- so eliminate all other candidates in same cell
			if j/=dig then
				candidate(rr,cc)(j):=false;
			end if;
			end loop; --j
			m9(rr,cc):=dig; --define the singleton

-- somewhat helpful:
if showK then
	append(consoleBuf, crlf);
	append(consoleBuf," +");
	append(consoleBuf,i2st(dig));
	append(consoleBuf,"@(");
	append(consoleBuf,i2st(rr));
	append(consoleBuf,",");
	append(consoleBuf,i2st(cc));
	append(consoleBuf,"):");
end if;

			flushDups(rr,cc); --eliminate dig from 3 houses
		end if;

	end loop; --dig

end loop; --cc

end findUniqueCol;


procedure findUniqueRow( changed: out boolean )  is
	type sumtype is array(i9) of s9;
	sum: integer;
	cc: s9;
begin
changed:=false;
for rr in i9 loop
	for dig in i9 loop

		-- see if dig occurs only once in this row:

		sum:=0;
		for c in i9 loop
		if 
			m9(rr,c)=0 --not yet processed as singleton
			and 
			candidate(rr,c)(dig) 
		then
			sum:=sum+1;
			cc:=c;
		end if;
		end loop; --c
		if sum=1 then -- found a unique dig in row rr
			changed:=true;
			for j in i9 loop -- so eliminate all other candidates in same cell
			if j/=dig then
				candidate(rr,cc)(j):=false;
			end if;
			end loop; --j
			m9(rr,cc):=dig; --define the singleton

-- somewhat helpful:
if showK then
	append(consoleBuf, crlf);
	append(consoleBuf," +");
	append(consoleBuf,i2st(dig));
	append(consoleBuf,"@(");
	append(consoleBuf,i2st(rr));
	append(consoleBuf,",");
	append(consoleBuf,i2st(cc));
	append(consoleBuf,"):");
end if;

			flushDups(rr,cc); --eliminate this dig from 3 houses
		end if;

	end loop; --dig
end loop; --rr
end findUniqueRow;



procedure findUniqueBlock( changed: out boolean )  is
	type sumtype is array(i9) of s9;
	sum: integer;
	rr,cc, row,col: s9;
begin
changed:=false;
for br in 0..2 loop
for bc in 0..2 loop -- for each block (1 of 9)

	for dig in i9 loop -- for each possible digit 1..9

		-- see if dig occurs only once in this box:

		sum:=0;
		for r in 0..2 loop
		for c in 0..2 loop -- for each cell in block (1 of 9)
			row:=br*3+r+1;
			col:=bc*3+c+1;
			if 
				m9(row,col)=0 -- not yet processed as singleton
				and
				candidate(row,col)(dig)
			then
				sum:=sum+1;
				rr:=row; cc:=col;
			end if;
		end loop; --c
		end loop; --r

		if sum=1 then -- found a unique dig in this box
			changed:=true;
		-- found the only cell in the block that contains digit dig
		-- ...so eliminate other candidates in this cell:
			for j in i9 loop
			if j/=dig then
				candidate(rr,cc)(j):=false;
			end if;
			end loop; --j
			m9(rr,cc):=dig; -- define the singleton

-- somewhat helpful:
if showK then
	append(consoleBuf, crlf);
	append(consoleBuf," +");
	append(consoleBuf,i2st(dig));
	append(consoleBuf,"@(");
	append(consoleBuf,i2st(rr));
	append(consoleBuf,",");
	append(consoleBuf,i2st(cc));
	append(consoleBuf,"):");
end if;

			flushDups(rr,cc); -- eliminate this digit from its 3 houses
		end if;

	end loop; --dig

end loop; --bc
end loop; --br

end findUniqueBlock;




procedure findUnique( changed: out boolean ) is
	chR,chC,chX: boolean;
begin

	flush; --14aug23 addendum...
	--this will autopromote/flush any single candidates

	findUniqueRow(chR);
	findUniqueCol(chC);
	findUniqueBlock(chX);
	changed := chR or chC or chX;
end findUnique;






--forward declarations:
procedure fullsavepuzzle( usetemp: boolean := false; id: s9 := 0 );
function fullreadpuzzle( usetemp: boolean := false; id: s9 := 0  ) return boolean;
-- now sets fnamUstr





puztested: boolean := false;


badig: s9; --output from kram
type badcelltype is array(1..18) of ocoords;
badcells: badcelltype;
nbad: integer;




-- eXperimental Limited version of kram:
procedure zram( c0: in coords; 
	bad: out s9; badsell: out badcelltype; numbad: out integer
	) is separate;





procedure kram( c0: in coords; 
	bad: out s9; badsell: out badcelltype; numbad: out integer;
	forceoutput: in boolean := false
	) is separate;




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



	package fmath is new
			Ada.Numerics.generic_elementary_functions( float );
	use fmath;


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

	type vec3 is array(1..3) of float;


	onepi : constant float     := 3.14159_26535_89793;
	halfpi : constant float    := onepi/2.0;
	fourthpi : constant float  := onepi/4.0;
	twopi : constant float     := onepi*2.0;
	deg2rad : constant float   := onepi/180.0;
	rad2deg : constant float   := 180.0/onepi;

	userexit, help: boolean := false;

	--fanfare : glint;

	MVP, ModelMatrix, ViewMatrix, ProjectionMatrix
			: mat44 := identity;










procedure InitGlfw( wid, hit, fwd,fht : in out glint; name: string ) is

	use system;

	title : interfaces.c.strings.chars_ptr := new_string(name&ascii.nul);

	maj,min,rev : aliased glint;

	awidth:  aliased glint := wid;
	aheight: aliased glint := hit;

	azero : aliased glint := 0;

	axs, ays : aliased float;
	awwid,awhit, afwid, afhit : aliased glint;


begin

	--put_line("...using fastrgv's Ada Binding to GLFW3...");

	GlfwGetVersion(maj'access,min'access,rev'access); --naturals
	--put("GLFW ver: ");
	--put(glint'image(maj));
	--put(":"&glint'image(min));
	--put(":"&glint'image(rev));
	--New_Line;



	if GlfwInit /= gl_true then
		new_line;
		put_line("glfwInit failed");
		raise program_error;
	end if;

	-- use version here that your graphics card would support:
	GlfwWindowHint( glfw_context_version_major, 3);
	GlfwWindowHint( glfw_context_version_minor, 3);
	GlfwWindowHint( glfw_opengl_forward_compat, gl_true);
	GlfwWindowHint( glfw_opengl_profile, glfw_opengl_core_profile);

	GlfwWindowHint( glfw_samples, 4);
	GlfwWindowHint( glfw_client_api, glfw_opengl_api);



	declare
		vmode: access constant glfwVidMode 
			:= glfwGetVideoMode(glfwGetPrimaryMonitor);
	begin

		--get current video mode size [full screen]
		mwid:=vmode.width;
		mhit:=vmode.height;

	end;



	mainWindow := glfwcreatewindow(
		wid, hit,	title, null, null );


		

	if mainWindow = null then
		new_line;
		put_line("glfwCreateWindow failed");
		raise program_error;
	end if;

	glfwmakecontextcurrent( mainWindow );


--HiDpi queries:
	glfwGetWindowSize(mainWindow, awwid'access, awhit'access);
	glfwGetFramebufferSize(mainWindow, afwid'access,afhit'access);
	glfwGetWindowContentScale(mainWindow, axs'access,ays'access);

	--put_line("HighDpi Queries:");
	--put_line("WindowSize: "&glint'image(awwid)&","&glint'image(awhit));
	--put_line("FrameBuffer: "&glint'image(afwid)&","&glint'image(afhit));
	--put_line("Scale: "&float'image(axs)&","&float'image(ays));

	fwd:=afwid;
	fht:=afhit;
	wid:=awwid;
	hit:=awhit;


end InitGlfw;












procedure updateMVP is -- only call once unless change in aspect ratio

	xlook, ylook, zlook, xlk,ylk,zlk, xrt,yrt,zrt, xup,yup,zup : float;
	xme,yme,zme : float;

	fovdeg : constant float := 45.0;
	fovrad : constant float := fovdeg*deg2rad;


	-- distance from eye so FOV encompasses proper field:
	eyeradius : constant float := 1.0 / fmath.tan(fovrad/2.0);

	horiAng : constant float := 0.0;
	near : constant float := 0.1;
	far  : constant float := 100.0;

	focus : constant vec3 := (0.0, -1.0, 0.0);
	eyepos: constant vec3 := (0.0, eyeradius-1.0 , 0.0);
	look  : constant vec3 := 
		( focus(1)-eyepos(1), focus(2)-eyepos(2), focus(3)-eyepos(3) );
	vertAng : constant float := fmath.arctan( look(2), look(3) );

begin

	ModelMatrix:=identity;

	xme:=eyepos(1);
	yme:=eyepos(2);
	zme:=eyepos(3);

	-- look direction:
	xlook := fmath.cos(vertang)*fmath.sin(horiang);
	ylook := fmath.sin(vertang);
	zlook := fmath.cos(vertang)*fmath.cos(horiang);

	xlk := xme+xlook;
	ylk := yme+ylook;
	zlk := zme+zlook;

	-- Right unit-Direction
	xrt:= fmath.sin(horiang-halfpi);
	yrt:= 0.0;
	zrt:= fmath.cos(horiang-halfpi);

	-- calculate UP unit-Direction
	cross( xrt,yrt,zrt, xlook,ylook,zlook, xup,yup,zup );

	perspective(ProjectionMatrix, fovdeg, 1.0,  near, far);

	lookat(ViewMatrix, xme,yme,zme, xlk,ylk,zlk, xup,yup,zup );

	MVP:=ModelMatrix;
	matXmat(MVP,ViewMatrix);
	matXmat(MVP,ProjectionMatrix);

end updateMVP;






fnamUstr: unbounded_string;


xize : integer := 80;


procedure restart( resize: boolean := true ) is
	tstr: string := to_string( fnamUstr );
	cptr : chars_ptr := 
	  new_string("SudokuTool:  |"&tstr
	  		&"|   <h>:Help   <esc>:Quit   <f>:Flush   <.>:Unique");

	margin: constant glint := 200;
begin

	glfwsetwindowtitle(mainwindow, cptr);

	Wwid:=glint(xize*ncols);
	Whit:=glint(xize*nrows);


	if resize  then

		--put_line("new wid X hit X xize:");
		--put(glint'image(wwid));
		--put(" X");
		--put(glint'image(whit));
		--	put(" X");
		--	put(glint'image( glint(xize) ));
		--new_line;

		if Wwid>Mwid-margin or Whit>Mhit-margin then

			while Wwid>Mwid-margin or Whit>Mhit-margin loop
				xize:=xize-10;
				--put_line("reducing xize");
				Wwid:=glint(xize*ncols);
				Whit:=glint(xize*nrows);
			end loop;

			--put_line(" resizing xize="&integer'image(xize));

			--put_line("new wid X hit X xize:");
			--put(glint'image(wwid));
			--put(" X");
			--put(glint'image(whit));
			--new_line;

		end if;

	end if; --resize


	--28may19
	Wwid:=glint(xize*ncols);
	Whit:=glint(xize*nrows);
	glfwSetWindowSize(mainWindow,Wwid,Whit);
	glfwGetFramebufferSize(mainwindow, fwid'access, fhit'access);

	glViewport(0,0,Fwid,Fhit);


end restart;








procedure release_textures is -- prepare to close down
begin

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

	gldeletetextures(1, ol1_texid'address);
	gldeletetextures(1, ol2_texid'address);
	gldeletetextures(1, ol3_texid'address);
	gldeletetextures(1, ol4_texid'address);

	gldeletetextures(1, ol5_texid'address);
	gldeletetextures(1, ol6_texid'address);
	gldeletetextures(1, ol7_texid'address);
	gldeletetextures(1, ol8_texid'address);
	gldeletetextures(1, ol9_texid'address);


	gldeletetextures(1, floor_texid'address);
	gldeletetextures(1, space_texid'address);
	gldeletetextures(1, box_texid'address);

	gldeletetextures(1, gray_texid'address);
	gldeletetextures(1, black_texid'address);
	gldeletetextures(1, red_texid'address);
	gldeletetextures(1, blu_texid'address);
	gldeletetextures(1, pink_texid'address);

	glext.binding.glDeleteProgram( picttexshadid );

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

end release_textures;



procedure setSkin( cleanup: boolean := false ) is
begin

	gray_texid:= loadPng(mirror,"skins/gray.png");

	floor_texid:=loadPng(mirror,"skins/hatch.png"); --white/gray (was hatch0b2.png)

	ol1_texid:=loadPng(mirror,"skins/set1.png"); --pink/green overlay1
	ol2_texid:=loadPng(mirror,"skins/set2.png"); --pink/green overlay2
--note: apparently my graphics displays inverted images
	ol3_texid:=loadPng(mirror,"skins/set3.png"); --pink/green overlay3
	ol4_texid:=loadPng(mirror,"skins/set4.png"); --pink/green overlay4

	ol5_texid:=loadPng(mirror,"skins/set5.png"); --pink/green overlay5
	ol6_texid:=loadPng(mirror,"skins/set6.png"); --pink/green overlay6
--note: apparently my graphics displays inverted images
	ol7_texid:=loadPng(mirror,"skins/set7.png"); --pink/green overlay7
	ol8_texid:=loadPng(mirror,"skins/set8.png"); --pink/green overlay8
	ol9_texid:=loadPng(mirror,"skins/set9.png"); --pink/green overlay9

	space_texid:=loadPng(mirror,"skins/blank.png");
	black_texid:=loadPng(mirror,"skins/black.png");
	box_texid:=loadPng(mirror,"skins/box2.png");
	red_texid:=loadPng(mirror,"skins/red.png");
	blu_texid:=loadPng(mirror,"skins/blu.png");
	pink_texid:=loadPng(mirror,"skins/pink.png");

end setSkin;


procedure setup_textures is  -- prepare dungeon textures
begin 

	picttexshadid := loadshaders("./data/texobj.vs", "./data/texobj.fs");
	matrixid := glgetuniformlocation(picttexshadid, pmvp);
	uniftex  := glgetuniformlocation(picttexshadid, pmyts);

	setSkin;

end setup_textures;









procedure first_prep is -- main program setup
      FileId : text_io.File_Type;
begin



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

	Wwid:=500;
	Whit:=500;
	--put_line("setting 500 x 500");

	InitGlfw(Wwid, Whit, Fwid,Fhit, "AdaSokoban");



	purtex.inittext2d("data/sansp.png",integer(Wwid),integer(Whit)); --800080
	cyatex.inittext2d("data/sansc.png",integer(Wwid),integer(Whit)); --00e0e0
	grntex.inittext2d("data/sansg.png",integer(Wwid),integer(Whit));
	blutex.inittext2d("data/sansb0.png",integer(Wwid),integer(Whit));
	redtex.inittext2d("data/sansr.png",integer(Wwid),integer(Whit));
	magtex.inittext2d("data/sansm.png",integer(Wwid),integer(Whit)); --c000c0
	orntex.inittext2d("data/sanso.png",integer(Wwid),integer(Whit)); --ff6700 safety Orange
	yebtex.inittext2d("data/sansy2.png",integer(Wwid),integer(Whit));
	blktex.inittext2d("data/sansk.png",integer(Wwid),integer(Whit));
	grytex.inittext2d("data/sansgrey30.png",integer(Wwid),integer(Whit));
	--ltgtex.inittext2d("data/sansgrey60.png",integer(Wwid),integer(Whit));
	gr2tex.inittext2d("data/sansgrey60.png",integer(Wwid),integer(Whit));
	ltgtex.inittext2d("data/sansgrey100.png",integer(Wwid),integer(Whit));
	whitex.inittext2d("data/sansw.png",integer(Wwid),integer(Whit));
	--put_line( "Window: wid-X-hit :" 
	--	& interfaces.c.int'image(Wwid)&" X "
	--	& interfaces.c.int'image(Whit) );

	glViewport(0,0,Fwid,Fhit);

	--put_line( "pixels: Fwid-X-Fhit : "
	--	&interfaces.c.int'image(Fwid)&" X "
	--	& interfaces.c.int'image(Fhit) );


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

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



	--setup_textures; ...later

	glClearColor(0.4,0.4,0.4,1.0);

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


	glEnable(GL_MULTISAMPLE);
	glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
	glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);


end first_prep;








--3 utilities for next proc: --------------------------------

function nBox(row,col: in i9) return i9 is
begin
	return ((row-1)/3) * 3 + ((col-1)/3) +1;
end nBox;

function r0Box( nb: in i9 ) return s9 is
begin
	if nb in 1..3 then
		return 0;
	elsif nb in 4..6 then
		return 3;
	else
		return 6;
	end if;
end r0Box;


function c0Box( nb: in i9 ) return s9 is
begin
	if nb=1 or nb=4 or nb=7 then
		return 0;
	elsif nb=2 or nb=5 or nb=8 then
		return 3;
	else
		return 6;
	end if;
end c0Box;







-- identify isolated pairs/triples on rows/cols
-- set hiliteRC array accordingly
-- set rowPair( row#, col# ) := paired-col# (0=>none)
-- set colPair( col#, row# ) := paired-row# (0=>none)
procedure id_pairsRC is
	k : integer;
	nb1,nb2: i9;
	br0,bc0, br,bc: s9;
	row,col : array(1..2) of integer;
	rowrem, colrem : boolean := false;
begin

	rowPair  := (others=>(others=>(others=>0)));
	colPair  := (others=>(others=>(others=>0)));
	hiliteRow := (others=>(others=>(others=>false)));
	hiliteCol := (others=>(others=>(others=>false)));
	hiliteRowRem := (others=>(others=>(others=>false)));
	hiliteColRem := (others=>(others=>(others=>false)));

	--rows
	for r in 1..9 loop
	for idig in 1..9 loop
		k:=0;
		for c in 1..9 loop
			if candidate(r,c)(idig) then 
				k:=k+1;
				if k<=2 then
					row(k):=r;
					col(k):=c;
				end if;
			end if;
		end loop; --diag
		if k=2 then
			for d in 1..k loop
				hiliteRow(row(d),col(d))( idig ):=true;
			end loop; --d
			rowPair(idig,r,col(1)):=col(2);
			rowPair(idig,r,col(2)):=col(1);

			--if this pair share a box, flag any like digits within box
			-- here, row(1)=row(2)=r
			nb1:=nBox(row(1),col(1));
			nb2:=nBox(row(2),col(2));
			if nb1=nb2 then -- test for any removable digits
				br0:=r0Box(nb1);
				bc0:=c0Box(nb1);
				for rb in 0..2 loop
				for cb in 0..2 loop
					br:=br0+rb+1;
					bc:=bc0+cb+1;
					if br=r and (bc=col(1) or bc=col(2)) then
						null;
					elsif candidate(br,bc)(idig) then
						hiliteRowRem(br,bc)(idig):=true;
						rowrem:=true;
					end if;
				end loop; --cb
				end loop; --rb
			end if;

		end if;
	end loop; --idig
	end loop; --r


	--cols
	for c in 1..9 loop
	for idig in 1..9 loop
		k:=0;
		for r in 1..9 loop
			if candidate(r,c)(idig) then 
				k:=k+1;
				if k<=2 then
					row(k):=r;
					col(k):=c;
				end if;
			end if;
		end loop; --diag
		if k=2 then
			for d in 1..k loop
				hiliteCol(row(d),col(d))( idig ):=true;
			end loop; --d
			colPair(idig,c,row(1)):=row(2);
			colPair(idig,c,row(2)):=row(1);

			--if this pair share a box, flag any like digits within box
			-- here, col(1)=col(2)=c
			nb1:=nBox(row(1),col(1));
			nb2:=nBox(row(2),col(2));
			if nb1=nb2 then -- test for any removable digits
				br0:=r0Box(nb1);
				bc0:=c0Box(nb1);
				for rb in 0..2 loop
				for cb in 0..2 loop
					br:=br0+rb+1;
					bc:=bc0+cb+1;
					if bc=c and (br=row(1) or br=row(2)) then
						null;
					elsif candidate(br,bc)(idig) then
						hiliteColRem(br,bc)(idig):=true;
						colrem:=true;
					end if;
				end loop; --cb
				end loop; --rb
			end if;


		end if;
	end loop; --idig
	end loop; --c

end id_pairsRC;

















-- identify isolated pairs within blocks;
-- set hiliteBP array accordingly.
-- set BoxPair( box#, cell# ) := paired-cell# (0=>none)

--BoxPair : array(i9,i9) of s9;

procedure id_pairsBP is 
	tot: integer;

	r1,c1, r2,c2, r3,c3,
	boxnum, cell1, cell2: i9;
	--rr, cc : array(0..1) of integer;
	rr, cc : array(0..2) of integer;
begin

	boxrem:=false;

	BoxPair  := (others=>(others=>(others=>0)));
	hiliteBP := (others=>(others=>(others=>false)));
	hiliteBPna := (others=>(others=>(others=>false)));
	hiliteBoxRem := (others=>(others=>(others=>false)));



	for brow in 0..2 loop
	for bcol in 0..2 loop
	boxnum:=brow*3+bcol+1;
	--process each of 9 blocks:

	for idig in 1..9 loop
	--check idig

		tot:=0;
		for r in 0..2 loop
		for c in 0..2 loop
		--cellnum:=r*3+c+1;
			if candidate( brow*3+r+1, bcol*3+c+1 )( idig ) then
				if tot<=2 then
					rr(tot):=r; cc(tot):=c;
				end if;
				tot:=tot+1;
			end if;
		end loop;
		end loop;

		--if tot=2 then --allows non-aligned-pairs
		if tot=2 and ( rr(0)=rr(1) or cc(0)=cc(1) ) then --only aligned pairs

			cell1 := rr(0)*3+cc(0)+1;
			cell2 := rr(1)*3+cc(1)+1;
			BoxPair(idig,boxnum,cell1):=cell2;
			BoxPair(idig,boxnum,cell2):=cell1;

			r1:=brow*3+rr(0)+1; c1:=bcol*3+cc(0)+1;
			r2:=brow*3+rr(1)+1; c2:=bcol*3+cc(1)+1;

			hiliteBP(r1,c1)(idig):=true;
			hiliteBP(r2,c2)(idig):=true;

			--flag any removables aligned with this pointing-pair
			if r1=r2 then --check all cols this row
				for co in 1..9 loop
					if co=c1 or co=c2 then
						null;
					elsif candidate(r1,co)(idig) then
						hiliteBoxRem(r1,co)(idig):=true;
						boxrem:=true;
					end if;
				end loop;

			elsif c1=c2 then --check all rows this col
				for rw in 1..9 loop
					if rw=r1 or rw=r2 then
						null;
					elsif candidate(rw,c1)(idig) then
						hiliteBoxRem(rw,c1)(idig):=true;
						boxrem:=true;
					end if;
				end loop;
			else
				raise program_error;
			end if;


		elsif tot=2 then --only NonAligned Pairs

			hiliteBPna(brow*3+rr(0)+1, bcol*3+cc(0)+1)(idig):=true;
			hiliteBPna(brow*3+rr(1)+1, bcol*3+cc(1)+1)(idig):=true;


-- addendum to capture aligned digit triples 25jul23:

		elsif tot=3 and ( ( rr(0)=rr(1) and rr(0)=rr(2) ) or ( cc(0)=cc(1) and cc(0)=cc(2) ) ) then

			r1:=brow*3+rr(0)+1; c1:=bcol*3+cc(0)+1;
			r2:=brow*3+rr(1)+1; c2:=bcol*3+cc(1)+1;
			r3:=brow*3+rr(2)+1; c3:=bcol*3+cc(2)+1;

			hiliteBP(r1,c1)(idig):=true;
			hiliteBP(r2,c2)(idig):=true;
			hiliteBP(r3,c3)(idig):=true;

			--flag any removables aligned with this pointing-triple
			if r1=r2 then --check all cols this row
				for co in 1..9 loop
					if co=c1 or co=c2 or co=c3 then
						null;
					elsif candidate(r1,co)(idig) then
						hiliteBoxRem(r1,co)(idig):=true;
						boxrem:=true;
					end if;
				end loop;

			elsif c1=c2 then --check all rows this col
				for rw in 1..9 loop
					if rw=r1 or rw=r2 or rw=r3 then
						null;
					elsif candidate(rw,c1)(idig) then
						hiliteBoxRem(rw,c1)(idig):=true;
						boxrem:=true;
					end if;
				end loop;
			else
				raise program_error;
			end if;


		end if;

	end loop; --idig

	end loop; --bcol
	end loop; --brow

end id_pairsBP;


-- intent is to identify digits that only appear once in a 3x3 block
procedure id_1 is 
	tot: integer;
	rr, cc, row,col :integer;
begin

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

	for brow in 0..2 loop
	for bcol in 0..2 loop
	--process each of 9 blocks:

		for idig in 1..9 loop

			tot:=0;
			for r in 0..2 loop
			for c in 0..2 loop
				row:=brow*3+r+1;
				col:=bcol*3+c+1;
				if candidate(row,col)( idig ) and m9(row,col)=0 then
					rr:=r; cc:=c;
					tot:=tot+1;
				end if;
			end loop;
			end loop;
			if tot=1 then 
				hilite1(brow*3+rr+1, bcol*3+cc+1)(idig):=true;
			end if;

		end loop; --idig

	end loop; --bcol
	end loop; --brow

end id_1;

procedure id_3 is --ID digits unique in one of its houses
	tot: integer;
	rr, cc :integer;
begin

	hilite3 := hilite1; --must call id_1 first!

	for r in 1..9 loop
		for idig in 1..9 loop
			tot:=0;
			for c in 1..9 loop
				if candidate(r,c)(idig) and m9(r,c)=0 then
					rr:=r; cc:=c; tot:=tot+1;
				end if;
			end loop; --c
			if tot=1 then -- unique to this row
				hilite3(rr,cc)(idig):=true;
			end if;
		end loop; --idig
	end loop; --r


	for c in 1..9 loop
		for idig in 1..9 loop
			tot:=0;
			for r in 1..9 loop
				if candidate(r,c)(idig) and m9(r,c)=0 then
					rr:=r; cc:=c; tot:=tot+1;
				end if;
			end loop; --c
			if tot=1 then -- unique to this col
				hilite3(rr,cc)(idig):=true;
			end if;
		end loop; --idig
	end loop; --r


end id_3;



procedure LinkedPairs is separate;


procedure Draw is

	cc,rr, c01,r01, c01a, r01a, left: float;

	shrink : constant float := 1.0; --0.99;
	dv: constant float := shrink/float(nrows);
	dh: constant float := shrink/float(ncols);

	yy: constant float := -0.99; --dist perp to horz/vert
	dy: constant float :=  0.0001; --thickness perp to h/v

	dr: constant float := dv; --vert cell radius
	dc: constant float := dh; --horz cell radius

	drr: constant float := dr/8.0;
	dcc: constant float := dc/8.0;

	orr, occ,
	j1,j2,j3,j4,j5,j6: float;

	lgfont : constant integer := 22;
	tinyfont : constant integer := 8;

	szfont, tot: integer;
	d: integer; --digit to display 1..9
	big, badmatch, Ymatch, Xmatch, oXmatch: boolean := false;
begin


	if not manualmode then

		id_1; -- boxSingle
		id_3; -- all singles
		id_pairsBP; -- identify pairs within blocks; define boxPair
		id_pairsRC; -- isolated pairs aligned in rows or cols; define rowPair/colPair

		if show4h or show4n then
		setQuads; --problem here
		end if;

		if show2h then
		setHpairs;
		end if;

		if show2n then
		setNpairs;
		end if;

		if show3h then
		setHtriples;
		end if;

		if show3n then
		setNtriples;
		end if;

	end if;


	glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);


	if help  then

		szfont := 12;
		left:=0.05;

		blktex.print2d("Sudoku Key Menu",         0.2, 0.99, szfont);

		blktex.print2d("mouse-click:   cell-select/Deselect", left, 0.95, szfont);

		blktex.print2d("1-9  toggle num   <ctrl>1-9  Assert num",   left, 0.91, szfont);


		blktex.print2d("<u>   Undo last assert [x8]",   left, 0.87, szfont);


		blktex.print2d("<esc> quit",             left, 0.83, szfont);


		blktex.print2d("<m>   toggle Manual-Mode", left, 0.79, szfont);

		blktex.print2d("<h>   toggle this help screen",  left, 0.75, szfont);

		blktex.print2d("<f>   Flush (all-singles/selected)", left, 0.71, szfont);

		if not manualmode then
	------------------------------------------------------------------------------------
			blktex.print2d("======================================", left, 0.68, szfont);
	-----------------------------------------------------------------------------------

			blktex.print2d("<.>   process Unique singles", left, 0.65, szfont);

			blktex.print2d("<a/n> toggle Aligned/Non: Box-Dig-Dbls",left,0.60,szfont);

			blktex.print2d("<p>   Pairs: 123)hidden 4)naked 5)off", left, 0.55, szfont);

			blktex.print2d("<t>   Triples: 123)hidden 4)naked 5)off", left, 0.50, szfont);
			blktex.print2d("<q>   Quads: 123)hidden 4)naked 5)off", left, 0.45, szfont);

			blktex.print2d("<l>   Linked pairs: next Chain", left, 0.40, szfont);


			blktex.print2d("<x>   toggle Xwing", left, 0.36, szfont);

			blktex.print2d("<y>   toggle Ywing", left, 0.33, szfont);

			blktex.print2d("<c>   toggle x-Cycle", left, 0.29, szfont);


--blktex.print2d("<ctrl> <k>  Lite KeyCell (selected)", left, 0.25, szfont);


			blktex.print2d("<k>   toggle KeyCell (all or selected)", left, 0.22, szfont);

			blktex.print2d("<d>   DigDbls: 1)row 2)col 3)box 4)off", left, 0.18, szfont);

			blktex.print2d("<b>   show Brute-force solution", left, 0.14, szfont);

		end if; --not manualmode

		blktex.print2d("<s>   Save current state", left, 0.10, szfont);
		blktex.print2d("<r>   Restore state", left, 0.05, szfont);

	else -- not help






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

		glUseProgram(pictTexShadID);
		glUniformMatrix4fv(MatrixID, 1, GL_FALSE, MVP(1,1)'address);
		glUniform1i(uniftex,0);


		cc := +1.0 - 2.0*(0.5*float(ncols+1)-0.5)*dh;
		rr := +1.0 - 2.0*(0.5*float(nrows+1)-0.5)*dv;

		pictobj.setrect(opict, cc,-1.0,rr,1.0,dy,1.0,j1,j2,j3,j4,j5,j6 );


		if overlay1 then
			glBindTexture(GL_TEXTURE_2D, ol1_texid);
			pictobj.draw(opict, vertbuff, uvbuff, elembuff);
		elsif overlay2 then
			glBindTexture(GL_TEXTURE_2D, ol2_texid);
			pictobj.draw(opict, vertbuff, uvbuff, elembuff);

		elsif overlay3 then
			glBindTexture(GL_TEXTURE_2D, ol3_texid);
			pictobj.draw(opict, vertbuff, uvbuff, elembuff);
		elsif overlay4 then
			glBindTexture(GL_TEXTURE_2D, ol4_texid);
			pictobj.draw(opict, vertbuff, uvbuff, elembuff);

		elsif overlay5 then
			glBindTexture(GL_TEXTURE_2D, ol5_texid);
			pictobj.draw(opict, vertbuff, uvbuff, elembuff);
		elsif overlay6 then
			glBindTexture(GL_TEXTURE_2D, ol6_texid);
			pictobj.draw(opict, vertbuff, uvbuff, elembuff);

		elsif overlay7 then
			glBindTexture(GL_TEXTURE_2D, ol7_texid);
			pictobj.draw(opict, vertbuff, uvbuff, elembuff);
		elsif overlay8 then
			glBindTexture(GL_TEXTURE_2D, ol8_texid);
			pictobj.draw(opict, vertbuff, uvbuff, elembuff);

		elsif overlay9 then
			glBindTexture(GL_TEXTURE_2D, ol9_texid);
			pictobj.draw(opict, vertbuff, uvbuff, elembuff);


		else
			glBindTexture(GL_TEXTURE_2D, floor_texid);
			pictobj.draw(opict, vertbuff, uvbuff, elembuff);
		end if;




		szfont:=9;

-- note: (row=1,col=1) = UL corner

		-- draw red/black cell outlines
		for row in 1..nrows loop
			for col in 1..ncols loop

				badmatch:=false;
				for i in 1..nbad loop
					if row=badcells(i)(1) and col=badcells(i)(2) then
						badmatch:=true;
					end if;
				end loop;



				-- define center of cell (1 of 81):
				-- these coords in [-1..1, -1..1]:
				cc := -1.0 + 2.0*(float(col)-0.5)*dh;
				rr := +1.0 - 2.0*(float(row)-0.5)*dv;

				-- these coords in [0..1, 0..1]:
				c01 := 0.5*(cc+1.0);
				r01 := 0.5*(rr+1.0);
				c01 := c01 - dc/4.0; -- horizontal adjustment

				pictobj.setrect(opict,-cc,yy,rr, dc,dy,dr, j1,j2,j3,j4,j5,j6); --UL

				if (pr>0 and pr<10 and pc>0 and pc<10 
				and row=pr and col=pc )
				and then om9(pr,pc)=0 --disallow hiliting of cells with known values
				then --hilight
					glBindTexture(GL_TEXTURE_2D, red_texid);
					pictobj.draw(opict, vertbuff, uvbuff, elembuff);


	--8may24 addendum
	elsif manualmode and shopink and pinkcell(row,col) then
		glBindTexture(GL_TEXTURE_2D, pink_texid);
		pictobj.draw(opict, vertbuff, uvbuff, elembuff);


				elsif badmatch and showK and not manualmode then --bad cell
					glBindTexture(GL_TEXTURE_2D, blu_texid);
					pictobj.draw(opict, vertbuff, uvbuff, elembuff);

				--17apr24 addendum: Hilight in blue all singles matching selected [red] cell
				elsif ( (pr in 1..9) and (pc in 1..9) and (row/=pr or col/=pc) ) 
				and then ( m9(row,col)=m9(pr,pc) and m9(pr,pc)/=0 ) then
					glBindTexture(GL_TEXTURE_2D, blu_texid);
					pictobj.draw(opict, vertbuff, uvbuff, elembuff);

				--elsif shoZwing and zmatch  then
				--	glBindTexture(GL_TEXTURE_2D, blu_texid);
				--	pictobj.draw(opict, vertbuff, uvbuff, elembuff);

				else
					glBindTexture(GL_TEXTURE_2D, box_texid);
					pictobj.draw(opict, vertbuff, uvbuff, elembuff);
				end if;

			end loop; -- col

		end loop; -- row



		-- now, draw numerals in each cell that
		-- have not yet been eliminated:
		drawnYet:=(others=>(others=>(others=>false)));

		for row in 1..nrows loop
			for col in 1..ncols loop


				oXmatch := false; -- hilite Objects of Xwing deletion
				for i in 1..xcn loop
					if xcd(i)=(row,col) then oXmatch:=true; end if;
				end loop;

				Xmatch :=
					(rx1=row and cx1=col) or
					(rx2=row and cx2=col) or
					(rx3=row and cx3=col) or
					(rx4=row and cx4=col);

				Ymatch := -- cells, if any, involved with Ywing
					(ry1=row and cy1=col) or
					(ry2=row and cy2=col) or
					(ry3=row and cy3=col);

				-- define center of cell (1 of 81):
				-- these coords in [-1..1, -1..1]:
				cc := -1.0 + 2.0*(float(col)-0.5)*dh;
				rr := +1.0 - 2.0*(float(row)-0.5)*dv;

				-- these coords in [0..1, 0..1]:
				c01 := 0.5*(cc+1.0); -- horizontal adjustment for numeral-center
				r01 := 0.5*(rr+1.0); -- vertical adjustment for numeral-center

				-- microAdjust based on LL+LR Pencil Marks
				r01a:=r01+0.005;
				c01a:=c01;

				r01 := r01 - dr/20.0; -- vertical micro-adjustment (new as of 2jul23)
				c01 := c01 - dc/8.0;  -- horizontal micro-adjustment for numeral-center (2jul23)


				tot:=0;
				for d in 1..9 loop
					if candidate(row,col)(d) then tot:=tot+1; end if;
				end loop;

				--1may24 addendum:
				if m9(row,col)>0 then 
					big:=true; 
				else
					big:=false;
				end if;





				for r in 0..2 loop
				for c in 0..2 loop
					orr := drr*float(2-r);
					occ := dcc*float(c);

					d:=1+r*3+c; -- digit to display 1..9




	if manualmode then

--##############################################################################
--this is operation for manual-candidate-mode; begin:


					if om9(row,col)=d then --Original Spec (darker gray)
						grytex.print2d( i2st(d), c01a, r01a,  lgfont); --gray sg30

					elsif m9(row,col)=d then --lighter gray
						gr2tex.print2d( i2st(d), c01a, r01a,  lgfont); --gray sg60

					elsif mandidate(row,col)(d) and not big then
						ltgtex.print2d( i2st(d), c01+occ, r01+orr,  szfont); --ltGrey

					end if;

					--drawnYet(row,col)(d):=true;


--this is operation for manual-candidate-mode; end:
--##############################################################################

	else -- NOT manualmode


					if candidate(row,col)(d) then


						-- unique digit, centered, large
						if big or tot=1 then -- ? need for flush ?


							if om9(row,col)=d then --Original Spec (darker gray)
								grytex.print2d( i2st(d), c01a, r01a,  lgfont); --gray sg30
								drawnYet(row,col):=(others=>true);

							elsif m9(row,col)=d or showbrute then --lighter gray
								gr2tex.print2d( i2st(d), c01a, r01a,  lgfont); --gray sg60
								drawnYet(row,col):=(others=>true);

							elsif not big then -- single candidate (green)
								grntex.print2d( i2st(d), c01+occ, r01+orr,  szfont);
								drawnYet(row,col):=(others=>true);

							end if;


						--elsif shoZwing and zmatch and d=zval then
						--	grntex.print2d( i2st(d), c01+occ, r01+orr,  szfont);
						--	drawnYet(row,col)(d):=true;


---------- xCycle (showX=true)-----------------------------------------------------------------

						-- if showX is true then 1st digit is removable...cyan:
						elsif badxc and showX and d=digSelect and row=ca(1) and col=ca(2) then
							cyatex.print2d( i2st(d), c01+occ, r01+orr,  szfont+1); --deletable
							drawnYet(row,col)(d):=true;

						elsif badxc and showX and d=digSelect and row=cz(1) and col=cz(2) then
							--grntex.print2d( i2st(d), c01+occ, r01+orr,  szfont+1);
							blutex.print2d( i2st(d), c01+occ, r01+orr,  szfont+1); --ON
							drawnYet(row,col)(d):=true;

						elsif badxc and showX and d=digSelect 
						and (xoncycle(row,col) or xoffcycle(row,col)) then
							if xoncycle(row,col) then
								blutex.print2d( i2st(d), c01+occ, r01+orr,  szfont+1); --ON
							else
								redtex.print2d( i2st(d), c01+occ, r01+orr,  szfont+1); --OFF
							end if;
							drawnYet(row,col)(d):=true;

				------------ new good xCycle ----------------------------------------

						elsif not badxc and showX 
						and d=digSelect and hiliteXcDel(row,col)(d) 
						then
							cyatex.print2d( i2st(d), c01+occ, r01+orr,  szfont+1); --deletable
							drawnYet(row,col)(d):=true;

						elsif not badxc and showX and d=digSelect 
						and (xoncycle(row,col) or xoffcycle(row,col)) then
							if xoncycle(row,col) then
								blutex.print2d( i2st(d), c01+occ, r01+orr,  szfont+1); --ON
							else
								redtex.print2d( i2st(d), c01+occ, r01+orr,  szfont+1); --OFF
							end if;
							drawnYet(row,col)(d):=true;

---------- xCycle end -----------------------------------------------------------------


----------- KeyCell begin -----------------------------------------------------------
						elsif showK and d=badig and row=pr and col=pc then -- deletable
							cyatex.print2d( i2st(d), c01+occ, r01+orr,  szfont+1);
							drawnYet(row,col)(d):=true;

						--addendum 19may to show blue trail towards blue cells
						elsif showK and blu9(row,col)=d then --would-be singleton
							blutex.print2d( i2st(d), c01+occ, r01+orr,  szfont+1);
							drawnYet(row,col)(d):=true;

						elsif showK and hiliteKdel(row,col)(d) then --deleted digit
							orntex.print2d( i2st(d), c01+occ, r01+orr,  szfont+1);
							drawnYet(row,col)(d):=true;
----------- KeyCell end -----------------------------------------------------------


---------------Linked Pairs ------------------------------------------------------------
						elsif showLP and d=digSelect and colorL2(d,seechain(d),row,col)>0 then

							if colorL2(d,seechain(d),row,col)=3 then --Cyan (removable)
								cyatex.print2d( i2st(d), c01+occ, r01+orr,  szfont+1); --cyan
								drawnYet(row,col)(d):=true;

							elsif colorL2(d,seechain(d),row,col)=1 then
								redtex.print2d( i2st(d), c01+occ, r01+orr,  szfont+1); --Red 5jul23
								drawnYet(row,col)(d):=true;
							elsif colorL2(d,seechain(d),row,col)=2 then --Blue
								blutex.print2d( i2st(d), c01+occ, r01+orr,  szfont+1); --blu
								drawnYet(row,col)(d):=true;

							end if;
---------------Linked Pairs ------------------------------------------------------------



--------d-key------------------------------------------------------------------------

				-- RowPairs:

						elsif rowPairs and hiliteRowRem(row,col)(d) then 
							cyatex.print2d( i2st(d), c01+occ, r01+orr,  szfont);
							drawnYet(row,col)(d):=true;

						elsif rowPairs and hiliteRow(row,col)(d)  then 
						-- show digit pairs in rows/cols
							redtex.print2d( i2st(d), c01+occ, r01+orr,  szfont);
							drawnYet(row,col)(d):=true;


				-- ColPairs:

						elsif colPairs and hiliteColRem(row,col)(d)  then 
							cyatex.print2d( i2st(d), c01+occ, r01+orr,  szfont);
							drawnYet(row,col)(d):=true;

						elsif colPairs and hiliteCol(row,col)(d)  then 
						-- show digit pairs in rows/cols
							redtex.print2d( i2st(d), c01+occ, r01+orr,  szfont);
							drawnYet(row,col)(d):=true;


				-- BoxPairs:

						--elsif hiliteBoxRem(row,col)(d) and boxpairs  then 
						elsif hiliteBoxRem(row,col)(d) and (boxpairs or boxPairsAl)  then --26jul23
						--highlight aligned deletables
							cyatex.print2d( i2st(d), c01+occ, r01+orr,  szfont);
							drawnYet(row,col)(d):=true;

						elsif hiliteBP(row,col)(d) and (boxpairs or boxPairsAl) then 
						--highlight aligned boxPairs = pointing-pairs
							redtex.print2d( i2st(d), c01+occ, r01+orr,  szfont);
							drawnYet(row,col)(d):=true;

------addendum 12jul23:
						elsif hiliteBPna(row,col)(d) and boxpairsNa then 
							purtex.print2d( i2st(d), c01+occ, r01+orr,  szfont);
							drawnYet(row,col)(d):=true;

--------d-key------------------------------------------------------------------------




--------2s 3s 4s--------------------------------------------------------------
-- note that removables should be drawn first:

						elsif show2h and hiliteHPrem(row,col)(d)  then 
						-- show hidden pairs --deletable
							cyatex.print2d( i2st(d), c01+occ, r01+orr,  szfont);
							drawnYet(row,col)(d):=true;

						elsif show2h and hiliteHP(row,col)(d)  then 
						-- show hidden pairs
							redtex.print2d( i2st(d), c01+occ, r01+orr,  szfont);
							drawnYet(row,col)(d):=true;


						elsif show2n and hiliteNPrem(row,col)(d)  then 
						-- show naked pairs deletable
							cyatex.print2d( i2st(d), c01+occ, r01+orr,  szfont);
							drawnYet(row,col)(d):=true;

						elsif show2n and hiliteNP(row,col)  then 
						-- show naked pairs
							redtex.print2d( i2st(d), c01+occ, r01+orr,  szfont);
							drawnYet(row,col)(d):=true;




						elsif show3h and hiliteHTrem(row,col)(d)  then 
						-- show hidden triples --deletable
							cyatex.print2d( i2st(d), c01+occ, r01+orr,  szfont);
							drawnYet(row,col)(d):=true;

						elsif show3h and hiliteHT(row,col)(d)  then 
						-- show hidden triples
							redtex.print2d( i2st(d), c01+occ, r01+orr,  szfont);
							drawnYet(row,col)(d):=true;


						elsif show3n and hiliteNTrem(row,col)(d)  then 
						-- show naked triples deletables
							cyatex.print2d( i2st(d), c01+occ, r01+orr,  szfont);
							drawnYet(row,col)(d):=true;

						elsif show3n and hiliteNT(row,col)  then 
						-- show naked triples
							redtex.print2d( i2st(d), c01+occ, r01+orr,  szfont);
							drawnYet(row,col)(d):=true;



						elsif show4h and hiliteHQrem(row,col)(d)  then 
						-- show hidden quads --deletable
							cyatex.print2d( i2st(d), c01+occ, r01+orr,  szfont);
							drawnYet(row,col)(d):=true;

						elsif show4h and hiliteHQ(row,col)(d)  then 
						-- show hidden quads
							redtex.print2d( i2st(d), c01+occ, r01+orr,  szfont);
							drawnYet(row,col)(d):=true;


						elsif show4n and hiliteNQrem(row,col)(d)  then 
						-- show naked quads removables
							cyatex.print2d( i2st(d), c01+occ, r01+orr,  szfont);
							drawnYet(row,col)(d):=true;

						elsif show4n and hiliteNQ(row,col)  then 
						-- show naked quads
							redtex.print2d( i2st(d), c01+occ, r01+orr,  szfont);
							drawnYet(row,col)(d):=true;

--------2s 3s 4s--------------------------------------------------------------



						elsif shoXwing and oXmatch and d=xdig then --show Xwing deletable digits
							cyatex.print2d( i2st(d), c01+occ, r01+orr,  szfont);
							drawnYet(row,col)(d):=true;

						elsif shoXwing and Xmatch and d=xdig then --show main Xwing digits
							redtex.print2d( i2st(d), c01+occ, r01+orr,  szfont);
							drawnYet(row,col)(d):=true;



						elsif showY and row=tr0 and col=tc0 and d=tdig then -- Ywing deletable target
								cyatex.print2d( i2st(d), c01+occ, r01+orr,  szfont);
							drawnYet(row,col)(d):=true;

						elsif showY and Ymatch then -- show Ywing cells
								redtex.print2d( i2st(d), c01+occ, r01+orr,  szfont);
							drawnYet(row,col)(d):=true;


						elsif 
						not hilite3(row,col)(d) 
						and not hiliteBP(row,col)(d) 
						then
							ltgtex.print2d( i2st(d), c01+occ, r01+orr,  szfont); --ltGrey
							drawnYet(row,col)(d):=true;

						end if;


						if not drawnYet(row,col)(d) then

							if 
								not showLP and not showX and not showK
								and not shoXwing and not showY
								and not boxPairs and not rowPairs and not colPairs
								and not show2h and not show2n
								and not show3h and not show3n
								and not show4h and not show4n
							then
							-- avoid this color-coded drawing of singles/boxPairs
							-- in special modes above.

								if  hilite3(row,col)(d)  then --single to be asserted
									--orntex.print2d( i2st(d), c01+occ, r01+orr,  szfont);
									grntex.print2d( i2st(d), c01+occ, r01+orr,  szfont);
									drawnYet(row,col)(d):=true;

								end if;

							end if; --not showLP...


							--if not drawnYet(row,col)(d)  then
							if not big and not drawnYet(row,col)(d)  then -- upd 1may24
								ltgtex.print2d( i2st(d), c01+occ, r01+orr,  szfont); --ltGrey
								drawnYet(row,col)(d):=true;
							end if;


						end if; --not drawnYet


					end if;


	end if; --[NOT-]manualmode #################################################################


				end loop;
				end loop;

			end loop; -- col

		end loop; -- row


--####################################################################################
	if not manualmode then


		if showK then -- KeyCell test
			grytex.print2d( "KeyCell-Test", 0.4, 0.999, tinyfont );

		elsif show3n then --naked triples
			grytex.print2d( "NAKED TRIPLES-R/C/B", 0.37, 0.999, tinyfont);

		elsif show3h then --hidden triples
			if bmode then
				grytex.print2d( "HIDDEN TRIPLES-BOX", 0.37, 0.999, tinyfont);
			elsif rmode then
				grytex.print2d( "HIDDEN TRIPLES-ROW", 0.37, 0.999, tinyfont);
			elsif cmode then
				grytex.print2d( "HIDDEN TRIPLES-COL", 0.37, 0.999, tinyfont);
			end if;

		elsif show4h then --hidden quads
			if bmode then
				grytex.print2d( "HIDDEN QUADS-BOX", 0.38, 0.999, tinyfont);
			elsif rmode then
				grytex.print2d( "HIDDEN QUADS-ROW", 0.38, 0.999, tinyfont);
			elsif cmode then
				grytex.print2d( "HIDDEN QUADS-COL", 0.38, 0.999, tinyfont);
			end if;

		elsif show4n then --naked quads
			grytex.print2d( "NAKED QUADS-R/C/B", 0.38, 0.999, tinyfont);

		elsif show2h then --hiddenpairs
			if bmode then
				grytex.print2d( "HIDDEN PAIRS BOX", 0.38, 0.999, tinyfont);
			elsif rmode then
				grytex.print2d( "HIDDEN PAIRS ROW", 0.38, 0.999, tinyfont);
			elsif cmode then
				grytex.print2d( "HIDDEN PAIRS COL", 0.38, 0.999, tinyfont);
			end if;

		elsif show2n then --nakedpairs
			grytex.print2d( "NAKED PAIRS-R/C/B", 0.38, 0.999, tinyfont);

		elsif showX then --Xcycle
			grytex.print2d( 
				"xCycle-"&i2st(ca(1))&i2st(ca(2))&"-"&i2st(cz(1))&i2st(cz(2))
				,0.41, 0.999, tinyfont);
				--,0.4, 0.999, tinyfont);


		--elsif shoZwing then --zwing
		--	grytex.print2d( "Z-WING", 0.4, 0.999, tinyfont);


		elsif shoXwing then --Xwing
			grytex.print2d( "X-WING", 0.4, 0.999, tinyfont);


		elsif showY then --Ywing
			grytex.print2d( "Y-WING", 0.4, 0.999, tinyfont);


		--elsif showU then --all singles
		--	orntex.print2d( "SINGLES", 0.4, 0.999, tinyfont);

		elsif rowPairs  then -- r/c 2
			grytex.print2d( "DIG DBLs ROW", 0.4, 0.999, tinyfont );

		elsif colPairs  then -- r/c 2
			grytex.print2d( "DIG DBLs COL", 0.4, 0.999, tinyfont );


		elsif showLP then
			grytex.print2d( "LINKED-PAIRS(" & i2st(digSelect)
				&")"&integer'image(1+seechain(digSelect))&" of"
				&integer'image(nchains(digSelect)), 
				0.4, 0.999, tinyfont);

		elsif boxPairsNa then
			grytex.print2d( "NonAligned Pairs", 0.35, 0.999, tinyfont );

		elsif boxPairsAl then
			grytex.print2d( "Aligned Pairs", 0.35, 0.999, tinyfont );

		elsif boxPairs  then
			grytex.print2d( "DIG Dbls/Trpls BOX", 0.35, 0.999, tinyfont );

		elsif showbrute then
			grytex.print2d( "Solution View", 0.4, 0.999, tinyfont );

		else -- auto-candidate view
			grytex.print2d( "Auto-Candidate", 0.4, 0.999, tinyfont );

		end if;

	else --manualmode

		grytex.print2d( "Manual Candidate", 0.4, 0.999, tinyfont );


	end if; --not manualmode


--####################################################################################


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

	end if; --help


end Draw;












	nc1,nc2, ncc : integer := 0;
	numstr : string(1..5) := (others=>' ');

	totgame, nlevels : integer := 0;

	tfile : text_io.file_type;





procedure checkForUserFile is
	use myint_io;
	ifil: file_type;
	i: integer;
	ok: boolean;

	svc, svm: candidatetype;
	svm9: m9type;
begin

  	if Ada.Command_Line.Argument_Count = 0 then --restore
		ok:=fullreadpuzzle; -- now sets fnamUstr
		if not ok then
			raise program_error;
		end if;

findUnique(ok); --experimental 18apr24

		restoredPuzzle:=true;

  	elsif Ada.Command_Line.Argument_Count = 1 then

		declare
       fstr : string := Ada.Command_Line.Argument(1);--File
		begin

			fnamUstr:=to_unbounded_string( fstr );


			text_io.open(ifil, in_file, fstr);

			candidate:=(others=>(others=>(others=>true)));
			mandidate:=remEmpty;


			for r in 1..9 loop
			for c in 1..9 loop
				get(ifil,i);
				if i>0 and i<=9 then
					om9(r,c):=i;
					candidate(r,c):=(others=>false);
					candidate(r,c)(i) := true;
					mandidate(r,c)(i) := true;
				end if;

--put(" ");
--put( i2st(i) );

			end loop;
--new_line;
			end loop;
--new_line;

			m9:=om9;

			text_io.close(ifil);
		end; --declare


-- note: at this point flushes are likely needed to initialize
-- the candidates. But each flush might discover additional singles
-- that require further flushing. It is best to clearly understand
-- the initial puzzle state.

		--flush; --known values are removed from all their houses

   end if;


	--1may24 addendum: get solution...

	svc:=candidate;
	svm:=mandidate;
	svm9:=m9;

	susolve;
	sol:=m9;

	candidate:=svc;
	mandidate:=svm;
	m9:=svm9;

end checkForUserFile;






procedure fullsavepuzzle( usetemp: boolean := false; id: s9 := 0 ) is
	--path: constant string := "data/";
	path: constant string := "data"&gnat.os_lib.directory_separator;

	use myint_io;
	ofil: file_type;

	ok2save: boolean;
begin

	--addendum 9may24...to avoid saving a corrupt puzzle, begin------------------------
	ok2save:=true;
	for r in 1..9 loop
	for c in 1..9 loop
		if m9(r,c)>0 and m9(r,c)/=sol(r,c) then ok2save:=false; end if;
	end loop;
	end loop;
	--addendum 9may24...to avoid saving a corrupt puzzle, end------------------------

if not ok2save then
	put(" save failed due to erroneous state!");
	new_line;
else

	if usetemp and id=0 then --Warning: this dis-allows user save in Kcell view
		text_io.create(ofil, out_file, path&"k_tmp.txt");
	elsif usetemp then
		text_io.create(ofil, out_file, path&i2st(id)&"_tmp.txt");
	else
		text_io.create(ofil, out_file, path&"frestoreB.txt");
	end if;

	for r in 1..9 loop
		for c in 1..9 loop
			for d in 1..9 loop

--if usetemp then
if usetemp and id=0 then

				if candidate(r,c)(d) then
					put(ofil, "1 ");
				else
					put(ofil, "0 ");
				end if;

else

				--4=>mc9=ttt : m9(r,c)=d
				--3=>mc9=ttf : m9=0
				--2=>mc9=tff
				--1=>mc9=ftf
				--0=>mc9=fff

				if m9(r,c)=d then
					put(ofil, "4 ");

				elsif mandidate(r,c)(d) and candidate(r,c)(d) then
					put(ofil, "3 ");

				elsif mandidate(r,c)(d) and not candidate(r,c)(d) then
					put(ofil, "2 ");

				elsif not mandidate(r,c)(d) and candidate(r,c)(d) then
					put(ofil, "1 ");

				else
					put(ofil, "0 ");
				end if;

end if;

			end loop;
		end loop;
	end loop;

	new_line(ofil);
	put_line(ofil, to_string(fnamUstr) );

	for r in 1..9 loop
	for c in 1..9 loop
		put(ofil, " ");
		put(ofil, i2st(om9(r,c)) );
	end loop;
	end loop;

--2may24 addendum
if manualmode then
	put(ofil, " 0");
else
	put(ofil, " 1");
end if;


	text_io.close(ofil);

	if not usetemp then
		put_line("Saved to frestoreB.txt");
	end if;

end if; --ok2save

end fullsavepuzzle;




function fullreadpuzzle( usetemp: boolean := false; id: s9 := 0  ) return boolean is
	--path: constant string := "data/";
	path: constant string := "data"&gnat.os_lib.directory_separator;

	use myint_io;
	ifil: file_type;
	b,k,ii: integer; --boolean
	junkUstr: unbounded_string;
	onshok: constant boolean := showK;
begin

if usetemp or else ada.directories.Exists(path&"frestoreB.txt") then

	puztested:=false;

	if usetemp and id=0 then
		text_io.open(ifil, in_file, path&"k_tmp.txt");
	elsif usetemp then
		text_io.open(ifil, in_file, path&i2st(id)&"_tmp.txt");
	else
		text_io.open(ifil, in_file, path&"frestoreB.txt");
	end if;

	for r in 1..9 loop
		for c in 1..9 loop
			for d in 1..9 loop
				get(ifil,b);

	--if usetemp then
	if usetemp and id=0 then

				if b=1 then candidate(r,c)(d):=true;
				else candidate(r,c)(d):=false;
				end if;

	else

				--4=>mc9=ttt : m9(r,c)=d
				--3=>mc9=ttf : m9=0
				--2=>mc9=tff
				--1=>mc9=ftf
				--0=>mc9=fff

				if b=4 then 
					m9(r,c):=d; 
					mandidate(r,c)(d):=true;
					candidate(r,c)(d):=true; 
				elsif b=3 then
					m9(r,c):=0; 
					mandidate(r,c)(d):=true; 
					candidate(r,c)(d):=true;
				elsif b=2 then
					m9(r,c):=0; 
					mandidate(r,c)(d):=true; 
					candidate(r,c)(d):=false;
				elsif b=1 then 
					m9(r,c):=0; 
					mandidate(r,c)(d):=false;
					candidate(r,c)(d):=true;
				else 
					m9(r,c):=0; 
					mandidate(r,c)(d):=false;
					candidate(r,c)(d):=false;
				end if;

	end if;

			end loop;
		end loop;
	end loop;

	get_line(ifil, junkUstr); --read to EOL of data line
	get_line(ifil, fnamUstr); --next [=last] line is now the original filename

	for r in 1..9 loop
	for c in 1..9 loop
		get(ifil,b); om9(r,c):=b;
	end loop;
	end loop;

--2may24 addendum
get(ifil,b);
if b=0 then
	manualmode:=true;
else
	manualmode:=false;
end if;


	text_io.close(ifil);


	if usetemp then 
	--we must fully restore m9 by REpromoting singles
	--since only the original om9 was actually saved

		m9:=om9;
		for r in i9 loop
		for c in i9 loop
		if m9(r,c)=0 then
			k:=0;
			for dig in 1..9 loop
			if candidate(r,c)(dig) then k:=k+1; ii:=dig; end if;
			end loop;
			if k=1 then -- ii is only candidate
				m9(r,c):=ii;
			end if;
		end if;
		end loop;
		end loop;

	end if;

	if not usetemp then 
		put_line("Read from frestoreB.txt");
	end if;

	return true;

else --frestore.txt does not exist
	put_line("Restore file not found!");
	return false;
end if;

end fullreadpuzzle;















	arrowdwell : constant float := 0.2; --also for autosolve
	dwell : constant float := 0.2;

	keytime, akeytime: float := 0.0;


procedure getKeyInputs( mainWin : access GLFWwindow ) is separate;

	pickdwell: constant float := 0.5;
	mptime: float := 0.0;
procedure getMouseClick( 
	mainWin : access GLFWwindow;
	wid,hit: interfaces.c.int
	) is separate;


	nz: integer;
	rr, cc, bno,rno,cno: s9 := 0;

	contradiction, ok: boolean := false;

begin -- asud =========================================================



	first_prep; -- init graphics/sound, defines fnum, flev

	checkForUserFile; --input puzzle

	setup_textures;

	updateMVP;

	restart;


	--9jun21 : to avoid opening with wrong drawable size
	wwid:=0;
	whit:=0;



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



		--GlfwPollEvents; --good
		GlfwWaitEvents;

		getKeyInputs(mainWindow);
		getMouseClick(mainWindow,wwid,whit);


		exit when glfwWindowShouldClose(mainWindow) /= 0; --14may21 addendum



-------- here we handle resizing window ----------------------


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

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

		end if;


-------------------------------------------------------
		if not puztested then

			nz:=numZeros; --# undefined cells remaining
			contradiction := 
				emptyCell(rr,cc)  --(rr,cc) = last-found empty
				or missingDigit(bno,rno,cno); --block/row/col

			if nz=0 and not showbrute then
				put_line(" Solved !");
				puztested:=true; --message just once
				badcells := (others=>(others=>0));
				pr:=0; pc:=0;
			elsif contradiction then
				puztested:=true;
				if rr>0 and cc>0 then
					put(" empty cell @ "&i2st(rr)&i2st(cc));
				elsif bno>0 then
					put(" missing digit in box "&i2st(bno));
				elsif rno>0 then
					put(" missing digit @ row "&i2st(rno));
				elsif cno>0 then
					put(" missing digit @ col "&i2st(cno));
				end if;
				put_line("   FAIL!  Undo last assert, if possible.");

			end if;

		end if;
-------------------------------------------------------
-------------------------------------------------------


		Draw; -- main drawing here


		glflush;
		glfwSwapBuffers( mainWindow );


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





	release_textures;
	purtex.cleanuptext;
	blktex.cleanuptext;
	grytex.cleanuptext;
	ltgtex.cleanuptext;
	gr2tex.cleanuptext;
	whitex.cleanuptext;
	blutex.cleanuptext;
	cyatex.cleanuptext;
	redtex.cleanuptext;
	magtex.cleanuptext;
	orntex.cleanuptext;
	yebtex.cleanuptext;
	grntex.cleanuptext;

	glfwdestroywindow(mainWindow);
	glfwTerminate;


exception
when others=>

	put_line("asud: abnormal termination");
	release_textures;
	purtex.cleanuptext;
	blktex.cleanuptext;
	grytex.cleanuptext;
	ltgtex.cleanuptext;
	gr2tex.cleanuptext;
	whitex.cleanuptext;
	blutex.cleanuptext;
	cyatex.cleanuptext;
	redtex.cleanuptext;
	magtex.cleanuptext;
	orntex.cleanuptext;
	yebtex.cleanuptext;
	grntex.cleanuptext;
	glfwdestroywindow(mainWindow);
	glfwTerminate;

end asud;

