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


-- Brute-Force Sudoku solver


separate( asud )



procedure susolve is


	type flagtype is array(i9) of boolean;
	flags: flagtype;



procedure output is
	mm: s9;
begin

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

	for r in i9 loop
		for c in i9 loop
			mm:=m9(r,c);
			candidate(r,c)(mm):=true;
		end loop;
	end loop;


end output;






function badBlock(r,c:i9) return boolean is
	mm,r0,c0: s9;
begin

	if r<=3 then r0:=0;
	elsif r<=6 then r0:=3;
	else r0:=6; end if;
	if c<=3 then c0:=0;
	elsif c<=6 then c0:=3;
	else c0:=6; end if;

	flags := (others=>false);

	for r in r0+1..r0+3 loop
	for c in c0+1..c0+3 loop

		mm := m9(r,c);
		if mm /= 0 then
			if flags(mm) = true then
				return true; --already used
			else
				flags(mm) := true; 
			end if;
		end if;

	end loop; --c
	end loop; --r

	return false;

end badBlock;


function badRow(r:i9) return boolean is
	mm: s9;
begin

	flags := (others=>false);
	for c in i9 loop
		mm := m9(r,c);
		if mm /= 0 then
			if flags(mm) = true then --already used
				return true;
			else
				flags(mm) := true; 
			end if;
		end if;
	end loop;

	return false;

end badRow;


function badCol(c:i9) return boolean is
	mm: s9;
begin

	flags := (others=>false);
	for r in i9 loop
		mm := m9(r,c);
		if mm /= 0 then
			if flags(mm) = true then --already used
				return true;
			else
				flags(mm) := true; 
			end if;
		end if;
	end loop;

	return false;

end badCol;


function done return boolean is
	mm: s9;
begin

	for r in i9 loop
	for c in i9 loop
		mm:=m9(r,c);
		if mm=0 then
			return false;
		end if;
	end loop;
	end loop;

	return true;

end done;


victory: boolean := false;

procedure recurse(found: in out boolean) is
	skip,quit: boolean := false;
begin
	--simple brute force...
	--for each zero [undetermined entry] 
	--in lexicographic order...
	--try 1..9 until it is ruled out.

	quit:=false;

if not found then

	outer: --8may22
	for r in i9 loop
		middle: --8may22
		for c in i9 loop

			if m9(r,c)=0 then
			-- this must be the next indeterminate
			-- in lexicographic order

				inner: --8may22
				for x in i9 loop

					m9(r,c):=x; --attempt to stuff an "x" here

					skip:=badBlock(r,c) or badRow(r) or badCol(c);

					if not skip then

						if done then
							output;
							found:=true;
							quit:=true;
							exit outer; --8may22
						else
							recurse(found);
						end if;

					end if;

					exit when quit;

				end loop inner; -- tried 1..9 for m9(r,c)

				m9(r,c):=0; --this setup failed...i.e.
				--there was no value for m9(r,c) that was valid
				quit:=true;

			end if;

			exit when quit;
		end loop middle; --c

		exit when quit;
	end loop outer; --r

end if; --not found

end recurse;


begin --susolve

	victory:=false;
	recurse(victory);

--addendum 9may24 ...apparently only candidate is set here!
for r in 1..9 loop
for c in 1..9 loop
for i in 1..9 loop
if candidate(r,c)(i) then
	m9(r,c):=i;
end if;
end loop;
end loop;
end loop;
--this simplifies setting "sol"

end susolve;
