Sudoku

Post your working scripts, libraries and tools
pekoe
Posts: 5
Joined: 25 Mar 2016, 11:42

Sudoku

25 Mar 2016, 14:13

  • Shows numbers or colors and pencil marks.
  • Detects X-wings, Y-wings, empty rectangles, Swordfish and chains and explains the solution.
  • Generates random Sudokus and creates Sudoku images.
  • 10 beautiful Sudoku images are included.

Code: Select all

#NoEnv
#singleinstance off
SendMode input
SetTitleMatchMode, 1
SetBatchLines, -1
SetMouseDelay, -1

;_____________________________________________________________________________________________
;________ basic variables ____________________________________________________________________


cells =
loop, 9
{
	row = %a_index%
	loop, 9
	{
		column = %a_index%
		cells = %cells%%row%%column%-
		cell%row%%column% = 0
		highlight%row%%column% = 0
		loop, 9
			PencilMark%row%%column%%a_index% = 0
	}
}
stringtrimright, cells, cells, 1

unit1 = 11-12-13-14-15-16-17-18-19	; rows
unit2 = 21-22-23-24-25-26-27-28-29
unit3 = 31-32-33-34-35-36-37-38-39
unit4 = 41-42-43-44-45-46-47-48-49
unit5 = 51-52-53-54-55-56-57-58-59
unit6 = 61-62-63-64-65-66-67-68-69
unit7 = 71-72-73-74-75-76-77-78-79
unit8 = 81-82-83-84-85-86-87-88-89
unit9 = 91-92-93-94-95-96-97-98-99
unit10 = 11-21-31-41-51-61-71-81-91	; columns
unit11 = 12-22-32-42-52-62-72-82-92
unit12 = 13-23-33-43-53-63-73-83-93
unit13 = 14-24-34-44-54-64-74-84-94
unit14 = 15-25-35-45-55-65-75-85-95
unit15 = 16-26-36-46-56-66-76-86-96
unit16 = 17-27-37-47-57-67-77-87-97
unit17 = 18-28-38-48-58-68-78-88-98
unit18 = 19-29-39-49-59-69-79-89-99
unit19 = 11-12-13-21-22-23-31-32-33	; blocks
unit20 = 14-15-16-24-25-26-34-35-36
unit21 = 17-18-19-27-28-29-37-38-39
unit22 = 41-42-43-51-52-53-61-62-63
unit23 = 44-45-46-54-55-56-64-65-66
unit24 = 47-48-49-57-58-59-67-68-69
unit25 = 71-72-73-81-82-83-91-92-93
unit26 = 74-75-76-84-85-86-94-95-96
unit27 = 77-78-79-87-88-89-97-98-99

loop, parse, cells, -
{
	rc = %a_loopfield%
	loop, 27
		if (a_index >= 19)  ; only blocks
			ifinstring, unit%a_index%, %rc%
	block%rc% = %a_index%
}

loop, parse, cells, -
{
	rc = %a_loopfield%
	CrossRoads%rc% =
	stringleft, r, rc, 1
	stringright, c, rc, 1
	c += 9
	b := block%rc%
	RowColumn := unit%r% . "-" . unit%c%
	loop, parse, RowColumn, -
		ifinstring, unit%b%, %a_loopfield%
			CrossRoads%rc% := CrossRoads%rc% . "-" . a_loopfield
	stringtrimleft, CrossRoads%rc%, CrossRoads%rc%, 1
	CrossRoads%rc%r = %r%
	CrossRoads%rc%c = %c%
}

loop, parse, cells, -
{
	rc = %a_loopfield%
	string =
	loop, 27
		ifinstring, unit%a_index%, %rc%
			loop, parse, unit%a_index%, -
				if a_loopfield <> %rc%
				ifnotinstring, string, %a_loopfield%
					string = %string%%a_loopfield%-
	stringtrimright, ConnectedCells%rc%, string, 1
}

color1name = white
color1value = white
color2name = yellow
color2value = yellow
color3name = orange
color3value = ff8040
color4name = red
color4value = red
color5name = purple
color5value = purple
color6name = blue
color6value = blue
color7name = light blue
color7value = aqua
color8name = green
color8value = green
color9name = black
color9value = black

cBackground1 = FFFFFF  ; background color for numbers
cBackground2 = DDEEFF  ; background color for colors
cBackground = %cBackground1%

cNumber =
loop, 9
{
	row = %a_index%
	loop, 9
	{
		column = %a_index%
		cNumber%row%%column% =
	}
}


wCell1 = 80
sNumber1 = 50
sColor1 = 54
sHighlight1 = 60
wPencilMark1 = 22
sPencilNumber1 = 14
sPencilColor1 = 12
wCaption1 = 40
sCaption1 = 20

PlusMinus = 0
switch = numbers

HistoryIndex = 0
HistoryIndexMax = 0
string = numbers-FFFFFF-
history(string)

;_____________________________________________________________________________________________
;________ GUI ________________________________________________________________________________


gui, 1:-DPIScale
if (a_screendpi > 96)
{
	sNumber1 := sNumber1*96//a_screendpi
	sColor1 := sColor1*96//a_screendpi
	sHighlight1 := sHighlight1*96//a_screendpi
	sPencilNumber1 := sPencilNumber1*96//a_screendpi
	sPencilColor1 := sPencilColor1*96//a_screendpi
}
if (a_screenheight < 10*wCell1)
	PlusMinus -= 1

loop
{
	winTitle = Sudoku %A_Index%
	IfWinNotExist, %winTitle%
		break
}
GroupAdd, SudokuWindows, %winTitle%

menu, SudokuMenu, add, &Easy and symmetrical, easy
menu, SudokuMenu, add, &Difficult but not symmetrical, difficult
menu, SudokuMenu, add, &Open..., open
menu, SudokuMenu, add, &Fix/unfix, FixUnfix
menu, SudokuMenu, add, &Save as..., SaveAs
menu, SudokuMenu, add  ; separator line
menu, SudokuMenu, add, house
menu, SudokuMenu, add, tree, tree
menu, SudokuMenu, add, autumn tree, AutumnTree
menu, SudokuMenu, add, fir trees, FirTrees
menu, SudokuMenu, add, Christmas tree, ChristmasTree
menu, SudokuMenu, add, spiral
menu, SudokuMenu, add, crown
menu, SudokuMenu, add, sun
menu, SudokuMenu, add, smiley
menu, SudokuMenu, add, heart
menu, SudokuMenu, add  ; separator line
menu, SudokuMenu, add, &Create from image..., create

menu, ViewMenu, add, &Larger	+, larger
menu, ViewMenu, add, &Smaller	-, smaller
menu, ViewMenu, add, &Color numbers	Ctrl+C, ColorNumbers
menu, ViewMenu, add, S&witch between numbers and colors, switch

menu, SolveMenu, add, Find &one	Ctrl+page down, FindOne
menu, SolveMenu, add, Find &all, FindAll

menu, PlayMenu, add, &Back	page up, back
menu, PlayMenu, add, &Forward	page down, forward
menu, PlayMenu, add, &All pencil marks, AllPencilMarks
menu, PlayMenu, add, &Pencil marks only for singles and pairs, HintPencilMarks
menu, PlayMenu, add, &Remove pencil marks, RemovePencilMarks
menu, PlayMenu, add, &Clear board, ClearBoard

menu, MenuBar, add, &Sudoku, :SudokuMenu
menu, MenuBar, add, &View, :ViewMenu
menu, MenuBar, add, &Play, :PlayMenu
menu, MenuBar, add, S&olve, :SolveMenu
menu, MenuBar, add, &Help, help

gui, 1:menu, MenuBar

menu, LeftMouseMenu, add
menu, RightMouseMenu, add

loop, parse, cells, -
{
	gui, 1:add, text, vGridCell%a_loopfield% -background, g
	; G in Webdings makes the grid. Without Webdings, -background makes the grid.
	gui, 1:add, text, vhighlight%a_loopfield%
	gui, 1:add, text, vcell%a_loopfield% +center backgroundtrans
	loop, 9
		gui, 1:add, text, vPencilMark%a_loopfield%%a_index% +center backgroundtrans
}
caption123 = 1-2-3-4-5-6-7-8-9
loop, parse, caption123, -
	gui, 1:add, text, vcaption123%a_loopfield% +center
captionABC = A-B-C-D-E-F-G-H-I
loop, parse, captionABC, -
	gui, 1:add, text, vcaptionABC%a_loopfield% +center

gosub CellsSize
gui, 1:color, %cBackground%
gui, 1:show, w%wGui% h%wGui%, %winTitle%  ; GuiSize is launched

today = %A_MM%%A_DD%
if (today >= 1224 or today <= 0106)
	gosub ChristmasTree

return

;_____________________________________________________________________________________________
;________ gui events _________________________________________________________________________


GuiClose:
something = 0
loop, parse, cells, -
{
	if (cell%a_loopfield% <> 0)
		something += 1
	else loop, 9
		if (PencilMark%a_loopfield%%a_index% = 1)
			something += 1
}
if something > 3
{
	msgbox, 0x2003,, Do you want to save the current situation?
	IfMsgBox Yes
		gosub SaveAs
	IfMsgBox Cancel
		return
}
exitapp

;---------------------------------------------------------------------------------------------

GuiSize:
wingetpos,,,, winheight, %winTitle% ahk_class AutoHotkeyGUI
hTitleMenu := winheight-a_guiheight
return

;_____________________________________________________________________________________________
;________ keyboard hotkeys ___________________________________________________________________


; ---- get a color for numbers ---------------------------------------------------------------

^!lbutton::
mousegetpos, x, y
pixelgetcolor, cNumber, x, y, RGB
return

; --------------------------------------------------------------------------------------------

#ifwinactive ahk_group SudokuWindows ahk_class AutoHotkeyGUI

~Esc::
tooltip
if guitip = 1
{
	gui, 5:destroy
	guitip = 0
}
return

;---- move the mouse cursor ------------------------------------------------------------------

~left::
~right::
~up::
~down::
stringtrimleft, key, a_thishotkey, 1
if key = left
{
	hor = -1
	ver = 0
}
else if key = right
{
	hor = 1
	ver = 0
}
else if key = up
{
	hor = 0
	ver = -1
}
else if key = down
{
	hor = 0
	ver = 1
}
mousegetpos x0, y0
xm := x0 + hor*wCell
ym := y0 + ver*wCell
gosub xyGetNearestCell
if (x0 <> xcenter or y0 <> ycenter)
	click %xcenter%, %ycenter%, 0
return

;---- set numbers/colors ---------------------------------------------------------------------

1::
2::
3::
4::
5::
6::
7::
8::
9::
numpad1::
numpad2::
numpad3::
numpad4::
numpad5::
numpad6::
numpad7::
numpad8::
numpad9::
stringright, n, a_thislabel, 1
if CreateIndex = 4
	gosub swap
else ifnotinstring, fixed, %rm%%cm%
{
	gosub MouseGetNearestCell
	valid = 1
	loop, parse, ConnectedCells%rm%%cm%, -
		if (cell%a_loopfield% = n)
		{
			valid = 0
			break
		}
	if valid = 1
	{
		fill(rm . cm, n)
		loop, parse, ConnectedCells%rm%%cm%, -
			PencilMark(a_loopfield, n, 0)
		HintPencilMarks("refresh")
		history("gui")
	}
	else
	{
		fixed  = %fixed%-%rm%%cm%
		fill(rm . cm, n)
		history("gui")
		sleep 200
		gosub back
		del := HistoryIndex + 1
		history%del% =
		HistoryIndexMax = %HistoryIndex%
		stringtrimright, fixed, fixed, 3
	}
}
return

swap:
if swap1 =
	swap1 = %n%
else if (n = swap1)
{
	swap1 =
	tooltip
}
else
{
	swap2 = %n%
	tooltip
	loop, parse, cells, -
	{
		if (cell%a_loopfield% = swap1)
			fill(a_loopfield, swap2)
		else if (cell%a_loopfield% = swap2)
			fill(a_loopfield, swap1)
	}
	history("gui")
	swap1 =
	swap2 =
}
return

;---- color numbers --------------------------------------------------------------------------

^v::
if (switch = "numbers" and cNumber <> "")
{
	gosub MouseGetNearestCell
	if (cell%rm%%cm% <> 0)
	{
		gui, 1:font, c%cNumber% s%sNumber%
		gui, 1:font,, Ubuntu
		gui, 1:font,, Arial
		guicontrol, 1:font, cell%rm%%cm%
		cNumber%rm%%cm% = %cNumber%
	}
}
return

;---- set/delete pencil marks ----------------------------------------------------------------

+1::  ; set/delete a single pencil mark
+2::
+3::
+4::
+5::
+6::
+7::
+8::
+9::
+numpad1::
+numpad2::
+numpad3::
+numpad4::
+numpad5::
+numpad6::
+numpad7::
+numpad8::
+numpad9::
gosub MouseGetNearestCell
stringright, n, a_thislabel, 1
if cell%rm%%cm% = 0
{
	if PencilMark%rm%%cm%%n% = 0
	{
		valid = 1
		loop, parse, ConnectedCells%rm%%cm%, -
			if (cell%a_loopfield% = n)
			{
				valid = 0
				break
			}
		if valid = 1
		{
			PencilMark(rm . cm, n, 1)
			history("gui")
		}
		else
		{
			cell%rm%%cm% = x
			PencilMark(rm . cm, n, 1)
			history("gui")
			sleep 200
			gosub back
			del := HistoryIndex + 1
			history%del% =
			HistoryIndexMax = %HistoryIndex%
			cell%rm%%cm% = 0
		}
	}
	else
	{
		PencilMark(rm . cm, n, 0)
		history("gui")
	}
}
return

p::  ; set/delete all pencil marks from one cell
if CreateIndex = 1
{
	gosub MouseGetNearestCell
	fill(rm . cm, 0)
	loop, 9
	{
		i = %a_index%
		valid = 1
		loop, parse, ConnectedCells%rm%%cm%, -
			if (cell%a_loopfield% = i)
			{
				valid = 0
				break
			}
		if valid = 1
			PencilMark(rm . cm, i, 1)
	}
	history("gui")
}
return

del & 1::  ; delete one pencil mark from all cells
del & 2::
del & 3::
del & 4::
del & 5::
del & 6::
del & 7::
del & 8::
del & 9::
del & numpad1::
del & numpad2::
del & numpad3::
del & numpad4::
del & numpad5::
del & numpad6::
del & numpad7::
del & numpad8::
del & numpad9::
if CreateIndex = 1
{
	stringright, n, a_thislabel, 1
	loop, parse, cells, -
		PencilMark(a_loopfield, n, 0)
	history("gui")
}
return

;---- delete number/color/pencil marks from one cell -----------------------------------------

space::
gosub MouseGetNearestCell
if cell%rm%%cm% <> 0
ifinstring, fixed, %rm%%cm%
	return
fill(rm . cm, 0)
history("gui")
return

;_____________________________________________________________________________________________
;________ mouse hotkeys ______________________________________________________________________


;---- set and delete numbers and colors and pencil marks -------------------------------------

~lbutton::
gosub MouseGetNearestCell
wingetpos,,, width, height, %winTitle% ahk_class AutoHotkeyGUI
if (xm > 0 and xm < width and ym > hTitleMenu and ym < height)
{
	sleep 40  ; doesn't work without, don't know why
	empty = 1
	if cell%rm%%cm% <> 0
		empty = 0
	else loop, 9
		if PencilMark%rm%%cm%%a_index% = 1
			empty = 0
	if (CreateIndex = 1 and empty = 1)
	{
		loop, 9
		{
			i = %a_index%
			valid = 1
			loop, parse, ConnectedCells%rm%%cm%, -
				if (cell%a_loopfield% = i)
				{
					valid = 0
					break
				}
			if valid = 1
				PencilMark(rm . cm, i, 1)
		}
		history("gui")
	}
	else if CreateIndex = 4
	{
		if (cell%rm%%cm% <> 0 and swap1 = "")
		{
			swap1 := cell%rm%%cm%
			if switch = numbers
				text = %swap1%
			else
				text := color%swap1%name
			tooltip, Swap %text% and ...
		}
		else if (cell%rm%%cm% <> 0 and cell%rm%%cm% = swap1)
		{
			swap1 =
			tooltip
		}
		else if (cell%rm%%cm% <> 0 and swap1 <> "" and cell%rm%%cm% <> swap1)
		{
			swap2 := cell%rm%%cm%
			tooltip
			loop, parse, cells, -
			{
				if (cell%a_loopfield% = swap1)
					fill(a_loopfield, swap2)
				else if (cell%a_loopfield% = swap2)
					fill(a_loopfield, swap1)
			}
			history("gui")
			swap1 =
			swap2 =
		}
	}
	else ifnotinstring, fixed, %rm%%cm%
	{
		menu, LeftMouseMenu, deleteall
		loop, 9
		{
			n = %a_index%
			valid = 1
			loop, parse, ConnectedCells%rm%%cm%, -
				if cell%a_loopfield% = %n%
			{
				valid = 0
				break
			}
			if valid = 1
			{
				if switch = colors
					item := color%n%name
				else
					item = %n%
				menu, LeftMouseMenu, add, %item%, SetDeleteNumber
				if (cell%rm%%cm% = n)
					menu, LeftMouseMenu, check, %item%
			}
		}
		menu, LeftMouseMenu, show
	}
}
return

~rbutton::
gosub MouseGetNearestCell
wingetpos,,, width, height, %winTitle% ahk_class AutoHotkeyGUI
if (xm > 0 and xm < width and ym > hTitleMenu and ym < height)
{
	sleep 40
	menu, RightMouseMenu, deleteall
	if (cell%rm%%cm% = 0)  ; menu to set/delete pencil marks
	{
		loop, 9
		{
			n = %a_index%
			valid = 1
			loop, parse, ConnectedCells%rm%%cm%, -
				if cell%a_loopfield% = %n%
			{
				valid = 0
				break
			}
			if valid = 1
			{
				if switch = colors
					item := "pencil mark " . color%a_index%name
				else
					item := "pencil mark " . a_index
				menu, RightMouseMenu, add, %item%, SetDeletePencilMark
				if PencilMark%rm%%cm%%a_index% = 0
					menu, RightMouseMenu, uncheck, %item%
				else
					menu, RightMouseMenu, check, %item%
			}
		}
	}
	menu, RightMouseMenu, show
}
return

SetDeleteNumber:
loop, 9
	if (a_thismenuitem = a_index or a_thismenuitem = color%a_index%name)
{
	n = %a_index%
	if (cell%rm%%cm% <> n)
	{
		fill(rm . cm, n)
		loop, parse, ConnectedCells%rm%%cm%, -
			PencilMark(a_loopfield, n, 0)
	}
	else
		fill(rm . cm, 0)
	HintPencilMarks("refresh")
	history("gui")
	break
}
return

SetDeletePencilMark:
stringtrimleft, NumberOrColor, a_thismenuitem, 12  ; omit "pencil mark "
loop, 9
	if (NumberOrColor = a_index or NumberOrColor = color%a_index%name)
{
	if PencilMark%rm%%cm%%a_index% = 0
		PencilMark(rm . cm, a_index, 1)
	else
		PencilMark(rm . cm, a_index, 0)
	history("gui")
	break
}
return

;_____________________________________________________________________________________________
;________ gui subroutines and hotkeys ________________________________________________________


;---- generate an easy Sudoku ----------------------------------------------------------------

easy:
progress, b zh0 fm20 wm400,, Please wait ...
loop, parse, cells, -
	fill(a_loopfield, 0)
gosub FillRandom
loop, parse, cells, -
	full%a_loopfield% := cell%a_loopfield%
NotYetOmitted = %cells%-  ; The trailing - is needed for stringreplace. <----
;---- omit numbers ----
; Omit numbers found by FillRandom if there was no choice.
sort, NotYetOmitted, random d-
AlreadyLooped =
loop, parse, NotYetOmitted, -
	if a_loopfield <>
	ifnotinstring, AlreadyLooped, %a_loopfield%
{
	stringleft, r, a_loopfield, 1
	stringright, c, a_loopfield, 1
	sym1 := r . 10-c
	sym2 := 10-r . c
	sym3 := 10-r . 10-c
	sym4 := c . r
	sym5 := c . 10-r
	sym6 := 10-c . r
	sym7 := 10-c . 10-r
	AlreadyLooped = %AlreadyLooped%%sym1%-%sym2%-%sym3%-%sym4%-%sym5%-%sym6%-%sym7%-
	ifinstring, NoChoice, %a_loopfield%
	ifinstring, NoChoice, %sym1%
	ifinstring, NoChoice, %sym2%
	ifinstring, NoChoice, %sym3%
	ifinstring, NoChoice, %sym4%
	ifinstring, NoChoice, %sym5%
	ifinstring, NoChoice, %sym6%
	ifinstring, NoChoice, %sym7%
	{
		fill(a_loopfield, 0)
		fill(sym1, 0)
		fill(sym2, 0)
		fill(sym3, 0)
		fill(sym4, 0)
		fill(sym5, 0)
		fill(sym6, 0)
		fill(sym7, 0)
		stringreplace, NotYetOmitted, NotYetOmitted, %a_loopfield%-,  ; <----
		stringreplace, NotYetOmitted, NotYetOmitted, %sym1%-,
		stringreplace, NotYetOmitted, NotYetOmitted, %sym2%-,
		stringreplace, NotYetOmitted, NotYetOmitted, %sym3%-,
		stringreplace, NotYetOmitted, NotYetOmitted, %sym4%-,
		stringreplace, NotYetOmitted, NotYetOmitted, %sym5%-,
		stringreplace, NotYetOmitted, NotYetOmitted, %sym6%-,
		stringreplace, NotYetOmitted, NotYetOmitted, %sym7%-,
	}
}
; Omit numbers found by GetPossibleNumbers if there was no choice.
AlreadyLooped =
loop, parse, NotYetOmitted, -
	if a_loopfield <>
	ifnotinstring, AlreadyLooped, %a_loopfield%
{
	stringleft, r, a_loopfield, 1
	stringright, c, a_loopfield, 1
	sym1 := r . 10-c
	sym2 := 10-r . c
	sym3 := 10-r . 10-c
	sym4 := c . r
	sym5 := c . 10-r
	sym6 := 10-c . r
	sym7 := 10-c . 10-r
	AlreadyLooped = %AlreadyLooped%%sym1%-%sym2%-%sym3%-%sym4%-%sym5%-%sym6%-%sym7%-
	cell%a_loopfield% = 0
	cell%sym1% = 0
	cell%sym2% = 0
	cell%sym3% = 0
	cell%sym4% = 0
	cell%sym5% = 0
	cell%sym6% = 0
	cell%sym7% = 0
	GetAll = 1
	gosub GetPossibleNumbers
	GetAll = 0
	AllSym = 0
	ifinstring, WhatNext, 1%a_loopfield%
	ifinstring, WhatNext, 1%sym1%
	ifinstring, WhatNext, 1%sym2%
	ifinstring, WhatNext, 1%sym3%
	ifinstring, WhatNext, 1%sym4%
	ifinstring, WhatNext, 1%sym5%
	ifinstring, WhatNext, 1%sym6%
	ifinstring, WhatNext, 1%sym7%
		AllSym = 1
	if AllSym = 1
	{
		fill(a_loopfield, 0)
		fill(sym1, 0)
		fill(sym2, 0)
		fill(sym3, 0)
		fill(sym4, 0)
		fill(sym5, 0)
		fill(sym6, 0)
		fill(sym7, 0)
	}
	else
	{
		cell%a_loopfield% := full%a_loopfield%
		cell%sym1% := full%sym1%
		cell%sym2% := full%sym2%
		cell%sym3% := full%sym3%
		cell%sym4% := full%sym4%
		cell%sym5% := full%sym5%
		cell%sym6% := full%sym6%
		cell%sym7% := full%sym7%
	}
}
fix("green")
history("gui")
progress, off
return

;---- generate a difficult Sudoku ------------------------------------------------------------

difficult:
progress, b fm20 wm400 R0-276,, Please wait ...
pos = 0
loop, parse, cells, -
	fill(a_loopfield, 0)
gosub FillRandom
loop, parse, cells, -
	full%a_loopfield% := cell%a_loopfield%
;---- Try for each number if there is still only one solution when omitted. ----
RandomCells = %cells%
sort, RandomCells, random d-
loop, parse, RandomCells, -
{
	if a_index < 4
	{
		fill(a_loopfield, 0)
		continue
	}
	TryOmit = %a_loopfield%
	cell%TryOmit% = 0
	DontDisplay = 1
	StopAt = 1
	gosub FillMinimumFirst
	DontDisplay = 0
	StopAt = 0
	Still1Solution = 0
	if (filled = NoChoice)
		Still1Solution = 1
	else
	{
		FirstSolutionIdentical = 1
		loop, parse, cells, -
			if (FirstSolution%a_loopfield% <> full%a_loopfield%)
		{
			FirstSolutionIdentical = 0
			break
		}
		if FirstSolutionIdentical = 1
		{
			DontDisplay = 1
			gosub FillMaximumFirst
			DontDisplay = 0
			if SecondSolutionIdentical = 1
				Still1Solution = 1
		}
	}
	loop, parse, cells, -
	{
		if (a_loopfield = TryOmit)
		{
			if Still1Solution = 1
				fill(a_loopfield, 0)
			else
				cell%a_loopfield% := full%a_loopfield% 
		}
		else
			cell%a_loopfield% := FillMinimumFirst%a_loopfield%
	}
	if a_index < 60
		pos += 1
	else
		pos += 10
	progress, %pos%
}
fix("green")
history("gui")
progress, off
return

;---- open -----------------------------------------------------------------------------------

open:
ifnotexist, %a_desktop%\Sudoku
	FileCreateDir, %a_desktop%\Sudoku
FileSelectFile, Sudoku,, %a_desktop%\Sudoku,, *.txt
if errorlevel = 0
{
	if fixed <>
		unfix()
	fileread, string, %Sudoku%
	StringToGui(string)
	history(string)
}
return

;---- fix/unfix ------------------------------------------------------------------------------

FixUnfix:
if fixed =
	fix("green")
else
	unfix()
return

;---- save as --------------------------------------------------------------------------------

SaveAs:
ifnotexist, %a_desktop%\Sudoku
	FileCreateDir, %a_desktop%\Sudoku
FileSelectFile, Sudoku, S16, %a_desktop%\Sudoku,, *.txt
if errorlevel = 0
{
	string := GuiToString()
	stringright, extension, Sudoku, 4
	if (extension <> ".txt")
		Sudoku = %Sudoku%.txt
	ifexist, %Sudoku%
		filedelete, %Sudoku%
	fileappend, %string%, %Sudoku%
}
return

;---- house ----------------------------------------------------------------------------------

house:
string =
(Join
numbers-FFFFFF--152-244-261-334-371-424-481-528-567-579
-584-622-633-649-668-685-723-742-769-778
-786-825-846-883-929-943-982
)
StringToGui(string)
fix(777777)
history(string)
return

;---- tree ----------------------------------------------------------------------------------

tree:
string =
(Join
numbers-FFFFFF-
13green,14green,15green,16green,22green,27green,31green,38green,41green,48green,51green,
58green,62green,67green,73green,76green,
74804000,75804000,84804000,85804000,94804000,95804000
-134-149-157-166-223-276-318-385-415-481-511-584-628-677-736-743-754-767-842-855-941-956
)
StringToGui(string)
fix("")
history(string)
return

;---- autumn tree ---------------------------------------------------------------------------

AutumnTree:
string =
(Join
numbers-FFFFFF-
13FF6400,14FFB700,157D7327,16FFB700,22FF4000,27FF6400,31FF6400,38FF4000,41FFB700,48FF6400,
517D7327,58FFB700,62FFB700,677D7327,73FF6400,74654000,75654000,76FFB700,84654000,85654000,
94654000,95654000
-133-144-159-165-226-275-317-381-412-483-511-588-628-679-735-743-756-769-842-855-941-954
)
StringToGui(string)
fix("")
history(string)
return

;---- fir trees -----------------------------------------------------------------------------

FirTrees:
string =
(Join
numbers-FFFFFF-
13006000,23006000,2700A000,32006000,34006000,3700A000,42006000,44006000,4600A000,4800A000,
51006000,55006000,5600A000,5800A000,61006000,65006000,6900A000,76006000,7700A000,7800A000,
7900A000,81006000,82006000,83654000,84006000,85006000,86006000,87654000,93654000
-131-232-271-327-341-372-423-448-467-484-517-551-563-585-618-659-691-761-773-788-795-819-828
-833-846-855-862-874-934
)
StringToGui(string)
fix("")
history(string)
return

;---- Christmas tree -------------------------------------------------------------------------

ChristmasTree:
string =
(Join
colors-%cBackground2%--114-152-196-251-343-364-448-465-532-578
-637-673-721-788-828-835-842-857-863-871
-884-959
)
StringToGui(string)
fix("")
history(string)
return

;---- spiral ---------------------------------------------------------------------------------

spiral:
string =
(Join
numbers-FFFFFF-
54ffff00,45ffb700,56ff6e00,66ff2500,75ff0024,74ff006d,73ff00b6,
62ff00ff,52b700ff,426e00ff,332500ff,240024ff,25006dff,2600b6ff,
3700ffff,4800ffb7,5800ff6e,6800ff25,7824ff00,876dff00,96b6ff00
-248-257-262-331-379-425-456-483-528-541
-563-582-624-669-687-735-742-753-786-874
-961
)
StringToGui(string)
fix("")
history(string)
return

;---- crown ----------------------------------------------------------------------------------

crown:
string =
(Join
colors-DDEEFF--216-254-298-312-323-345-368-384-396-413
-432-476-495-514-592-618-651-694-717-791
-811-828-834-842-859-866-873-885-897
)
StringToGui(string)
fix("")
history(string)
return

;---- sun ------------------------------------------------------------------------------------

sun:
string =
(Join
colors-%cBackground2%--136-168-193-242-263-287-351-372-411-426
-435-443-482-498-552-571-644-661-683-734
-762-797-823-866-912-967
)
StringToGui(string)
fix("")
history(string)
return

;---- smiley ----------------------------------------------------------------------------------

smiley:
string =
(Join
numbers-ffff50-
-147-155-161-231-278-327-346-369-381-428-484-525-536-573-587-621-642-657-664-685-733-771-845
-853-862
)
StringToGui(string)
fix(777777)
history(string)
return

;---- heart ----------------------------------------------------------------------------------

heart:
string =
(Join
numbers-FFFFFF-
22cc0000,23cc0000,27cc0000,28cc0000,31cc0000,34cc0000,36cc0000,39cc0000,41cc0000,45cc0000,
49cc0000,51cc0000,59cc0000,62cc0000,68cc0000,73cc0000,77cc0000,84cc0000,86cc0000,95cc0000
-224-235-276-283-317-342-368-391-415-458-492-511-597-626-681-734-778-841-867-954
)
StringToGui(string)
fix("")
history(string)
return

;---- create ---------------------------------------------------------------------------------

create:
CreateIndex = 1
gui, 3:destroy
gui, 2:font, s12
gui, 2:add, text,,
(
Paint an image with pencil marks. You can preset some %switch%.
There must be pencil marks or preset %switch% in at least 17 cells.
The program will try to create a Sudoku from your image:
Empty cells will be left empty, preset %switch% will not be changed,
cells with pencil marks will be filled with one of the pencil mark %switch%.
The left mouse button and the P key are the main painting tools:
They set all possible pencil marks in a cell.
Preset %switch% with the left mouse button or the number keys.
Delete preset %switch% with the left mouse button or the spacebar.
Set and delete single pencil marks with the right mouse button or Shift+number key.
You can delete one pencil mark from all cells with Delete+number key.
)
gui, 2:add, text, xs, 1 = %color1name%
gui, 2:add, text, xp+120, 2 = %color2name%
gui, 2:add, text, xp+120, 3 = %color3name%
gui, 2:add, text, xp+120, 4 = %color4name%
gui, 2:add, text, xp+120, 5 = %color5name%
gui, 2:add, text, xs, 6 = %color6name%
gui, 2:add, text, xp+120, 7 = %color7name%
gui, 2:add, text, xp+120, 8 = %color8name%
gui, 2:add, text, xp+120, 9 = %color9name%

gui, 2:add, button, xs y+20, Create Sudoku
gui, 2:add, button, x+20, Cancel
if guiX =
	guiX = 10
if guiY =
	guiY = 10
gui, 2:show, x%guiX% y%guiY%, Paint an image ...
return

2GuiClose:
2ButtonCancel:
wingetpos, guiX, guiY,,, A
gui, 2:destroy
CreateIndex = 0
return

2ButtonCreateSudoku:
wingetpos, guiX, guiY,,, A
winactivate, %winTitle%
CreateIndex = 2
image =
loop, parse, cells, -
{
	if (cell%a_loopfield% <> 0)
		image = %image%%a_loopfield%-
	else loop, 9
		if (PencilMark%a_loopfield%%a_index% = 1)
	{
		image = %image%%a_loopfield%-
		break
	}
}
stringtrimright, image, image, 1
ImageLen = 0  ;---- less than 17 cells? ----
loop, parse, image, -
	ImageLen += 1
if (ImageLen < 17)
{
	msgbox There must be %switch% or pencil marks in at least 17 cells.
	CreateIndex = 1
	return
}
missing = 123456789  ;---- two numbers missing completely? ----
loop, parse, Image, -
{
	n := cell%a_loopfield%
	stringreplace, missing, missing, %n%,
	loop, 9
	{
		n := PencilMark%a_loopfield%%a_index% 
		if (n = 1)
			stringreplace, missing, missing, %a_index%,
	}
}
stringlen, missingLen, missing
if (missingLen >= 2)
{
	stringleft, missing1, missing, 1
	stringmid, missing2, missing, 2, 1
	if switch = colors
	{
		missing1 := color%missing1%name
		missing2 := color%missing2%name
	}
	msgbox, There can be no unique solution because %missing1% and %missing2% are missing completely and could be swapped.
	CreateIndex = 1
	return
}
loop, 6  ;---- two rows or columns in the same blocks completely empty? ----
{
	i1 := a_index * 3 - 3
	unitA =
	loop, 3
	{
		i2 := i1 + a_index
		empty = 1
		loop, parse, unit%i2%, -
			ifinstring, image, %a_loopfield%
		{
			empty = 0
			break
		}
		if empty = 1
		{
			if (i2 > 9)
				unitB := "column " . (i2 - 9)
			else
				unitB = row %i2%
			if unitA =
				unitA = %unitB%
			else
			{
				msgbox, There can be no unique solution because %unitA% and %unitB% are completely empty and could be swapped.
				CreateIndex = 1
				return
			}
		}
	}
}
loop, 27  ;---- more than n cells with only n possible numbers in one unit? ----
{
	u = %a_index%
	loop, 8
	{
		lenPencilCells := a_index+1
		PencilCells =
		loop, %lenPencilCells%
			PencilCells = %PencilCells%%a_index%
		loop
		{
			InImage = 1
			NotEmpty = 1
			PencilMarks =
			loop, parse, PencilCells
			{
				if (u <= 9)
				{
					row = %u%
					column := a_loopfield
				}
				else if (u <= 18)
				{
					row := a_loopfield
					column := u-9
				}
				else
				{
					block := u-18
					if (block <= 3)
						row = 1
					else if (block <= 6)
						row = 4
					else
						row = 7
					if (block = 1 or block = 4 or block = 7)
						column = 1
					else if (block = 2 or block = 5 or block = 8)
						column = 4
					else
						column = 7
					if (a_loopfield > 6)
						row += 2
					else if (a_loopfield > 3)
						row += 1
					if (a_loopfield = 2 or a_loopfield = 5 or a_loopfield = 8)
						column += 1
					else if (a_loopfield = 3 or a_loopfield = 6 or a_loopfield = 9)
						column += 2
				}
				ifnotinstring, image, %row%%column%
				{
					InImage = 0
					break
				}
				if cell%row%%column% <> 0
				{
					NotEmpty = 0
					break
				}
				loop, 9
					if PencilMark%row%%column%%a_index% = 1
					ifnotinstring, PencilMarks, %a_index%
						PencilMarks = %PencilMarks%%a_index%
			}
			if (InImage = 1 and NotEmpty = 1)
			{
				stringlen, lenPencilMarks, PencilMarks
				if (lenPencilMarks < lenPencilCells)
				{
					PencilCellsText = cells
					loop, parse, PencilCells
						PencilCellsText = %PencilCellsText% %a_loopfield% and
					stringtrimright, PencilCellsText, PencilCellsText, 4
					if (u <= 9)
						unit := "row " . u
					else if (u <= 18)
						unit := "column " . u-9
					else
						unit := "block " . u-18
					msgbox, In %PencilCellsText% in %unit% there are only %lenPencilMarks% possible %switch%, so one cell can't be filled.
					CreateIndex = 1
					return
				}
			}
			PencilCellsR =
			loop, parse, PencilCells
				PencilCellsR := a_loopfield . PencilCellsR
			FirstPossibleIncrease =
			loop, parse, PencilCellsR
				if (a_loopfield < 10-a_index)
				{
					FirstPossibleIncrease := lenPencilCells+1-a_index
					break
				}
			if FirstPossibleIncrease =
				break
			PencilCellsNew =
			loop, parse, PencilCells
			{
				if (a_index < FirstPossibleIncrease)
					PencilCellsNew := PencilCellsNew . a_loopfield
				else if (a_index = FirstPossibleIncrease)
				{
					increase := a_loopfield+1
					PencilCellsNew := PencilCellsNew . increase
				}
				else
				{
					increase += 1
					PencilCellsNew := PencilCellsNew . increase
				}
			}
			PencilCells = %PencilCellsNew%
		}
	}
}
PresetImage =
PencilImage =
loop, parse, image, -
	if (cell%a_loopfield% <> 0)
		PresetImage = %PresetImage%%a_loopfield%-
	else
		PencilImage = %PencilImage%%a_loopfield%-
stringtrimright, PresetImage, PresetImage, 1
stringtrimright, PencilImage, PencilImage, 1
if PencilImage =  ;---- no pencil marks? ----
{
	msgbox,
(
There are no pencil marks.
There have to be pencil marks so that the Sudoku creator can try different %switch%.
)
	CreateIndex = 1
	return
}
loop, parse, cells, -
	DeletedNumbers%a_loopfield% =
loop, parse, PencilImage, -
	loop, 9
		if (PencilMark%a_loopfield%%a_index% = 0)
			DeletedNumbers%a_loopfield% := DeletedNumbers%a_loopfield% . a_index
gosub FillRandom
if SolutionAtAll = 0
{
	msgbox, There is no solution.
	CreateIndex = 1
	return
}
gosub LeaveImage
gui, 2:destroy
CreateIndex = 3
interrupt = 0
examined = 0
NoSolution = 0
LastPossible = 0
DontRepeatList =
loop							;---- START CHANGING NUMBERS ----
{
	FirstIndex = %a_index%
	if (FirstIndex - LastPossible > 2)
	{
		CreateIndex = 4
		history("gui")
		gosub back
SoundBeep, 480, 240
sleep 80
SoundBeep, 480, 240
sleep 80
SoundBeep, 720, 240
sleep 80
SoundBeep, 720, 240
sleep 80
SoundBeep, 768, 240
sleep 80
SoundBeep, 768, 240
sleep 80
SoundBeep, 720, 400
		guicontrol, 3:text, Gui3Text, Can't create a Sudoku with a unique solution.
		return
	}
	loop, parse, PencilImage, -
	{
		PencilImageLoopfield = %a_loopfield%
		PencilImageIndex = %a_index%
		stringleft, PencilImageLoopfieldL, PencilImageLoopfield, 1
		stringright, PencilImageLoopfieldR, PencilImageLoopfield, 1
		if (FirstIndex = 1 and PencilImageIndex = 1)
		{
			gui, 3:font, s12
			gui, 3:add, text, vGui3Text w500,
(
Loop 1, row %PencilImageLoopfieldL%, column %PencilImageLoopfieldR%
Examined positions:
Cells with no unique solution:

Please wait, this can take some time ...




)
			gui, 3:add, button,, Cancel
			gui, 3:show, x%guiX% y%guiY% w520, Create a Sudoku ...
		}
		else
			guicontrol, 3:text, Gui3Text,
(
Loop %FirstIndex%, row %PencilImageLoopfieldL%, column %PencilImageLoopfieldR%
Examined positions: %examined%
Cells with no unique solution: %DiffMin%

Please wait, this can take some time ...
)
		if interrupt = 1
		{
			gui, 3:destroy
			CreateIndex = 0
			history("gui")
			return
		}
		else if interrupt = 2
		{
			history("gui")
			gosub back
			gosub create
			return
		}
		DontRepeatString =
		loop, parse, PencilImage, -
			if (a_loopfield <> PencilImageLoopfield)
				DontRepeatString := DontRepeatString . cell%a_loopfield%
			else
				DontRepeatString = %DontRepeatString%X
		ifinstring, DontRepeatList, %DontRepeatString%
		{
			results := %DontRepeatString%  ; results is the value of the value of DontRepeatString!
			if (results <> "")
			{
				LastPossible := FirstIndex
				loop, parse, results, -
				{
					NextResult = %a_loopfield%
					break
				}
				loop, parse, NextResult, /
					if (a_index = 1)
						DiffMin = %a_loopfield%
					else
						PencilImageString = %a_loopfield%
				loop, parse, PencilImage, -
				{
					stringmid, n, PencilImageString, a_index, 1
					fill(a_loopfield, n)
				}
				stringlen, len, NextResult
				stringtrimleft, results, results, len+1
				%DontRepeatString% := results
			}
			continue
		}
		DontRepeatList = %DontRepeatList%%DontRepeatString%`n
		missing = 123456789
		loop, parse, Image, -
			if (a_loopfield <> PencilImageLoopfield)
			{
				n := cell%a_loopfield%
				stringreplace, missing, missing, %n%,
			}
		stringlen, missingLen, missing
		if (missingLen >= 2)
			possible = %missing%
		else
			possible = 123456789
		if (FirstIndex = 1 and PencilImageIndex = 1)
			results =
		else
		{
			if DiffMin <>
			{
				PencilImageString =
				loop, parse, PencilImage, -
					PencilImageString := PencilImageString . cell%a_loopfield%
				results := DiffMin . "/" . PencilImageString . "-"
			}
			else
				results =
			n := cell%PencilImageLoopfield%
			stringreplace, possible, possible, %n%,
		}
		if DeletedNumbers%PencilImageLoopfield% <>
			loop, parse, DeletedNumbers%PencilImageLoopfield%
				stringreplace, possible, possible, %a_loopfield%,
		loop, parse, PresetImage, -
			ifinstring, ConnectedCells%PencilImageLoopfield%, %a_loopfield%
			{
				n := cell%a_loopfield%
				stringreplace, possible, possible, %n%,
			}
		if possible <>
		{
			LastPossible := FirstIndex
			loop, parse, PencilImage, -
			{
				stringlen, possibleLen, possible
				if (possibleLen <= 2)
					break
				ifinstring, ConnectedCells%PencilImageLoopfield%, %a_loopfield%
				{
					n := cell%a_loopfield%
					stringreplace, possible, possible, %n%,
				}
			}
		}
		if possible <>
		{
			PencilImageString1 =
			loop, parse, PencilImage, -
				PencilImageString1 := PencilImageString1 . cell%a_loopfield%
			loop, parse, possible
			{
				if interrupt = 1
				{
					gui, 3:destroy
					CreateIndex = 0
					history("gui")
					return
				}
				else if interrupt = 2
				{
					history("gui")
					gosub back
					gosub create
					return
				}
				if SwitchAfterLoopIteration = 1
				{
					SwitchAfterLoopIteration = 0
					gosub switch2
				}
				PossLoopfield = %a_loopfield%
				fill(PencilImageLoopfield, PossLoopfield)
				ChangeConnectedCells = 0
				loop, parse, PencilImage, -
					ifinstring, ConnectedCells%PencilImageLoopfield%, %a_loopfield%
					if (cell%a_loopfield% = PossLoopfield)
					{
						fill(a_loopfield, 0)
						ChangeConnectedCells = 1
					}
				if ChangeConnectedCells = 1
				{
					gosub FillRandom
					gosub LeaveImage
				}
				examined += 1
				ChangePencilImage = 0
				gosub FillMinimumFirst
				if SolutionAtAll = 0
				{
					NoSolution += 1
					if (NoSolution/examined > 1/2)
						loop, parse, PencilImage, -
							if cell%a_loopfield% <> 0
							{
								fill(a_loopfield, 0)
								ChangePencilImage = 1
								gosub FillRandom
								if SolutionAtAll = 1
								{
									gosub LeaveImage
									gosub FillMinimumFirst
									break
								}
							}
				}
				if SolutionAtAll = 1
				{
					gosub FillMaximumFirst
					gosub LeaveImage
					if SecondSolutionIdentical = 1
					{
						CreateIndex = 4
						history("gui")
SoundBeep, 480, 240
sleep 80
SoundBeep, 480, 240
sleep 80
SoundBeep, 720, 240
sleep 80
SoundBeep, 720, 240
sleep 80
SoundBeep, 800, 240
sleep 80
SoundBeep, 800, 240
sleep 80
SoundBeep, 720, 400
						guicontrol, 3:text, Gui3Text,
(
Loop %FirstIndex%, row %PencilImageLoopfieldL%, column %PencilImageLoopfieldR%
Examined positions: %examined%

Ready! You can improve the image in two ways:
1. Swap %switch%. Simply click on %switch% you want to swap, you can do that as long as this window is open.
2. Color numbers with "Color numbers" in the View menu. You can do that now or later.
)
						gui, 3:add, button, x+20, Save
						return
					}
					else
					{
						PencilImageString =
						loop, parse, PencilImage, -
							PencilImageString := PencilImageString . cell%a_loopfield%
						results := results . different . "/" . PencilImageString . "-"
					}
				}
				if (ChangeConnectedCells = 1 or ChangePencilImage = 1)
					loop, parse, PencilImage, -
					{
						stringmid, n, PencilImageString1, a_index, 1
						fill(a_loopfield, n)
					}
			}
			if results <>
			{
				sort, results, N D-
				loop, parse, results, -
				{
					NextResult = %a_loopfield%
					break
				}
				loop, parse, NextResult, /
					if (a_index = 1)
						DiffMin = %a_loopfield%
					else
						PencilImageString = %a_loopfield%
					loop, parse, PencilImage, -
					{
						stringmid, n, PencilImageString, a_index, 1
						fill(a_loopfield, n)
					}
				stringlen, len, NextResult
				stringtrimleft, results, results, len+1
				%DontRepeatString% := results
			}
		}
	}
}
return

3GuiClose:
wingetpos, guiX, guiY,,, A
if CreateIndex = 3
	interrupt = 1
else
{
	gui, 3:destroy
	CreateIndex = 0
}
return

3ButtonCancel:
wingetpos, guiX, guiY,,, A
if CreateIndex = 3
	interrupt = 2
else
{
	gui, 3:destroy
	CreateIndex = 0
}
return

3ButtonSave:
wingetpos, guiX, guiY,,, A
gui, 3:destroy
CreateIndex = 0
gosub SaveAs
return

LeaveImage:
loop, parse, cells, -
	ifnotinstring, image, %a_loopfield%
		fill(a_loopfield, 0)
return

;---- larger ---------------------------------------------------------------------------------

larger:
+::
NumpadAdd::
if PlusMinus < 6
{
	PlusMinus += 1
	gosub CellsSize
	gui, 1:show, w%wGui% h%wGui%
}
return

;---- smaller --------------------------------------------------------------------------------

smaller:
-::
NumpadSub::
if PlusMinus > -2
{
	PlusMinus -= 1
	gosub CellsSize
	gui, 1:show, w%wGui% h%wGui%
}
return

;---- color numbers --------------------------------------------------------------------------

ColorNumbers:
inputbox, cNumber,,
(
1. Enter a color.
You can input these color names:
black, silver, gray, maroon, brown, red, purple, fuchsia, green, lime, olive, yellow, navy, blue, teal, aqua
Or input a 6-digit hexadecimal RGB color value.
2. Or get a color anywhere on your computer with Ctrl+Alt+mouse click.
3. Assign the color to the number under the mouse cursor with Ctrl+V. (You don't have to click.)

- RGB means red-green-blue, the first two digits are the red part of the color, the third and fourth digit are the green part of the color and the last two digits are the blue part of the color. 
- Hexadecimal means there are 16 instead of 10 digits: 0 1 2 3 4 5 6 7 8 9 a b c d e f. Hexadecimal numbers all start with the prefix 0x (e.g. 0xCC0000 is the dark red of the heart Sudoku) but the prefix may be omitted.

You can get any color by increasing or reducing the red or green or blue value:

ffff00 to ff0000 = yellow to red
(In slow motion: ffff00, fffe00, fffd00, ..., ffa100, ffa000, ff9900, ff9800, ..., ff0200, ff0100, ff0000)
ff0000 to ff00ff = red to fuchsia
ff00ff to 0000ff = fuchsia to blue
0000ff to 00ffff = blue to aqua
00ffff to 00ff00 = aqua to lime
00ff00 to ffff00 = lime to yellow

ffffff to 000000 = white to black

Colored numbers are only for the looks of the Sudoku, the colors don't affect the solution! But you can switch from numbers to colors (also in the View menu), then 9 predefined colors REPLACE the numbers and every color must appear only once in every row and every column and every block.

The colors of numbers are not remembered, the numbers will turn black again the next time when their cells are filled. You have to save the Sudoku when you have colored it and want to keep it.
),, 800, 600,,,,, %cNumber%
if cNumber = white
	cNumber =
else if cNumber = brown
	cNumber = 654000
return

;---- switch between numbers and colors -------------------------------------------------------

switch:
if CreateIndex = 3
{
	SwitchAfterLoopIteration = 1
	return
}
switch2:
if switch = colors
{
	switch = numbers
	cBackground = %cBackground1%
	gui, 1:color, %cBackground1%
}
else
{
	switch = colors
	cBackground = %cBackground2%
	gui, 1:color, %cBackground2%
}
loop, parse, cells, -
{
	if cell%a_loopfield% <> 0
		fill(a_loopfield, cell%a_loopfield%)
	else loop, 9
		PencilMark(a_loopfield, a_index, PencilMark%a_loopfield%%a_index%)
}
history("gui")
return

;---- back -----------------------------------------------------------------------------------

pgup::
back:
if HistoryIndex > 1
{
	if (fixed <> "" and HistoryIndex >= FixIndex)
		unfix()
	HistoryIndex -= 1
	StringToGui(history%HistoryIndex%)
}
return

;---- forward --------------------------------------------------------------------------------

pgdn::
forward:
if (HistoryIndex < HistoryIndexMax)
{
	HistoryIndex += 1
	StringToGui(history%HistoryIndex%)
}
return

;---- all pencil marks -----------------------------------------------------------------------

AllPencilMarks:
loop, parse, cells, -
	if cell%a_loopfield% = 0
{
	PencilMarks = 123456789
	loop, parse, ConnectedCells%a_loopfield%, -
		if cell%a_loopfield% <> 0
	{
		n := cell%a_loopfield%
		stringreplace, PencilMarks, PencilMarks, %n%,
	}
	loop, 9
	{
		ifinstring, PencilMarks, %a_index%
			PencilMark(a_loopfield, a_index, 1)
		else
			PencilMark(a_loopfield, a_index, 0)
	}
}
history("gui")
return

;---- pencil marks only for singles and pairs ------------------------------------------------

HintPencilMarks(mode)
{
	global
	local PencilMarks, u, rc, p, n
	if (mode = "refresh")
	{
		PencilMarks = 0
		loop, parse, cells, -
			loop, 9
				if PencilMark%a_loopfield%%a_index% = 1
		{
			PencilMarks = 1
			break
		}
		if (PencilMarks = 0)
			return
	
	}
	PencilMarks =
	loop, parse, cells, -
		if cell%a_loopfield% = 0
			PossibleNumbers%a_loopfield% = 123456789
	loop, parse, cells, -
	{
		rc = %a_loopfield%
		if cell%rc% = 0
		{
			loop, parse, ConnectedCells%rc%, -
				if cell%a_loopfield% <> 0
			{
				n := cell%a_loopfield%
				stringreplace, PossibleNumbers%rc%, PossibleNumbers%rc%, %n%,
			}
			stringlen, PossibleNumbersLen, PossibleNumbers%rc%
			if (PossibleNumbersLen = 1)
			{
				p := PossibleNumbers%rc%
				PencilMark(rc, p, 1)
				PencilMarks = %PencilMarks%%rc%%p%-
			}
		}
	}
	loop, 27  ; units
	{
		u = %a_index%
		loop, 9  ; numbers
		{
			n = %a_index%
			PossibleCells%u%%n% =
			loop, parse, unit%u%, -
			{
				if cell%a_loopfield% = %n%
					break
				else if cell%a_loopfield% = 0
					ifinstring, PossibleNumbers%a_loopfield%, %n%
						PossibleCells%u%%n% := PossibleCells%u%%n% . a_loopfield . "-"
			}
			stringlen, PossibleCellsLen, PossibleCells%u%%n%
			if (PossibleCellsLen = 3 or PossibleCellsLen = 6)
			{
				loop, parse, PossibleCells%u%%n%, -
					if a_loopfield <>
				{
					PencilMark(a_loopfield, n, 1)
					PencilMarks = %PencilMarks%%a_loopfield%%n%-
				}
			}
		}
	}
	if (mode <> "refresh")  ; if refresh, only find new ones, don't delete existing ones
	{
		loop, parse, cells, -
			loop, 9
				ifnotinstring, PencilMarks, %a_loopfield%%a_index%
					PencilMark(a_loopfield, a_index, 0)
		history("gui")
	}
}

;---- remove pencil marks --------------------------------------------------------------------

RemovePencilMarks:
loop, parse, cells, -
	loop, 9
		PencilMark(a_loopfield, a_index, 0)
history("gui")
return

;---- clear board ----------------------------------------------------------------------------

ClearBoard:
if fixed <>
	unfix()
loop, parse, cells, -
	fill(a_loopfield, 0)
if switch = numbers
{
	if (cBackground <> cBackground1)
	{
		cBackground = %cBackground1%
		gui, 1:color, %cBackground1%
	}
}
else
{
	if (cBackground <> cBackground2)
	{
		cBackground = %cBackground2%
		gui, 1:color, %cBackground2%
	}
}
history("gui")
return

;---- find one -------------------------------------------------------------------------------

^pgdn::
FindOne:
text =
explain = 1
gosub GetPossibleNumbers
explain = 0
stringleft, WhatNextLeft, WhatNext, 1
if WhatNextLeft = x  ; no possible cell
{
	stringtrimleft, WhatNext, WhatNext, 1
	stringright, n, WhatNext, 1
	stringtrimright, u, WhatNext, 1
	loop, parse, unit%u%, -
		if cell%a_loopfield% = 0
	{
		stringleft, r, a_loopfield, 1
		stringright, c, a_loopfield, 1
		xm := pos%c%+wCell/2
		ym := pos%r%+wCell/2+hTitleMenu
		click %xm%, %ym%, 0
		highlight(r . c, "red")
		sleep 400
	}
	text = Number %n%# can't be set anywhere in unit %u%.
	loop, parse, unit%u%, -
		if explain%a_loopfield%%n% <>
			text := text . explain%a_loopfield%%n%
}
else if WhatNextLeft = 0  ; no possible number
{
	stringmid, r, WhatNext, 2, 1
	stringmid, c, WhatNext, 3, 1
	xm := pos%c%+wCell/2
	ym := pos%r%+wCell/2+hTitleMenu
	click %xm%, %ym%, 0
	highlight(r . c, "red")
	text = This cell can't be filled.
	loop, 9
		if explain%r%%c%%a_index% <>
			text := text . explain%r%%c%%a_index%
}
else if WhatNextLeft = 1  ; one possible number
{
	stringmid, r, WhatNext, 2, 1
	stringmid, c, WhatNext, 3, 1
	n := PossibleNumbers%r%%c%
	xm := pos%c%+wCell/2
	ym := pos%r%+wCell/2+hTitleMenu
	click %xm%, %ym%, 0
	fill(r . c, n)
	highlight(r . c, "green")
	loop, parse, ConnectedCells%r%%c%, -
		PencilMark(a_loopfield, n, 0)
	HintPencilMarks("refresh")
	history("gui")
	if explain%r%%c%%n% =
	{
		text = %n%# is the only possible number in this cell.
		loop, 9
			if explain%r%%c%%a_index% <>
				text := text . explain%r%%c%%a_index%
	}
	else
	{
		u := explain%r%%c%%n%
		text = This is the only possible cell for number %n%# in unit %u%.
		loop, parse, unit%u%, -
			if a_loopfield <> %r%%c%
			if explain%a_loopfield%%n% <>
				text := text . explain%a_loopfield%%n%
	}
}
else if WhatNextLeft > 1  ; several possible numbers
{
	stringmid, r0, WhatNext, 2, 1  ; r and c are used by FillMinimumFirst. <---------
	stringmid, c0, WhatNext, 3, 1
	xm := pos%c0%+wCell/2
	ym := pos%r0%+wCell/2+hTitleMenu
	click %xm%, %ym%, 0
	ProvedNumbers =
	loop, parse, PossibleNumbers%r0%%c0%
	{
		fill(r0 . c0, a_loopfield)
		gosub FillMinimumFirst  ; <---------
		if SolutionAtAll = 1
			ProvedNumbers = %ProvedNumbers%%a_loopfield%
		history("gui")
		gosub back
	}
	stringlen, ProvedNumbersLen, ProvedNumbers
	if ProvedNumbersLen = 0
	{
		highlight(r0 . c0, "red")
		text := "This cell could be filled with"
		loop, parse, PossibleNumbersAll%r0%%c0%
			text = %text% %a_loopfield%# or
		stringtrimright, text, text, 3
		text := text . " but there is no solution with any of them."
	}
	else
	{
		if ProvedNumbersLen = 1
		{
			fill(r0 . c0, ProvedNumbers)
			highlight(r0 . c0, "green")
			loop, parse, ConnectedCells%r0%%c0%, -
				PencilMark(a_loopfield, ProvedNumbers, 0)
			HintPencilMarks("refresh")
			history("gui")
		}
		else
			highlight(r0 . c0, "blue")
		text := "Possible numbers:"
		loop, parse, PossibleNumbersAll%r0%%c0%
			text = %text% %a_loopfield%#,
		stringtrimright, text, text, 1
		text := text . ".There is a solution with:"
		loop, parse, ProvedNumbers
			text = %text% %a_loopfield%#,
		stringtrimright, text, text, 1
		text := text . "."
	}
}
if text <>
{
	loop, parse, cells, -
		if highlight%a_loopfield% <> green
			ifinstring, text, %a_loopfield%<blue>
				highlight(a_loopfield, "blue")
			else ifinstring, text, %a_loopfield%<red>
				highlight(a_loopfield, "red")
	stringreplace, text, text, <red>,, all
	stringreplace, text, text, <blue>,, all
	if switch = colors
	{
		loop, 9
		{
			color := color%a_index%name
			stringreplace, text, text, number %a_index%#, %color%, all
			stringreplace, text, text, %a_index%#, %color%, all
		}
		stringreplace, text, text, number, color, all
	}
	else
		stringreplace, text, text, #,, all
	text2 =
	loop, parse, text, .
		if a_loopfield <>
		ifnotinstring, text2, %a_loopfield%
			text2 = %text2%%a_loopfield%.
	text =
	loop, parse, text2, .
		if a_loopfield <>
	{
		stringleft, x, a_loopfield, 1
		if (x = "`n")
			text = %text%%a_loopfield%.
		else
		{
			stringupper, x, x
			stringtrimleft, line, a_loopfield, 1
			text = %text%`n%x%%line%.
		}
	}
	stringtrimleft, text, text, 1
	loop, parse, cells, -
		stringreplace, text, text, coord%a_loopfield%, % coord(a_loopfield), all
	loop, 9
	{
		u := a_index+9
		C := letter(a_index)
		stringreplace, text, text, unit %u%, column %C%, all
		u := a_index+18
		stringreplace, text, text, unit %u%, block %a_index%, all
	}
	loop, 9
		stringreplace, text, text, unit %a_index%, row %a_index%, all
	LineLenMax = 0
	loop, parse, text, `n`r
	{
		stringlen, LineLen, a_loopfield
		if (LineLen > LineLenMax)
			LineLenMax = %LineLen%
		LineIndex = %a_index%
	}
	if LineIndex <= 4
		tooltip %text%
	else
	{
		gui, 5:-caption +border +AlwaysOnTop +Disabled +Owner
		gui, 5:color, FFFFE1
		gui, 5:font, s12
		gui, 5:add, text,, %text%
		k = 6
		l = 20
		if (a_screendpi > 96)
		{
			k := k*a_screendpi//96
			l := l*a_screendpi//96
		}
		loop, 4
		{
			wingetpos, winx, winy, winwidth, winheight, %winTitle% ahk_class AutoHotkeyGUI
			xRelGui := winx+winwidth+10
			yRelGui := winy+winheight+10
			xRelScreen := a_screenwidth-k*LineLenMax-180  ; got by testing
			if (xRelScreen < 0)
				xRelScreen = 0
			yRelScreen := a_screenheight-l*LineIndex-40  ; got by testing
			if (yRelScreen < 0)
				yRelScreen = 0
			if (yRelScreen >= yRelGui)
			{
				yText = %yRelGui%
				if (xRelScreen >= winx)
					xText = %winx%
				else
					xText = %xRelScreen%
				break
			}
			else if (xRelScreen >= xRelGui)
			{
				xText = %xRelGui%
				if (yRelScreen >= winy)
					yText = %winy%
				else
					yText = %yRelScreen%
				break
			}
			else
			{
				if (a_index = 1)
					gui, 1:show, y10
				else if (a_index = 2)
					gui, 1:show, x10
				else if (a_index = 3)
					gosub smaller
				else
				{
					xText = %xRelScreen%
					yText = %yRelScreen%
				}
			}
		}
		gui, 5:show, x%xText% y%yText% NoActivate
		guitip = 1
	}
	sleep 10
	gui, 1:show  ; for Linux
}
return

coord(rc)
{
	stringleft, r, rc, 1
	stringright, c, rc, 1
	return letter(c) . r
}

letter(c)
{
	if c = 1
		letter = A
	else if c = 2
		letter = B
	else if c = 3
		letter = C
	else if c = 4
		letter = D
	else if c = 5
		letter = E
	else if c = 6
		letter = F
	else if c = 7
		letter = G
	else if c = 8
		letter = H
	else if c = 9
		letter = I
	return letter
}

;---- find all -------------------------------------------------------------------------------

FindAll:
gosub FillMinimumFirst
if SolutionAtAll = 0
	msgbox, There is no solution!
else if SolutionAtAll = 1
{
	history("gui")
	sleep 1000
	gosub FillMaximumFirst
	if SecondSolutionIdentical = 1
		msgbox, There is only one solution!
	else
	{
		history("gui")
		msgbox, There is a second solution!
	}
}
return

;---- help -----------------------------------------------------------------------------------

help:
gui, 4:destroy
gui, 4:font, s12
gui, 4:add, text,, Set %switch% with the left mouse button or the number keys.
if switch = colors
{
	gui, 4:add, text, xs, 1 = %color1name%
	gui, 4:add, text, xp+120, 2 = %color2name%
	gui, 4:add, text, xp+120, 3 = %color3name%
	gui, 4:add, text, xp+120, 4 = %color4name%
	gui, 4:add, text, xp+120, 5 = %color5name%
	gui, 4:add, text, xs, 6 = %color6name%
	gui, 4:add, text, xp+120, 7 = %color7name%
	gui, 4:add, text, xp+120, 8 = %color8name%
	gui, 4:add, text, xp+120, 9 = %color9name%
	pos = m
}
else
	pos = 0
gui, 4:add, text, xs y+%pos%,
(
Delete %switch% with the left mouse button or the spacebar.
Set/delete pencil marks with the right mouse button or with Shift+number key.
The arrow keys also move the mouse cursor.

This program in its compiled form (that is, as exe file, not as ahk file) also works with Wine
in Linux but colors will probably appear as = or g.
To fix this, copy webdings.ttf from the Windows fonts folder (C:\Windows\Fonts)
to the Linux truetype folder (/usr/share/fonts/truetype - open as administrator!).
)
gui, 4:show, x10 y10, Help
return

4GuiClose:
gui, 4:destroy
return

;_____________________________________________________________________________________________
;________ hotkey variants for the swap gui ___________________________________________________


#ifwinactive Create ahk_class AutoHotkeyGUI
1::
2::
3::
4::
5::
6::
7::
8::
9::
numpad1::
numpad2::
numpad3::
numpad4::
numpad5::
numpad6::
numpad7::
numpad8::
numpad9::
stringright, n, a_thislabel, 1
gosub swap
return

;_____________________________________________________________________________________________
;________ other subroutines __________________________________________________________________


CellsSize:
parameters = wCell-sNumber-sColor-sHighlight-wPencilMark-sPencilNumber-sPencilColor-wCaption-sCaption
loop, parse, parameters, -
	%a_loopfield% := %a_loopfield%1 + (PlusMinus * %a_loopfield%1)//4
wLine := PlusMinus//2+2
loop, 9
{
	pos%a_index% := (a_index-1)*(wCell+wLine)  ; position of column/row
	if (a_index > 6)
		pos%a_index% += 2*wLine
	else if (a_index > 3)
		pos%a_index% += wLine
}
wGui := pos9+wCell+wCaption
loop, parse, cells, -
{
	stringleft, r, a_loopfield, 1
	stringright, c, a_loopfield, 1
	x := pos%c%
	y := pos%r%
	wGridCell := pos4-pos3
	sSquare := wGridCell*4//5
	gui, 1:font, s%sSquare% c888888, Webdings
	guicontrol, 1:font, GridCell%a_loopfield%
	guicontrol, 1:movedraw, GridCell%a_loopfield%, x%x% y%y% w%wGridCell% h%wGridCell%
	guicontrol, 1:movedraw, highlight%a_loopfield%, x%x% y%y% w%wCell% h%wCell%
	guicontrol, 1:movedraw, cell%a_loopfield%, x%x% y%y% w%wCell% h%wCell%
	loop, 3
		posP%a_index% := (wCell-3*wPencilMark)//2 + (a_index-1)*wPencilMark  ; position of pencil mark column/row
	x1 := x+posP1
	y1 := y+posP1
	x2 := x+posP2
	y2 := y+posP1
	x3 := x+posP3
	y3 := y+posP1
	x4 := x+posP1
	y4 := y+posP2
	x5 := x+posP2
	y5 := y+posP2
	x6 := x+posP3
	y6 := y+posP2
	x7 := x+posP1
	y7 := y+posP3
	x8 := x+posP2
	y8 := y+posP3
	x9 := x+posP3
	y9 := y+posP3
	loop, 9
	{
		x := x%a_index%
		y := y%a_index%
		guicontrol, 1:movedraw, PencilMark%a_loopfield%%a_index%, x%x% y%y% w%wPencilMark% h%wPencilMark%
	}
	if cell%a_loopfield% <> 0
		fill(a_loopfield, cell%a_loopfield%)
	else loop, 9
		PencilMark(a_loopfield, a_index, PencilMark%a_loopfield%%a_index%)
	if highlight%a_loopfield% <> 0
		highlight(a_loopfield, highlight%a_loopfield%)
}
x := pos9+wCell+2*wLine
i = 0
loop, parse, caption123, -
{
	i += 1
	y := pos%i%+wCell/4
	guicontrol, 1:movedraw, caption123%a_loopfield%, x%x% y%y% w%wCaption% h%wCell%
	gui, 1:font, c222222 s%sCaption%
	gui, 1:font,, Ubuntu
	gui, 1:font,, Arial
	guicontrol, 1:font, caption123%a_loopfield%
	guicontrol, 1:text, caption123%a_loopfield%, %a_loopfield%
}
y := pos9+wCell+2*wLine
i = 0
loop, parse, captionABC, -
{
	i += 1
	x := pos%i%
	guicontrol, 1:movedraw, captionABC%a_loopfield%, x%x% y%y% w%wCell% h%wCaption%
	gui, 1:font, c222222 s%sCaption%
	gui, 1:font,, Ubuntu
	gui, 1:font,, Arial
	guicontrol, 1:font, captionABC%a_loopfield%
	guicontrol, 1:text, captionABC%a_loopfield%, %a_loopfield%
}
return

;---------------------------------------------------------------------------------------------

MouseGetNearestCell:
mousegetpos, xm, ym
xyGetNearestCell:
rm = 1
cm = 1
loop, 9
	if a_index > 1
{
	if abs(xm-(pos%a_index%+wCell/2)) < abs(xm-(pos%cm%+wCell/2))
		cm = %a_index%
	if abs(ym-(pos%a_index%+wCell/2+hTitleMenu)) < abs(ym-(pos%rm%+wCell/2+hTitleMenu))
		rm = %a_index%
}
xcenter := pos%cm%+wCell/2
ycenter := pos%rm%+wCell/2+hTitleMenu
return

;---------------------------------------------------------------------------------------------

fill(rc, n)
{
	global
	if (cell%rc% <> n)
	{
		tooltip
		if guitip = 1
		{
			gui, 5:destroy
			guitip = 0
		}
	}
	if (JustHighlighted <> 1 and cell%rc% <> n)
		loop, parse, cells, -
			highlight(a_loopfield, 0)
	cell%rc% = %n%
	if CreateIndex = 3
	ifnotinstring, image, %rc%
		return
	if DontDisplay = 1
		return
	loop, 9
		PencilMark(rc, a_index, 0)
	if n = 0
	{
		if (LastFill%rc% <> 0)
		{
			guicontrol, 1:text, cell%rc%
			LastFill%rc% = 0
		}
	}
	else
	{
		if switch = colors
		{
			if (LastFill%rc% <> color%n%value . sColor . "Webdings" . "=" or JustHighlighted = 1)
			{
				color := color%n%value
				gui, 1:font, c%color% s%sColor%, Webdings
				guicontrol, 1:font, cell%rc%
				guicontrol, 1:text, cell%rc%, =
				LastFill%rc% := color%n%value . sColor . "Webdings" . "="
			}
		}
		else
		{
			if (LastFill%rc% <> sNumber . "Ubuntu Arial" . n 
			or JustHighlighted = 1
			or cNumber%rc% <> "" and MultipleChange > 1)
			{
				cNumber%rc% =
				if (a_thislabel = "CellsSize" and fixed <> "")
					gui, 1:font, cgreen s%sNumber%
				else
					gui, 1:font, c222222 s%sNumber%
				gui, 1:font,, Ubuntu
				gui, 1:font,, Arial
				guicontrol, 1:font, cell%rc%
				guicontrol, 1:text, cell%rc%, %n%
				LastFill%rc% := sNumber . "Ubuntu Arial" . n
			}
		}
	}
}

;---------------------------------------------------------------------------------------------

highlight(rc, color)
{
	global
	highlight%rc% = %color%
	if highlight%rc% = 0
	{
		if LastHighlight%rc% <> 0
		{
			guicontrol, 1:text, highlight%rc%
			LastHighlight%rc% = 0
			JustHighlighted = 1
			if cell%rc% <> 0
				fill(rc, cell%rc%)
			else loop, 9
				PencilMark(rc, a_index, PencilMark%rc%%a_index%)
			JustHighlighted = 0
		}
	}
	else
	{
		if (LastHighlight%rc% <> highlight%rc% . sHighlight)
		{
			if highlight%rc% = red
				RealColor = 0xFFCCCC
			else if highlight%rc% = green
				RealColor = 0xCCFFCC
			else if highlight%rc% = blue
				RealColor = 0xCCCCFF
			gui, 1:font, c%RealColor% s%sHighlight%, Webdings
			guicontrol, 1:font, highlight%rc%
			guicontrol, 1:text, highlight%rc%, g
			LastHighlight%rc% := highlight%rc% . sHighlight
			JustHighlighted = 1
			if cell%rc% <> 0
				fill(rc, cell%rc%)
			else loop, 9
				PencilMark(rc, a_index, PencilMark%rc%%a_index%)
			JustHighlighted = 0
		}
	}
}

;---------------------------------------------------------------------------------------------

PencilMark(rc, n, value)
{
	global
	PencilMark%rc%%n% = %value%
	if value = 0
	{
		if (LastPencilMark%rc%%n% <> 0)
		{
			guicontrol, 1:text, PencilMark%rc%%n%
			LastPencilMark%rc%%n% = 0
		}
	}
	else if value = 1
	{
		if switch = colors
		{
			if (LastPencilMark%rc%%n% <> color%n%value . sPencilColor . "Webdings" . "=" or JustHighlighted = 1)
			{
				color := color%n%value
				gui, 1:font, c%color% s%sPencilColor%, Webdings
				guicontrol, 1:font, PencilMark%rc%%n%
				guicontrol, 1:text, PencilMark%rc%%n%, =
				LastPencilMark%rc%%n% := color%n%value . sPencilColor . "Webdings" . "="
			}
		}
		else
		{
			if (LastPencilMark%rc%%n% <> sPencilNumber . "Ubuntu Arial" . n or JustHighlighted = 1)
			{
				gui, 1:font, c222222 s%sPencilNumber%
				gui, 1:font,, Ubuntu
				gui, 1:font,, Arial
				guicontrol, 1:font, PencilMark%rc%%n%
				guicontrol, 1:text, PencilMark%rc%%n%, %n%
				LastPencilMark%rc%%n% := sPencilNumber . "Ubuntu Arial" . n
			}
		}
	}
}

;---------------------------------------------------------------------------------------------

GuiToString()
{
	global
	string = %switch%-%cBackground%-
	if (switch = "numbers" and a_thislabel = "SaveAs") ; remember colored numbers only when you save them
	{
		loop, parse, cells, -
			if (cell%a_loopfield% <> 0 and cNumber%a_loopfield% <> "")
				string := string . a_loopfield . cNumber%a_loopfield% . ","
		stringright, x, string, 1
		if (x = ",")
			stringtrimright, string, string, 1
	}
	loop, parse, cells, -
		if (cell%a_loopfield% <> 0)
			string := string . "-" . a_loopfield . cell%a_loopfield%
	loop, parse, cells, -
		if (cell%a_loopfield% = 0)
			loop, 9
				if (PencilMark%a_loopfield%%a_index% = 1)
					string := string . "-" . a_loopfield . "p" . a_index
	return string
}

;---------------------------------------------------------------------------------------------

StringToGui(string)
{
	global
	loop, parse, cells, -
	{
		cell%a_loopfield%new = 0
		loop, 9
			PencilMark%a_loopfield%%a_index%new = 0
	}
	MultipleChange = 0
	loop, parse, string, -, `n`r
	{
		if a_index = 1
			switch = %a_loopfield%
		else if a_index = 2
		{
			if (a_loopfield <> cBackground)
				gui, 1:color, %a_loopfield%
			cBackground = %a_loopfield%
		}
		else if a_index = 3
			ColoredNumbers = %a_loopfield%
		else
		{
			stringleft, rc, a_loopfield, 2
			stringright, n, a_loopfield, 1
			ifnotinstring, a_loopfield, p
			{
				cell%rc%new = %n%
				if (cell%rc% <> n)
					MultipleChange += 1
			}
			else
				PencilMark%rc%%n%new = 1
		}
	}
	loop, parse, cells, -
	{
		if (cell%a_loopfield%new <> 0)
			fill(a_loopfield, cell%a_loopfield%new)
		else
		{
			if cell%a_loopfield% <> 0
				fill(a_loopfield, 0)
			loop, 9
				PencilMark(a_loopfield, a_index, PencilMark%a_loopfield%%a_index%new)
		}
	}
	MultipleChange = 0
	loop, parse, ColoredNumbers, `,
	{
		stringleft, rc, a_loopfield, 2
		stringtrimleft, color, a_loopfield, 2
		gui, 1:font, c%color% s%sNumber%
		gui, 1:font,, Ubuntu
		gui, 1:font,, Arial
		guicontrol, 1:font, cell%rc%
		cNumber%rc% = %color%
	}
}

;---------------------------------------------------------------------------------------------

fix(color)
{
	global
	fixed =
	loop, parse, cells, -
	if cell%a_loopfield% <> 0
	{
		fixed = %fixed%%a_loopfield%-
		if (switch = "numbers" and color <> "")
		{
			FixColor = %color%
			gui, 1:font, c%color% s%sNumber%
			gui, 1:font,, Ubuntu
			gui, 1:font,, Arial
			guicontrol, 1:font, cell%a_loopfield%
		}
	}
	FixIndex = %HistoryIndex%
}

unfix()
{
	global
	if (switch = "numbers" and FixColor <> "")
	loop, parse, fixed, -
	if a_loopfield <>
	{
		gui, 1:font, c222222 s%sNumber%
		gui, 1:font,, Ubuntu
		gui, 1:font,, Arial
		guicontrol, 1:font, cell%a_loopfield%
	}
	fixed =
	FixColor =
	FixIndex =
}

;---------------------------------------------------------------------------------------------

history(add)
{
	global
	if (HistoryIndexMax > HistoryIndex)
	{
		l := HistoryIndexMax - HistoryIndex
		loop, %l%
		{
			i := HistoryIndex + a_index
			history%i% =
		}
	}
	HistoryIndex += 1
	HistoryIndexMax = %HistoryIndex%
	if (add = "gui")
		add := GuiToString()
	history%HistoryIndex% = %add%
}

;---------------------------------------------------------------------------------------------

GetPossibleNumbers:
loop, parse, cells, -
	if cell%a_loopfield% = 0
		PossibleNumbers%a_loopfield% = 123456789
loop, 27
{
	u = %a_index%
	loop, 9
		PossibleCells%u%%a_index% =
}
loop, parse, cells, -
	loop, 9
		explain%a_loopfield%%a_index% =
; explainRCN will be a text string, explaining why N can't be set in cell RC,
; or the index of a unit where N can only be set in cell RC.
;---- Get possible numbers for every cell. ----
loop, parse, cells, -
{
	rc = %a_loopfield%
	if cell%rc% = 0
	{
		loop, parse, ConnectedCells%rc%, -
			if cell%a_loopfield% <> 0
		{
			n := cell%a_loopfield%
			stringreplace, PossibleNumbers%rc%, PossibleNumbers%rc%, %n%,
		}
		if (CreateIndex = 2 or CreateIndex = 3)
		if DeletedNumbers%rc% <>
			loop, parse, DeletedNumbers%rc%
				stringreplace, PossibleNumbers%rc%, PossibleNumbers%rc%, %a_loopfield%,
		PossibleNumbersRev%rc% =
		loop, parse, PossibleNumbers%rc%
			PossibleNumbersRev%rc% := a_loopfield . PossibleNumbersRev%rc%
		PossibleNumbersAll%rc% := PossibleNumbers%rc%
		stringlen, PossibleNumbersLen, PossibleNumbers%rc%
		if (PossibleNumbersLen = 0 or PossibleNumbersLen = 1 and GetAll <> 1)
		{
			WhatNext = %PossibleNumbersLen%%rc%
			return
		}
	}
}
loop, 3
{
main_index = %a_index%
	if (explain = 1 or GetAll = 1)
	{
		;---- Y-wings/chains ----
		CellsWith2PossibleNumbers =
		loop, parse, cells, -
			if (cell%a_loopfield% = 0)
		{
			stringlen, PossibleNumbersLen, PossibleNumbers%a_loopfield%
			if (PossibleNumbersLen = 2)
				CellsWith2PossibleNumbers = %CellsWith2PossibleNumbers%%a_loopfield%-
		}
		stringtrimright, CellsWith2PossibleNumbers, CellsWith2PossibleNumbers, 1
		ChainLinks =
		loop, parse, CellsWith2PossibleNumbers, -
		{
			rc1 = %a_loopfield%
			loop, parse, CellsWith2PossibleNumbers, -
			ifinstring, ConnectedCells%rc1%, %a_loopfield%
			{
				rc2 = %a_loopfield%
				n1 =
				n12 =
				n2 =
				loop, 9
				{
					ifinstring, PossibleNumbers%rc1%, %a_index%
					ifnotinstring, PossibleNumbers%rc2%, %a_index%
						n1 = %a_index%
					ifinstring, PossibleNumbers%rc2%, %a_index%
					ifnotinstring, PossibleNumbers%rc1%, %a_index%
						n2 = %a_index%
					ifinstring, PossibleNumbers%rc1%, %a_index%
					ifinstring, PossibleNumbers%rc2%, %a_index%
						n12 = %a_index%
					if (n1 <> "" and n2 <> "" and n12 <> "")
						ifnotinstring, ChainLinks, %rc1%%rc2%%n1%%n2%%n12%
							ChainLinks = %ChainLinks%%rc1%%rc2%%n1%%n2%%n12%-
				}
			}
		}
		stringtrimright, ChainLinks, ChainLinks, 1
		loop, 9
			ChainLink%a_index% =
		loop, parse, ChainLinks, -
		{
			ChainLink1 = %a_loopfield%
			loop, parse, ChainLinks, -
			{
				ChainLink2 = %a_loopfield%
				if FitIn(2) = 2
					return
				else if FitIn(2) = 1
					loop, parse, ChainLinks, -
				{
					ChainLink3 = %a_loopfield%
					if FitIn(3) = 2
						return
					else if FitIn(3) = 1
						loop, parse, ChainLinks, -
					{
						ChainLink4 = %a_loopfield%
						if FitIn(4) = 2
							return
					}
				}
			}
		}
	}
	loop, 27  ; units
	{
		u = %a_index%
		loop, 9  ; numbers
		{
			n = %a_index%
;---- Get possible cells for every number in every unit. ----
			i = 0
			PossibleCells%u%%n% =
			loop, parse, unit%u%, -
			{
				if cell%a_loopfield% = %n%
				{
					i = 1
					break
				}
				else if cell%a_loopfield% = 0
				{
					ifinstring, PossibleNumbers%a_loopfield%, %n%
						PossibleCells%u%%n% := PossibleCells%u%%n% . a_loopfield . "-"
				}
			}
			stringlen, PossibleCellsLen, PossibleCells%u%%n%
			if (i = 0 and PossibleCellsLen = 0)  ; Number n is not and can not be set in unit u.
			{
				WhatNext = x%u%%n%
				return
			}
			else if PossibleCellsLen = 3  ; In unit u number n must be ...
			{
				stringleft, rc, PossibleCells%u%%n%, 2  ; ... in cell rc.
				PossibleNumbers%rc% = %n%
				if explain = 1
					explain%rc%%n% = %u%
				if GetAll <> 1
				{
					WhatNext = 1%rc%
					return
				}
			}
			else
			{
				;---- If there are two numbers with the same two possible cells
				; then these two numbers are the only possible numbers in these two cells. ----
				if PossibleCellsLen = 6
					loop, % n-1
						if (PossibleCells%u%%a_index% = PossibleCells%u%%n%)
				{
					n2 = %a_index%
					loop, parse, PossibleCells%u%%n%, -
						if a_loopfield <>
					{
						rc = %a_loopfield%
						if explain = 1
							loop, parse, PossibleNumbers%rc%
								if (a_loopfield <> n and a_loopfield <> n2)
						{
							n3 = %a_loopfield%
							stringleft, rc1, PossibleCells%u%%n%, 2
							stringmid, rc2, PossibleCells%u%%n%, 4, 2
							explain%rc%%n3% = %n3%# can't be in coord%rc%<red> because in unit %u% %n2%# and %n%# must be in coord%rc1%<blue> and coord%rc2%<blue>.
							loop, parse, unit%u%, -
							{
								if explain%a_loopfield%%n% <>
									explain%rc%%n3% := explain%rc%%n3% . explain%a_loopfield%%n%
								if explain%a_loopfield%%n2% <>
									explain%rc%%n3% := explain%rc%%n3% . explain%a_loopfield%%n2%
							}
						}
						PossibleNumbers%rc% = %n2%%n%
						PossibleNumbersRev%rc% = %n%%n2%
					}
					break
				}
				;---- If number n has two or three possible cells in unit u and all of them are also
				; in another unit then number n can't be set anywhere else in the other unit
				; because otherwise number n couldn't be set anywhere in unit u. ----
				if (PossibleCellsLen = 6 or PossibleCellsLen = 9)
				{
					stringleft, pc1, PossibleCells%u%%n%, 2
					if (u <= 18)  ; u = row or column => u2 must be a block
						BorRC := block%pc1%
					else
					{
						stringleft, r, pc1, 1
						stringright, c, pc1, 1
						c += 9
						BorRC = %r%-%c%
					}
					loop, parse, BorRC, -
					{
						u2 = %a_loopfield%
						AllInU2 = 1
						loop, parse, PossibleCells%u%%n%, -
							if a_loopfield <>
							ifnotinstring, unit%u2%, %a_loopfield%
						{
							AllInU2 = 0
							break
						}
						if AllInU2 = 1
						{
							loop, parse, unit%u2%, -
								if cell%a_loopfield% = 0
								ifnotinstring, PossibleCells%u%%n%, %a_loopfield%
								ifinstring, PossibleNumbers%a_loopfield%, %n%
							{
								rc = %a_loopfield%
								if explain = 1
								{
									string = %n%# can't be in coord%rc%<red> because in unit %u% it must be in
									loop, parse, PossibleCells%u%%n%, -
										if a_loopfield <>
											string = %string% coord%a_loopfield%<blue> or
									stringtrimright, string, string, 3
									explain%rc%%n% = %string%.
									loop, parse, unit%u%, -
										if explain%a_loopfield%%n% <>
											explain%rc%%n% := explain%rc%%n% . explain%a_loopfield%%n%
								}
								stringreplace, PossibleNumbers%rc%, PossibleNumbers%rc%, %n%,
								stringreplace, PossibleNumbersRev%rc%, PossibleNumbersRev%rc%, %n%,
								stringlen, pn, PossibleNumbers%rc%
								if (pn = 0 or pn = 1 and GetAll <> 1)
								{
									WhatNext = %pn%%rc%
									return
								}
							}
							break
						}
					}
				}
				if (explain = 1 or GetAll = 1)
				{
					;---- empty rectangle: delete x from xyz ----
					; 1 1 1			1x
					; 1
					; 1
					; 
					; 
					; 
					; 1x			xyz

					if (PossibleCellsLen >= 6 and PossibleCellsLen <= 15)
					{
						loop, parse, unit%u%, -
						{
							rc = %a_loopfield%
							AllInCrossRoads = 1
							loop, parse, PossibleCells%u%%n%, -
								if a_loopfield <>
									ifnotinstring, CrossRoads%rc%, %a_loopfield%
							{
								AllInCrossRoads = 0
								break
							}
							if (AllInCrossRoads = 1)
							{
								road1 := CrossRoads%rc%r
								road2 := CrossRoads%rc%c
								loop, parse, unit%road1%, -
									ifnotinstring, unit%u%, %a_loopfield%
										if (cell%a_loopfield% = 0)
								{
									rc1 = %a_loopfield%
									stringlen, PossibleNumbersLen, PossibleNumbers%rc1%
									if (PossibleNumbersLen = 2)
										ifinstring, PossibleNumbers%rc1%, %n%
											loop, parse, unit%road2%, -
												ifnotinstring, unit%u%, %a_loopfield%
													if (cell%a_loopfield% = 0)
									{
										rc2 = %a_loopfield%
										if (PossibleNumbers%rc2% = PossibleNumbers%rc1%)
										{
											stringright, c, rc1, 1
											stringleft, r, rc2, 1
											rc3 = %r%%c%
											loop, parse, PossibleNumbers%rc1%
											if (a_loopfield <> n)
												OtherNumber = %a_loopfield%
											ifinstring, PossibleNumbers%rc3%, %OtherNumber%
											{
												textu =
												textr =
												textc =
												loop, parse, PossibleCells%u%%n%, -
													if a_loopfield <>
												{
													textu = %textu% or coord%a_loopfield%<blue>
													stringleft, r, a_loopfield, 1
													if (r = road1)
														textr = %textr% or coord%a_loopfield%
													stringright, c, a_loopfield, 1
													if (c = road2-9)
														textc = %textc% or coord%a_loopfield%
												}
												stringtrimleft, textu, textu, 3
												stringtrimleft, textr, textr, 3
												stringtrimleft, textc, textc, 3
												TextExplain =
(
%OtherNumber%# can't be in coord%rc3%<red>.
In unit %u%, %n%# must be in %textu%.
- If %n%# is in %textr% then %n%# can't be in coord%rc1%<red>, then %OtherNumber%# must be in coord%rc1% and %OtherNumber%# can't be in coord%rc3%.
- If %n%# is in %textc% then %n%# can't be in coord%rc2%<red>, then %OtherNumber%# must be in coord%rc2% and again, %OtherNumber%# can't be in coord%rc3%.
)
												loop, parse, unit%u%, -
													ifnotinstring, PossibleCells%u%%n%, %a_loopfield%
														if explain%a_loopfield%%n% <>
															TextExplain := TextExplain . explain%a_loopfield%%n%
												loop, 9
													ifnotinstring, PossibleNumbers%rc1%, %a_index%
														if explain%rc1%%a_index% <>
															TextExplain := TextExplain . explain%rc1%%a_index%
												loop, 9
													ifnotinstring, PossibleNumbers%rc2%, %a_index%
														if explain%rc2%%a_index% <>
															TextExplain := TextExplain . explain%rc2%%a_index%
												explain%rc3%%OtherNumber% = %TextExplain%
												stringreplace, PossibleNumbers%rc3%, PossibleNumbers%rc3%, %OtherNumber%,
												stringlen, PossibleNumbersLen, PossibleNumbers%rc3%
												if (PossibleNumbersLen = 0 or PossibleNumbersLen = 1 and GetAll <> 1)
												{
													WhatNext = %PossibleNumbersLen%%rc3%
													return
												}
											}
										}
									}
								}
								break
							}
						}
					}
					;---- X-wing ----
					if (PossibleCellsLen = 6)
					{
						stringleft, A, PossibleCells%u%%n%, 2
						stringmid, B, PossibleCells%u%%n%, 4, 2
						loop, % u-1  ; iterations u+1 to 27 would get earlier PossibleCells
						{
							u2 = %a_index%
							stringlen, p2, PossibleCells%u2%%n%
							stringleft, C, PossibleCells%u2%%n%, 2
							stringmid, D, PossibleCells%u2%%n%, 4, 2
							if (p2 = 6 and A <> C and A <> D and B <> C and B <> D)
							{
								positions = %A%%B%%C%%D%/%B%%A%%C%%D%/%A%%B%%D%%C%/%B%%A%%D%%C%
								loop, parse, positions, /
								{
									stringleft, uCell1, a_loopfield, 2
									stringmid, uCell2, a_loopfield, 3, 2
									stringmid, u2Cell1, a_loopfield, 5, 2
									stringright, u2Cell2, a_loopfield, 2
									ifinstring, ConnectedCells%uCell1%, %u2Cell1%
									ifnotinstring, ConnectedCells%uCell2%, %u2Cell1%
									ifnotinstring, ConnectedCells%u2Cell2%, %uCell1%
									{
										loop, parse, ConnectedCells%uCell2%, -
											if cell%a_loopfield% = 0
											ifinstring, ConnectedCells%u2Cell2%, %a_loopfield%
											ifinstring, PossibleNumbers%a_loopfield%, %n%
											{
												rc = %a_loopfield%
												explain%rc%%n% =
(
%n%# can't be in coord%rc%<red> because
- if in unit %u2% it is in coord%u2Cell1%<blue> then in unit %u% it must be in coord%uCell2%<blue>
- if in unit %u% it is in coord%uCell1%<blue> then in unit %u2% it must be in coord%u2Cell2%<blue>.
Either way %n%# can't be in coord%rc% because coord%rc% is connected with both coord%uCell2% and coord%u2Cell2%.
)
												loop, parse, unit%u%, -
													ifnotinstring, PossibleCells%u%%n%, %a_loopfield%
													if explain%a_loopfield%%n% <>
														explain%rc%%n% := explain%rc%%n% . explain%a_loopfield%%n%
												loop, parse, unit%u2%, -
													ifnotinstring, PossibleCells%u2%%n%, %a_loopfield%
													if explain%a_loopfield%%n% <>
														explain%rc%%n% := explain%rc%%n% . explain%a_loopfield%%n%
												stringreplace, PossibleNumbers%rc%, PossibleNumbers%rc%, %n%,
												stringlen, PossibleNumbersLen, PossibleNumbers%rc%
												if (PossibleNumbersLen = 0 or PossibleNumbersLen = 1 and GetAll <> 1)
												{
													WhatNext = %PossibleNumbersLen%%rc%
													return
												}
											}
									}
								}
							}
						}
					}
					;---- Swordfish ----
					if (main_index > 1)  ; don't catch too many Swordfish
						if (u <= 18)
							if (PossibleCellsLen = 6 or PossibleCellsLen = 9)
					{
						loop, 18
							if ((u <= 9 and a_index <= 9 or u >= 10 and a_index >= 10) and a_index <> u)
						{
							u2 = %a_index%
							if (PossibleCells%u2%%n% <> "" and DiagonsLen(u, PossibleCells%u%%n% . PossibleCells%u2%%n%) <= 6)
							{
								loop, 18
								if ((u <= 9 and a_index <= 9 or u >= 10 and a_index >= 10) and a_index <> u and a_index <> u2)
								{
									u3 = %a_index%
									if (PossibleCells%u3%%n% <> "" and DiagonsLen(u, PossibleCells%u%%n% . PossibleCells%u2%%n% . PossibleCells%u3%%n%) <= 6)
									{
										loop, parse, diagons, -
											if a_loopfield <>
										{
											d = %a_loopfield%
											if (u <= 9)	; if unit = row
												d += 9		; then diagon = column
											loop, parse, unit%d%, -
												ifnotinstring, unit%u%, %a_loopfield%
													ifnotinstring, unit%u2%, %a_loopfield%
														ifnotinstring, unit%u3%, %a_loopfield%
															if (cell%a_loopfield% = 0)
																ifinstring, PossibleNumbers%a_loopfield%, %n%
											{
												rc = %a_loopfield%
												;--------------------
												TextUnits =
												PossibleCells =
												ThreeUnits = %u%-%u2%-%u3%
												sort, ThreeUnits, D-
												loop, parse, ThreeUnits, -
												{
													TextUnits = %TextUnits% and unit %a_loopfield%
													PossibleCells := PossibleCells . PossibleCells%a_loopfield%%n%
												}
												stringtrimleft, TextUnits, TextUnits, 4
												;--------------------
												TextPossibleCells =
												loop, parse, PossibleCells, -
													if a_loopfield <>
												TextPossibleCells = %TextPossibleCells% or coord%a_loopfield%<blue>
												stringtrimleft, TextPossibleCells, TextPossibleCells, 3
												;--------------------
												TextDiagons =
												sort, diagons, N D-
												loop, parse, diagons, -
													if a_loopfield <>
												{
													d = %a_loopfield%
													if (u <= 9)	; if unit = row
														d += 9		; then diagon = column
													TextDiagons = %TextDiagons% or unit %d%
												}
												stringtrimleft, TextDiagons, TextDiagons, 3
												;--------------------
												explain%rc%%n% =
(
%n%# can't be in coord%rc%<red> because in %TextUnits% %n%# must be in %TextPossibleCells%;
that's all in %TextDiagons%, so there can't be any other %n%# in %TextDiagons%.
)
												loop, parse, unit%u%, -
													ifnotinstring, PossibleCells%u%%n%, %a_loopfield%
														if explain%a_loopfield%%n% <>
															explain%rc%%n% := explain%rc%%n% . explain%a_loopfield%%n%
												loop, parse, unit%u2%, -
													ifnotinstring, PossibleCells%u2%%n%, %a_loopfield%
														if explain%a_loopfield%%n% <>
															explain%rc%%n% := explain%rc%%n% . explain%a_loopfield%%n%
												loop, parse, unit%u3%, -
													ifnotinstring, PossibleCells%u3%%n%, %a_loopfield%
														if explain%a_loopfield%%n% <>
															explain%rc%%n% := explain%rc%%n% . explain%a_loopfield%%n%
												stringreplace, PossibleNumbers%rc%, PossibleNumbers%rc%, %n%,
												stringlen, PossibleNumbersLen, PossibleNumbers%rc%
												if (PossibleNumbersLen = 0 or PossibleNumbersLen = 1 and GetAll <> 1)
												{
													WhatNext = %PossibleNumbersLen%%rc%
													return
												}
											}
										}
									}
								}
							}
						}
					}
				}
			}
		}
	}
}
WhatNext =
loop, parse, cells, -
	if cell%a_loopfield% = 0
	{
		stringlen, PossibleNumbersLen, PossibleNumbers%a_loopfield%
		WhatNext = %WhatNext%%PossibleNumbersLen%%a_loopfield%-
	}
sort, WhatNext, d-
return

;----------------

DiagonsLen(u, CellList)
{
	global
	diagons =
	loop, parse, CellList, -
		if a_loopfield <>
	{
		if (u <= 9)
			stringright, RorC, a_loopfield, 1
		else
			stringleft, RorC, a_loopfield, 1
		ifnotinstring, diagons, %RorC%
			diagons = %diagons%%RorC%-
	}
	stringlen, DiagonsLen, diagons
	return DiagonsLen
}

FitIn(cl_index)  ; cl_index = chain link index
{
	global
	ChainLink%cl_index% = %a_loopfield%
	fit = 0
	repeat = 0
	l := cl_index-1
	loop, %l%
		if (ChainLink%cl_index% = ChainLink%a_index%)
	{
		repeat = 1
		break
	}
	if (repeat = 0)  ; no chain link twice
	{
		stringmid, rc1, ChainLink%l%, 3, 2
		stringleft, rc2, ChainLink%cl_index%, 2
		stringright, n1, ChainLink%l%, 1
		stringright, n2, ChainLink%cl_index%, 1
		if (rc1 = rc2 and n1 <> n2)  ; last two chain links something like 12-23 and 23-34: 2 <> 3
		{
			fit = 1
			stringleft, rc1, ChainLink1, 2
			stringmid, rc2, ChainLink%cl_index% , 3, 2
			stringmid, n1, ChainLink1, 5, 1
			stringmid, n2, ChainLink%cl_index% , 6, 1
			if (n1 = n2)  ; first chain link begins and last chain link ends with the same possible number
			{
				loop, parse, cells, -
					if (cell%a_loopfield% = 0)
						ifinstring, ConnectedCells%rc1%, %a_loopfield%
							ifinstring, ConnectedCells%rc2%, %a_loopfield%
								ifinstring, PossibleNumbers%a_loopfield%, %n1%
				{
; Any other empty cell with this possible number (there may be more possible numbers) that "sees" both start and end of the
; chain. The chain prevents this number being in this cell.
; chain: 12	23	34	41
; chain links: 12-23, 23-34, 34-41
; 1 in 12 or if 2 in 12 then 3 in 23 then 4 in 34 then 1 in 41, so  either way no 1 in any other cell that "sees" both start
; and end of the chain.
					SeeBoth = %a_loopfield%
					SeeWhat = %n1%
					chain =
					loop, %cl_index%
					{
						stringleft, cc%a_index%, ChainLink%a_index%, 2  ; cc = chain cell
						chain := chain . cc%a_index% . "-"
						stringmid, mcc%a_index%, ChainLink%a_index%, 5, 1  ; mcc, ncc = possible numbers in cc, mcc1 = SeeWhat
						stringright, ncc%a_index%, ChainLink%a_index%, 1
					}
					i := cl_index+1
					stringmid, cc%i%, ChainLink%cl_index%, 3, 2  ; ChainLink%cl_index% (not ChainLink%a_index%) is the last chain link!
					chain := chain . cc%i%
					stringright, mcc%i%, ChainLink%cl_index%, 1
					stringmid, ncc%i%, ChainLink%cl_index%, 6, 1  ; ncci = SeeWhat
					if (cl_index = 2)
					{
						stringleft, r1, SeeBoth, 1
						stringleft, r2, cc1, 1
						stringleft, r3, cc2, 1
						stringleft, r4, cc3, 1
						stringright, c1, SeeBoth, 1
						stringright, c2, cc1, 1
						stringright, c3, cc2, 1
						stringright, c4, cc3, 1
						if  (r1 = r2 and r1 = r3 and r1 = r4
						or c1 = c2 and c1 = c3 and c1 = c4
						or block%SeeBoth% = block%cc1% and block%SeeBoth% = block%cc2% and block%SeeBoth% = block%cc3%)  ; all in one unit?
						{
							ThreeBlueCells = %cc1%-%cc2%-%cc3%
							ThreePossibleNumbers = %mcc1%-%mcc2%-%mcc3%
							sort, ThreeBlueCells, D-
							sort, ThreePossibleNumbers, N D-
							loop, parse, ThreeBlueCells, -
								blue%a_index% = %a_loopfield%
							loop, parse, ThreePossibleNumbers, -
								blueN%a_index% = %a_loopfield%
							explain%SeeBoth%%blueN1% =
(
Together, the three blue cells coord%blue1%<blue> and coord%blue2%<blue> and coord%blue3%<blue> have the three possible numbers %blueN1%# and %blueN2%# and %blueN3%#.
So %blueN1%# and %blueN2%# and %blueN3%# will be somewhere in coord%blue1% and coord%blue2% and coord%blue3% and therefore can't be in coord%SeeBoth%<red>.
)
							explain%SeeBoth%%blueN2% := explain%SeeBoth%%blueN1%
							explain%SeeBoth%%blueN3% := explain%SeeBoth%%blueN1%
							Ywing = %blue1%-%blue2%-%blue3%
							ExplainMore =
							loop, parse, Ywing, -
								loop, 9
									ifnotinstring, PossibleNumbers%a_loopfield%, %a_index%
										if explain%a_loopfield%%a_index% <>
											ExplainMore := ExplainMore . explain%a_loopfield%%a_index%
							explain%SeeBoth%%blueN1% := explain%SeeBoth%%blueN1% . ExplainMore
							explain%SeeBoth%%blueN2% := explain%SeeBoth%%blueN2% . ExplainMore
							explain%SeeBoth%%blueN3% := explain%SeeBoth%%blueN3% . ExplainMore
							stringreplace, PossibleNumbers%SeeBoth%, PossibleNumbers%SeeBoth%, %blueN1%,
							stringreplace, PossibleNumbers%SeeBoth%, PossibleNumbers%SeeBoth%, %blueN2%,
							stringreplace, PossibleNumbers%SeeBoth%, PossibleNumbers%SeeBoth%, %blueN3%,
							stringlen, PossibleNumbersLen, PossibleNumbers%SeeBoth%
							if (PossibleNumbersLen = 0 or PossibleNumbersLen = 1 and GetAll <> 1)
							{
								WhatNext = %PossibleNumbersLen%%SeeBoth%
								return 2
							}
						}
					}
					ChainText1 = %SeeWhat%# can't be in coord%SeeBoth%<red> because of the chain
					ChainText2 = If there is %SeeWhat%# in coord%cc1%, then there can't be %SeeWhat%# in coord%SeeBoth%.Else, if
					loop, %i%
					{
						ChainText1 := ChainText1 . " coord" . cc%a_index% . "<blue> - "
						ChainText2 := ChainText2 . " there is " . ncc%a_index% . "# in coord" . cc%a_index% . ", then"
					}
					stringtrimright, ChainText1, ChainText1, 3  ; trim " - "
					stringtrimright, ChainText2, ChainText2, 5  ; trim " then"
					explain%SeeBoth%%SeeWhat% = %ChainText1%: %ChainText2% and again, there can't be %SeeWhat%# in coord%SeeBoth%.
					loop, parse, chain, -
						loop, 9
							ifnotinstring, PossibleNumbers%a_loopfield%, %a_index%
								if explain%a_loopfield%%a_index% <>
									explain%SeeBoth%%SeeWhat% := explain%SeeBoth%%SeeWhat% . explain%a_loopfield%%a_index%
					stringreplace, PossibleNumbers%SeeBoth%, PossibleNumbers%SeeBoth%, %SeeWhat%,
					stringlen, PossibleNumbersLen, PossibleNumbers%SeeBoth%
					if (PossibleNumbersLen = 0 or PossibleNumbersLen = 1 and GetAll <> 1)
					{
						WhatNext = %PossibleNumbersLen%%SeeBoth%
						return 2
					}
				}
			}
		}
	}
	return fit
}

;---------------------------------------------------------------------------------------------

FillMinimumFirst:
filled =
NoChoice =
loop, parse, cells, -
{
	FillMinimumFirst%a_loopfield% := cell%a_loopfield%
	minimum%a_loopfield% = 1
}
loop
{
	gosub GetPossibleNumbers
	if WhatNext =
	{
		SolutionAtAll = 1
		loop, parse, cells, -
			FirstSolution%a_loopfield% := cell%a_loopfield%
		return
	}
	stringleft, WhatNextLeft, WhatNext, 1
	if (WhatNextLeft = "x" or WhatNextLeft = 0)
	{
		if filled =
		{
			SolutionAtAll = 0
			return
		}
		stringtrimright, filled, filled, 1
		stringright, rc, filled, 2
		minimum%rc% := cell%rc%+1
		fill(rc, 0)
		stringtrimright, filled, filled, 2
	}
	else if WhatNextLeft = 1
	{
		stringmid, rc, WhatNext, 2, 2
		if (PossibleNumbers%rc% < minimum%rc%)
		{
			if filled =
			{
				SolutionAtAll = 0
				return
			}
			minimum%rc% = 1
			stringtrimright, filled, filled, 1
			stringright, rc, filled, 2
			minimum%rc% := cell%rc%+1
			fill(rc, 0)
			stringtrimright, filled, filled, 2
		}
		else
		{
			fill(rc, PossibleNumbers%rc%)
			filled = %filled%%rc%-
			ifnotinstring, NoChoice, %rc%
				NoChoice = %NoChoice%%rc%-
			if (StopAt = 1 and rc = TryOmit and filled = NoChoice)
				return
		}
	}
	else if WhatNextLeft > 1
	{
		stringmid, rc, WhatNext, 2, 2
		CouldFill = 0
		loop, parse, PossibleNumbers%rc%
		{
			if (a_loopfield < minimum%rc%)
				continue
			fill(rc, a_loopfield)
			filled = %filled%%rc%-
			stringreplace, NoChoice, NoChoice, %rc%-,
			CouldFill = 1
			break
		}
		if CouldFill = 0
		{
			if filled =
			{
				SolutionAtAll = 0
				return
			}
			minimum%rc% = 1
			stringtrimright, filled, filled, 1
			stringright, rc, filled, 2
			minimum%rc% := cell%rc%+1
			fill(rc, 0)
			stringtrimright, filled, filled, 2
		}
	}
}
return

;---------------------------------------------------------------------------------------------

FillMaximumFirst:
filled =
loop, parse, cells, -
{
	fill(a_loopfield, FillMinimumFirst%a_loopfield%)
	maximum%a_loopfield% = 9
}
loop
{
	gosub GetPossibleNumbers
	if WhatNext =
	{
		SecondSolutionIdentical = 1
		different = 0
		loop, parse, cells, -
			if (cell%a_loopfield% <> FirstSolution%a_loopfield%)
		{
			SecondSolutionIdentical = 0
			different += 1
		}
		return
	}
	stringleft, WhatNextLeft, WhatNext, 1
	if (WhatNextLeft = "x" or WhatNextLeft = 0)
	{
		stringtrimright, filled, filled, 1
		stringright, rc, filled, 2
		maximum%rc% := cell%rc%-1
		fill(rc, 0)
		stringtrimright, filled, filled, 2
	}
	else if WhatNextLeft = 1
	{
		stringmid, rc, WhatNext, 2, 2
		if (PossibleNumbers%rc% > maximum%rc%)
		{
			maximum%rc% = 9
			stringtrimright, filled, filled, 1
			stringright, rc, filled, 2
			maximum%rc% := cell%rc%-1
			fill(rc, 0)
			stringtrimright, filled, filled, 2
		}
		else
		{
			fill(rc, PossibleNumbers%rc%)
			filled = %filled%%rc%-
		}
	}
	else if WhatNextLeft > 1
	{
		stringmid, rc, WhatNext, 2, 2
		CouldFill = 0
		loop, parse, PossibleNumbersRev%rc%
		{
			if (a_loopfield > maximum%rc%)
				continue
			fill(rc, a_loopfield)
			filled = %filled%%rc%-
			CouldFill = 1
			break
		}
		if CouldFill = 0
		{
			maximum%rc% = 9
			stringtrimright, filled, filled, 1
			stringright, rc, filled, 2
			maximum%rc% := cell%rc%-1
			fill(rc, 0)
			stringtrimright, filled, filled, 2
		}
	}
}
return

;---------------------------------------------------------------------------------------------

FillRandom:
filled =
NoChoice =
loop, parse, cells, -
	remaining%a_loopfield% = 123456789
loop
{
	gosub GetPossibleNumbers
	if WhatNext =
	{
		SolutionAtAll = 1
		return
	}
	stringleft, WhatNextLeft, WhatNext, 1
	if (WhatNextLeft = "x" or WhatNextLeft = 0)
	{
		if filled =
		{
			SolutionAtAll = 0
			return
		}
		stringtrimright, filled, filled, 1
		stringright, rc, filled, 2
		cellRC := cell%rc%
		stringreplace, remaining%rc%, remaining%rc%, %cellRC%,
		fill(rc, 0)
		stringtrimright, filled, filled, 2
	}
	else if WhatNextLeft = 1
	{
		stringmid, rc, WhatNext, 2, 2
		PossibleNumbersRC := PossibleNumbers%rc%
		ifnotinstring, remaining%rc%, %PossibleNumbersRC%
		{
			if filled =
			{
				SolutionAtAll = 0
				return
			}
			remaining%rc% = 123456789
			stringtrimright, filled, filled, 1
			stringright, rc, filled, 2
			cellRC := cell%rc%
			stringreplace, remaining%rc%, remaining%rc%, %cellRC%,
			fill(rc, 0)
			stringtrimright, filled, filled, 2
		}
		else
		{
			fill(rc, PossibleNumbers%rc%)
			filled = %filled%%rc%-
			ifnotinstring, NoChoice, %rc%
				NoChoice = %NoChoice%%rc%-
		}
	}
	else if WhatNextLeft > 1
	{
		stringmid, rc, WhatNext, 2, 2
		CouldFill = 0
		PossibleNumbersRC =
		loop, parse, PossibleNumbers%rc%
			PossibleNumbersRC = %PossibleNumbersRC%%a_loopfield%-
		stringtrimright, PossibleNumbersRC, PossibleNumbersRC, 1
		sort, PossibleNumbersRC, random d-
		loop, parse, PossibleNumbersRC, -
		{
			ifnotinstring, remaining%rc%, %a_loopfield%
				continue
			fill(rc, a_loopfield)
			filled = %filled%%rc%-
			stringreplace, NoChoice, NoChoice, %rc%-,
			CouldFill = 1
			break
		}
		if CouldFill = 0
		{
			if filled =
			{
				SolutionAtAll = 0
				return
			}
			remaining%rc% = 123456789
			stringtrimright, filled, filled, 1
			stringright, rc, filled, 2
			cellRC := cell%rc%
			stringreplace, remaining%rc%, remaining%rc%, %cellRC%,
			fill(rc, 0)
			stringtrimright, filled, filled, 2
		}
	}
}
return
Last edited by pekoe on 23 Feb 2021, 03:07, edited 75 times in total.
User avatar
oldbrother
Posts: 179
Joined: 23 Oct 2013, 05:08

Re: Sudoku

27 Mar 2016, 06:41

Very nice! :thumbup: :thumbup: :thumbup:

Is there a way to input a new Sudoku?

Thanks!
pekoe
Posts: 5
Joined: 25 Mar 2016, 11:42

Re: Sudoku

27 Mar 2016, 12:19

1. Play -> Clear board
2. Set numbers/colors with the left mouse button or the number keys.
You can save Sudokus with Sudoku -> Save as... but you can't add Sudokus to the Sudoku menu.
Last edited by pekoe on 20 Feb 2017, 10:21, edited 1 time in total.
JJohnston2
Posts: 193
Joined: 24 Jun 2015, 23:38

Re: Sudoku

27 Mar 2016, 16:00

Nice. I did have one problem where clicking on a cell and then changing a pencil note for that cell, or setting the final number for that cell, would not set the cell I just clicked on but an adjacent one instead... that was happening fairly regularly.

Otherwise, very nice... looks like you put a lot of work into it.
pekoe
Posts: 5
Joined: 25 Mar 2016, 11:42

Re: Sudoku

28 Mar 2016, 10:55

Maybe you clicked on a cell, thought you had "selected" it, then moved the mouse a little and then pressed a number key? That would explain it.
You don't have to click, just move the mouse and press the number keys.

PS: There are mouse button menus now, so it works either way.
Last edited by pekoe on 20 Feb 2017, 10:27, edited 1 time in total.
JJohnston2
Posts: 193
Joined: 24 Jun 2015, 23:38

Re: Sudoku

29 Mar 2016, 01:02

Ok that works
joefiesta
Posts: 394
Joined: 24 Jan 2016, 13:54
Location: Pa., USA

Re: Sudoku

24 May 2020, 10:52

Error: Non-existent menu item (line 1731):

gui, 1:color, %cBackground2% menu, ViewMenu, Disable, &Color numbers Ctrl+C

Occurs when using VIEW --> SWITCH between numbers and colors
pekoe
Posts: 5
Joined: 25 Mar 2016, 11:42

Re: Sudoku

15 Jan 2021, 11:33

I can't reproduce the error, maybe the tabspace in the menu item name causes the problem? Anyway, I left away the disabling and enabling of the menu item, so it can't happen again. The disabling isn't necessary because the hotkey for coloring numbers already prevents the coloring of colors.
joefiesta
Posts: 394
Joined: 24 Jan 2016, 13:54
Location: Pa., USA

Re: Sudoku

15 Jan 2021, 13:33

I haven't played this Sudoku since I reported the problem. I played today, and right after the board was loaded hit "VIEW --> SWITCH between numbers and colors" and the problem did not occur. I haven't touched the program. This tells me there is some sequence of events I must go through to have the problem occur. I haven't figured out what that sequence is, however! If I do, I'll report it.
joefiesta
Posts: 394
Joined: 24 Jan 2016, 13:54
Location: Pa., USA

Re: Sudoku

16 Jan 2021, 12:33

I see you've made some changes.

I would like to suggest the following changes:

1. Add a sizing border. Even though the gui doesn't change when sized, I like the thicker, more distinct and more visible border. Visuality is important once you get my age! (One reason I wil not use Win10 is the lack of borders.... one of dozens of reasons).
After line 124 I add:
Gui, 1: +0x40000 ; 40000: sizing border

2. Make the default background color pale blue. Why have that horrible, bright BLINDING white background for numbers?
I change line 90 to:
cBackground = %cBackground2%

3. Hide the GUI (gui 1) until the board is is done being created.
I wrap the EASY and DIFFICULT subroutines with

Gui, 1: hide
...
Gui, 1: show

this is the easy fix. you might want the board to not disappear while it is being populated. I don't like seeing the solution FLASH and then disappear.

4. If SWITCH=colors, I disable the VIEWMENU "&color numbers" entry. Rather minor, but, since it doesn't do anything, why not turn it off?

The above are all very trivial coding issues. I have, however, two more difficult suggestions.

1. After the initial board is populated, the squares that are predefined should be immutable. If I accidentally change one, I've ruined the game. And, I can't imagine why I would want to purposefully change one.

2. I would like COLOR NUMBERS to work differently (or maybe a 2nd similar function added). Once I set a color, I would like ALL subsequently added squares to AUTOMATICALLY be made that color. I want to be able to see which squares I HAVE SET and which were set initially. I would actually like this to be a default behavior, with the user-added squares a default color (which, if you don't like the idea, could be BLACK!!!).

thanks.

Love your program!

Joe P.
pekoe
Posts: 5
Joined: 25 Mar 2016, 11:42

Re: Sudoku

19 Jan 2021, 04:55

Thanks for your posts.
First, I made a tiny change with a big consequence: I thought, 2 loops were enough in GetPossibleNumbers, but it didn't solve this classic Sudoku

without a bifurcation. Now, with just one more loop, it gets the solution!
I added "Fix input" in the Sudoku menu. "Generate" and the Sudoku images are automatically fixed and "Open", "Create" and "Clear board" will lift the fix.
I didn't make other changes. I like to watch a Sudoku being created, like the backside of a clock made of glass, and I have Linux and Windows XP and my Sudoku program works fine with Wine in Linux, so I don't care much about borders in Windows, and I like a simple and pure white background for numbers. I think, a pale blue "sky" background is nice for the color Sudokus, especially for the sun Sudoku.

Return to “Scripts and Functions”

Who is online

Users browsing this forum: No registered users and 12 guests