;unit SudokuSolve;

;interface

;type
;   TSudokuBoard=array[0..8,0..8] of byte;//òèï ïîëå äëÿ èãðû

;   function CheckSudoku(var Map: TSudokuBoard): boolean;
;   //âîçâðàùàåò true åñëè ïîëå ñîñòàâëåíî ïðàâèëüíî

;   function Solve(var Map: TSudokuBoard): integer;
;   //ðåøàåò Ñóäîêó
;   //Result = 1; - ðåøåíèå íàéäåíî
;   //Result = -1; - òóïèêëâàÿ êîìáèíàöèÿ

;   procedure CopyArray(var Dst: TSudokuBoard;Src: TSudokuBoard);

;implementation

;type
;   TSudokuPt=record //òèï òî÷êà ñ ìèíèìàëüíûì ÷èñëîì êàíäèäàòîâ
;       mini,minj,variances: byte;
;   end;

;var
;  TempMap: TSudokuBoard;//ïîëÿ
;  Pt: TSudokuPt;            //òî÷êà
;  i,j: byte;                //ñ÷åò÷èêè



align 4
CheckSudoku:
pushad
;function CheckSudoku(var Map: TSudokuBoard): boolean;		;êàðòà â esi!
;var
;    i,j,x,y: byte;
;    Zap: set of byte;
;begin

;//ïðîâåðÿåì ñòîëáöû
; for i:=0 to 8 do
; begin
; Zap:=[];
; for j:=0 to 8 do
;   if Map[i,j]<>0 then
;     if Map[i,j] in Zap then
;     begin
;       Result:=false;
;       Exit;
;       end else
;       Zap:=Zap+[Map[i,j]];
; end;
	xor	ecx,ecx
	xor	eax,eax
	xor	edx,edx
	mov	bx,0x0909
.1:	mov	al, byte [esi+ecx]
	test	al,al
	jz	@f
		btc	dx,ax
		jc	.ret_false
	@@:
	add	cl,9
	dec	bl
	jnz	.1
;	test	[flags],1 shl 15
;	jz	@f
;	cmp	edx,1022 ;1111111110b
;	jne	.ret_false
;@@:
	bt	[flags],15
	jnc	@f
	cmp	dx,1022 ;1111111110
	jne	.ret_false
@@:
	sub	cl,9*9-1
	xor	edx,edx
	mov	bl,9
	dec	bh
	jnz	.1


;//ïðîâåðÿåì ñòðîêè
; for j:=0 to 8 do
; begin
; Zap:=[];
; for i:=0 to 8 do
;    if Map[i,j]<>0 then
;       if Map[i,j] in Zap then
;       begin
;       Result:=false;
;       Exit;
;       end else
;       Zap:=Zap+[Map[i,j]]
; end;

	xor	ecx,ecx
	xor	eax,eax
	xor	edx,edx
	mov	bx,0x0909
.2:	mov	al, byte [esi+ecx]
	test	al,al
	jz	@f
		btc	dx,ax
		jc	.ret_false
	@@:
	inc	ecx
	dec	bl
	jnz	.2
	bt	[flags],15
	jnc	@f
	cmp	dx,1022 ;1111111110
	jne	.ret_false
@@:
	xor	edx,edx
	mov	bl,9
	dec	bh
	jnz	.2

;//ïðîâåðÿåì ñåêòîðà
;for i:=0 to 2 do
;  for j:=0 to 2 do
;  begin
;  zap:=[];
;  for x:=0 to 2 do
;     for y:=0 to 2 do
;     if map[i*3+y,j*3+x]<>0 then
;     if map[i*3+y,j*3+x] in Zap then
;     begin
;     Result:=false;
;     exit;
;     end else
;     Zap:=zap+[map[i*3+y,j*3+x]];
;  end;
;Result:=true;
;end;
	mov	ecx,0x0303 ;ij
	xor	eax,eax
	xor	edx,edx
	mov	ebx,0x0303 ;xy

.3:	movzx	eax,ch
	dec	al
	lea	eax,[eax*2+eax]
	add	al,bl		;i*3+y
	dec al
	mov	edi,eax
	movzx	eax,cl
	dec	al
	lea	eax,[eax*2+eax]
	add	al,bh		;j*3+x
	dec al
	xchg	eax,edi
	mov	ah,9
	mul	ah
	add	eax,edi		;i*3+y,j*3+x
	mov	al,[esi+eax]
	test	al,al
	jz	@f
		btc	dx,ax
		jc	.ret_false
	@@:
	dec	bl
	jnz	.3
	mov	bl,3
	dec	bh
	jnz	.3
	bt	[flags],15
	jnc	@f
	cmp	dx,1022 ;1111111110
	jne	.ret_false
@@:
	mov	bx,0x0303
	xor	edx,edx
	dec	cl
	jnz	.3
	mov	cl,3
	dec	ch
	jnz	.3
popad
clc
ret
.ret_false:
popad
stc
ret

_iRet	dw ?

Pt:
.mini db ?
.minj db ?
.variances db ?

bFree db ?
nVariances db ?
nMinVariances db ?

align 4
FindMinPoint:
	pushad
	mov	[bFree],0
	mov	[nMinVariances],10
	mov	cx,0x0909 ;ij
.1:	movzx	eax,ch
	mov	ah,9
	dec	al
	mul	ah
	add	al,cl
	dec	al
	cmp	byte [esi+eax],0
	je	@f
.11:	dec	cl
	jnz	.1
	mov	cl,9
	dec	ch
	jnz	.1
	jmp	.3

@@:	mov	[nVariances],0
	mov	[bFree],1
	mov	ebx,1
.2:	mov	[esi+eax],bl
	call	CheckSudoku
	jc	@f
	inc	[nVariances]
@@:	inc	ebx
	cmp	ebx,9
	jbe	.2

	mov	byte [esi+eax],0
	mov	dl,[nVariances]
	cmp	dl,0
	je	.11
	cmp	dl,[nMinVariances]
	jnb	.11
	mov	[Pt.mini],ch
	mov	[Pt.minj],cl
	mov	[Pt.variances],dl
	mov	[nMinVariances],dl
	jmp	.11

.3:	cmp	[bFree],1
	jne	@f
	cmp	[nMinVariances],10
	jge	@f
	mov	[_iRet],1
	popad
	ret
@@:	cmp	[bFree],1
	jne	@f
	mov	[_iRet],-1
	popad
	ret
@@:	mov	[_iRet],0
	popad
ret


;   //èùåò òî÷êó ñ ìèíèìàëüíûì ÷èñëîì êàíäèäàòîâ è çàïèñèâàåò ðåçóëüòàò â MinPt
;   //Result = -1; - íàøëè, êóäà ìîæíî ïîñòàâèòü öèôðó
;   //Result = 1; - ñâîáîäíîå ìåñòî åñòü íà ïîëå, íî ïîñòàâèòü íèêóäà íåëüçÿ
;   //Result = 0; - íåò ñâîáîäíîãî ìåñòà
;function FindMinPoint(var MinPt: TSudokuPt;var Map: TSudokuBoard): integer;
;var
;nVariances,nMinVariances,variance: byte;
;bFree: boolean;
;begin
;bFree:= false;
;nMinVariances:=10;
;for i:=0 to 8 do
;  for j:=0 to 8 do
;  begin
;  if Map[i,j]<>0 then continue;
;  nVariances := 0;
;  bFree := true;
;  for variance:=1 to 9 do
;   begin
;     map[i,j]:=variance;
;     if CheckSudoku(Map) then inc(nVariances);
;   end;
;  Map[i,j]:=0;
;  if nVariances=0 then continue;
;  if nVariances < nMinVariances then
;    begin
;    MinPt.mini:=i;
;    MInPt.minj:=j;
;    MinPt.variances:=nVariances;
;    nMinVariances := nVariances;
;    end;
;  end;
;if (bFree) and (nMinVariances<10) then // íàøëè, êóäà ìîæíî ïîñòàâèòü öèôðó
;  begin
;  Result:=1;
;  Exit;
;  end;
;if bFree then  // ñâîáîäíîå ìåñòî åñòü íà ïîëå, íî ïîñòàâèòü íèêóäà íåëüçÿ
;   begin
;   Result:=-1;
;   exit;
;   end;
;result:=0; // íåò ñâîáîäíîãî ìåñòà
;end;



;procedure CopyArray(var Dst: TSudokuBoard;Src: TSudokuBoard);
;begin
;for i:=0 to 8 do
;  for j:=0 to 8 do
;   Dst[i,j]:=Src[i,j];
;end;

CopyArray:
	push	ecx eax
	xor	ecx,ecx
@@:	mov	al,[esi+ecx]
	mov	[edi+ecx],al
	inc	ecx
	cmp	ecx,9*9
	jb	@b
	pop	eax ecx
ret



align 4
Solve:
	pushad
if DEBUG
dbg_dec esp
dbg_dec ecx
mcall 5,1
endf
	call	FindMinPoint
	cmp	[_iRet],0
	jne	@f
		mov	[_iRet],1
		popad
		ret
	@@:
	cmp	[_iRet],-1
	jne	@f
		popad
		ret
@@:
	push	esi edi
	mov	edi,TempMap
	call	CopyArray
	pop	edi esi
	mov	ecx,1
	movzx	eax, byte [Pt.mini]
	dec	al
	mov	ah,9
	mul	ah
	add	al,byte [Pt.minj]
	dec	al
.1:	mov	byte [esi+eax],cl
	call	CheckSudoku
	jnc	@f
.2:	inc	ecx
	cmp	ecx,9
	jbe	.1
;	jmp	.1
@@:	call	Solve
	cmp	[_iRet],-1
	jne	@f
	push	esi edi
	mov	edi,TempMap
	xchg	esi,edi
	call	CopyArray
	pop	edi esi
	popad
	ret
@@:	cmp	[_iRet],1
	jne	.3
	popad
	ret
.3:	mov	[_iRet],0
	popad
ret

;function Solve(var Map: TSudokuBoard): integer;
;var
;  variance: byte;
;  iRet: integer;
;begin
;// èùåì êëåòêó ñ íàèìåíüøèì ÷èñëîì êàíäèäàòîâ:
;iRet:=FindMinPoint(Pt,Map);
;if (iRet = 0) then
;   begin
;   result:=1;// ðåøåíèå íàéäåíî
;   exit;
;   end else
;if (iRet = -1) then // òóïèêîâàÿ êîìáèíàöèÿ
;     begin
;     result:=-1;
;     exit;
;     end;

;CopyArray(TempMap,Map); // ñîõðàíÿåì òî, ÷òî åñòü
;for variance:=1 to 9 do
;begin
; Map[pt.mini,pt.minj]:=variance; // ïûòàåìñÿ ñòàâèòü íà íàéäåííóþ êëåòêó öèôðû îò 1 äî 9
; if not CheckSudoku(Map) then continue; // òàêóþ öèôðó ïîñòàâèòü íåëüçÿ. Áåð¸ì ñëåäóþùóþ.
; iRet:=Solve(Map); // çàïóñêàåì ôóíêöèþ ðåêóðñèâíî
; if iRet=-1 then // òóïèêîâàÿ êîìáèíàöèÿ
;  begin
;  CopyArray(Map,tempmap); // âîññòàíàâëèâàåì ìàññèâ è áåð¸ì ñëåäóþùóþ öèôðó íà òî æå ìåñòî
;  continue;
;  end;
;if iRet=1 then // ðåøåíèå íàéäåíî
;  begin
;  Result:=1;
;  exit;
;  end;
;end;
;Result:=0;
;end;

;end.