16 puzzle game/autohotkey
AutoHotkey
16 Puzzle Game Gui with Solver
WW:= 44
Gui, font, S16
oHome := [], oLocation := [], oGrid := [], W := WW/2
IniRead, n, %A_ScriptFullPath%:Stream:$DATA, gridSize, gridSize, 4
loop % n**2
R := ((A_Index-1)//n) + 1
, C := Mod(A_Index-1, n) + 1
, oHome[A_Index] := {"R":R, "C":C}
; draw down arrows
x := WW
loop % n {
Gui, add, button, x%x% y%W% w%WW% h%W% -TabStop garwBtn v%A_Index%_D, ?
x := "+0"
}
; draw left and right arrows
cntr := 1
x := (n+1)*WW
Loop % n {
R := A_Index
Gui, add, button, xs-%W% y+0 w%W% h%WW% -TabStop garwBtn v%R%_R, ?
loop % n ; draw oGrid
Gui, add, button, x+0 yp w%WW% h%WW% -TabStop ggrdBtn v%R%_%A_Index%, % oGrid[R, A_Index]:=cntr++
Gui, add, button, x%x% yp w%W% h%WW% -TabStop garwBtn v%R%_L, ?
}
; darw up arrows
y := (n+1)*WW, x := "s"
loop % n {
Gui, add, button, x%x% y%Y% w%WW% h%W% -TabStop garwBtn v%A_Index%_U, ?
x := "+0"
}
y := WW*(n+1) + W + 10
Gui, add, Button, % "xs y" Y " w" n * WW " h" W+10 " gShuffle", Shuffle
Gui, add, Button, % "xs y+0 w" n * WW " h" W+10 " gReset", Reset
Gui, add, Button, % "xs y+0 w" n * WW " h" W+10 " gSolve", Solve
Gui, add, text,, Grid Size:
Gui, add, Edit, x+5 w40 vN Center, % n
Gui, add, button, x+0 w0 h0 hidden default gSubmit
;~ Gui, +AlwaysOnTop
Gui, Show, % "w" (WW*(n+2)), 16 Puzzle
SysGet, SM_CYCAPTION, 4
return
;------------------------------
solve(lRow:=0){
global
num := 0
slp := 500
; top row
loop % n
{
num++
ToolTip, % "solving # " num, 0, 0
if (oHome[num, "R"] = oLocation[num, "R"]) && (oHome[num, "C"] = oLocation[num, "C"])
continue
if (oHome[num, "R"] = oLocation[num, "R"]) && (oHome[num, "C"] <> oLocation[num, "C"]) && (num > 1) ; same row, different col
Move(oLocation[num, "C"], "D")
rowRev := false
if (abs(oLocation[num, "C"] - oHome[num, "C"]) > n/2)
rowRev := true
if (oLocation[num, "C"] > oHome[num, "C"]) && !rowRev
dir := "L"
if (oLocation[num, "C"] > oHome[num, "C"]) && rowRev
dir := "R"
if (oLocation[num, "C"] < oHome[num, "C"]) && !rowRev
dir := "R"
if (oLocation[num, "C"] < oHome[num, "C"]) && rowRev
dir := "L"
while (oLocation[num, "C"] <> oHome[num, "C"])
Move(oLocation[num, "R"], dir)
colRev := false
if (abs(oLocation[num, "R"] - oHome[num, "R"]) > n/2)
colRev := true
if (oLocation[num, "R"] > oHome[num, "R"]) && !colRev
dir := "U"
if (oLocation[num, "R"] > oHome[num, "R"]) && colRev
dir := "D"
if (oLocation[num, "R"] < oHome[num, "R"]) && !colRev
dir := "D"
if (oLocation[num, "R"] < oHome[num, "R"]) && colRev
dir := "U"
while (oLocation[num, "R"] <> oHome[num, "R"])
Move(oLocation[num, "C"], dir)
update_buttons(oGrid)
}
; general row
loop % n**2 - 2*n
{
;~ ToolTip % num
num++
ToolTip, % "solving # " num, 0, 0
if (oLocation[num, "R"] = oHome[num, "R"]) && (oLocation[num, "C"] = oHome[num, "C"])
continue
if (oLocation[num, "R"] = oHome[num, "R"]) && (oLocation[num, "C"] <> oHome[num, "C"]) ; same row, different col
{
c := oLocation[num, "C"]
Move(oLocation[num, "C"], "D")
Move(oLocation[num, "R"], "R")
Move(c, "U") ; restore previous column
}
if (oLocation[num, "C"] = oHome[num, "C"])
Move(oLocation[num, "R"], "L")
loop % oLocation[num, "R"] - oHome[num, "r"]
Move(oHome[num, "C"], "D")
while (oLocation[num, "C"] <> oHome[num, "C"])
Move(oLocation[num, "R"], "L")
while (oLocation[num, "R"] <> oHome[num, "R"])
Move(oLocation[num, "C"], "U")
update_buttons(oGrid)
}
update_buttons(oGrid)
if lRow = 1
return
lastRow()
ToolTip
}
lastRow(){
global
num++
loop % n-2
{
num++
ToolTip, % "solving # " num, 0, 0
if (oLocation[num, "R"] <> n)
{
while (oLocation[num-1, "C"] <> n-1)
Move(n, "R")
loop % n - oLocation[num, "R"]
Move(n, "D")
Move(n, "L")
Move(n, "U")
continue
}
while (oLocation[num, "C"] <> n) && (oLocation[num, "R"] = n)
Move(n, "R")
Move(n, "D")
while (oLocation[num-1, "C"] <> n-1)
Move(n, "R")
Move(n, "U")
update_buttons(oGrid)
}
celln1 := n**2 - n + 1
while (oLocation[celln1, "C"] <> 1)
Move(n, "L")
update_buttons(oGrid)
if !CheckSolved()
solve()
}
;=====================================================================================
Submit:
Gui, Submit, NoHide
IniWrite, % n, %A_ScriptFullPath%:Stream:$DATA, gridSize, gridSize
Reload
return
;=====================================================================================
^Esc::
ExitApp
;------------------------------
!1::
obj_map(oGrid)
return
;=====================================================================================
; Solve By Using Arrow Buttons
;=====================================================================================
arwBtn:
m := StrSplit(A_GuiControl, "_")
Move(m[1], m[2])
CheckSolved()
return
;=====================================================================================
; Solve By Using Mouse Drag
;=====================================================================================
;------------------------------
#If ((mText := getButtonText()) ~= "^\d+$")
~LButton::
RR := oLocation[mText].R
CC := oLocation[mText].C
DragLR := DragUD := false
CCF := RRF := 0
GuiControlGet, Pos, Pos, % RR "_" CC
MouseGetPos, mx1, my1
while % GetKeyState("Lbutton", "P")
{
CCF := CCF ? CCF : CC
RRF := RRF ? RRF : RR
MouseGetPos, mx2, my2
; Drag Left / Right
if (mx2<>mx1 && !DragUD) {
loop % n {
GuiControlGet, Pos%A_Index%, Pos, % RR "_" A_Index
GuiControl, move, % RR "_" A_Index, % "x" Pos%A_Index%X +mx2-mx1 " y" PosY
GuiControlGet, ButtonText%A_Index%,, % RR "_" A_Index
}
MouseGetPos, mx1, my1
DragLR := true
}
; Drag Up / Down
if (my2<>my1 && !DragLR) {
loop % n {
GuiControlGet, Pos%A_Index%, Pos, % A_Index "_" CC
GuiControl, move, % A_Index "_" CC, % "x" PosX " y" Pos%A_Index%Y +my2-my1
GuiControlGet, ButtonText%A_Index%,, % A_Index "_" CC
}
MouseGetPos, mx1, my1
DragUD := true
}
; Roll off Right Edge
if DragLR
GuiControlGet, Pos, Pos, % RR "_" n
if (PosX > WW*n + W) && DragLR {
loop % n {
GuiControlGet, Pos%A_Index%, Pos, % RR "_" A_Index
GuiControl, move, % RR "_" A_Index, % "x" Pos%A_Index%X - WW " y" PosY
i := A_Index-1
GuiControl,, % RR "_" A_Index, % ButtonText%i%
}
GuiControl,, % RR "_" 1, % ButtonText%n%
CCF++
;~ GuiControl, focus, % RR "_" CCF
MouseGetPos, mx1, my1
move(RR, "R")
}
; Roll off Left Edge
if DragLR
GuiControlGet, Pos, Pos, % RR "_" 1
if (PosX < W) && DragLR {
loop % n {
GuiControlGet, Pos%A_Index%, Pos, % RR "_" A_Index
GuiControl, move, % RR "_" A_Index, % "x" Pos%A_Index%X + WW " y" PosY
i := A_Index+1
GuiControl,, % RR "_" A_Index, % ButtonText%i%
}
GuiControl,, % RR "_" n, % ButtonText1
CCF--
;~ GuiControl, focus, % RR "_" CCF
MouseGetPos, mx1, my1
move(RR, "L")
}
; Roll off Bottom Edge
if DragUD
GuiControlGet, Pos, Pos, % n "_" CC
if (PosY > WW*n + W) && DragUD {
loop % n {
GuiControlGet, Pos%A_Index%, Pos, % A_Index "_" CC
GuiControl, move, % A_Index "_" CC, % "x" PosX " y" Pos%A_Index%Y - WW
i := A_Index-1
GuiControl,, % A_Index "_" CC, % ButtonText%i%
}
GuiControl,, % 1 "_" CC, % ButtonText%n%
RRF++
;~ GuiControl, focus, % RRF "_" CC
MouseGetPos, mx1, my1
move(CC, "D")
}
; Roll off Top Edge
if DragUD
GuiControlGet, Pos, Pos, % 1 "_" CC
if (PosY < W) && DragUD {
loop % n {
GuiControlGet, Pos%A_Index%, Pos, % A_Index "_" CC
GuiControl, move, % A_Index "_" CC, % "x" PosX " y" Pos%A_Index%Y + WW
i := A_Index+1
GuiControl,, % A_Index "_" CC, % ButtonText%i%
}
GuiControl,, % n "_" CC, % ButtonText1
RRF--
;~ GuiControl, focus, % RRF "_" CC
MouseGetPos, mx1, my1
move(CC, "U")
}
} ; End Drag
WinSet, Redraw,, A
if DragLR ; Place row in proper position after dragging
loop % n
GuiControl, move, % RR "_" A_Index, % "x" WW*A_Index " y" PosY
if DragUD ; Place column in proper position after dragging
loop % n
GuiControl, move, % A_Index "_" CC, % "x" PosX " y" WW*A_Index
Loop % n**2 { ; Update oGrid
R := ((A_Index-1)//n) + 1, C := Mod(A_Index-1, n) + 1
GuiControlGet, ButtonText,, % R "_" C
oGrid[R, C] := ButtonText ; update oGrid based on button locations
}
;~ Gui, show
CheckSolved()
return
#If
;=====================================================================================
; Solve By Using Arrow Keys
;=====================================================================================
;------------------------------
#If WinActive("16 Puzzle") && oGridR && oGridC
;------------------------------
Right::
Move(oGridR, "R")
GuiControl, focus, % oGridR "_" ++oGridC
CheckSolved()
return
;------------------------------
Left::
Move(oGridR, "L")
GuiControl, focus, % oGridR "_" --oGridC
CheckSolved()
return
;------------------------------
Down::
Move(oGridC, "D")
GuiControl, focus, % ++oGridR "_" oGridC
CheckSolved()
return
;------------------------------
Up::
Move(oGridC, "U")
GuiControl, focus, % --oGridR "_" oGridC
CheckSolved()
return
#If
;=====================================================================================
; SUBROUTINES
;=====================================================================================
;------------------------------
GuiEscape:
GuiClose:
ExitApp
return
;=====================================================================================
; FUNCTIONS
;=====================================================================================
;------------------------------
Move(num, Dir, update:=1){
global
local r, c, v
if (Dir="R"){ ; move row # num right
x := oGrid[num, n]
loop, % n-1
oGrid[num, n+1-A_Index] := oGrid[num, n-A_Index]
oGrid[num, 1] := x
}
if (Dir="L"){ ; move row # num left
x := oGrid[num, 1]
loop, % n-1
oGrid[num, A_Index] := oGrid[num, A_Index+1]
oGrid[num, n] := x
}
if (Dir="U"){ ; move column # num up
x := oGrid[1, Num]
loop, % n-1
oGrid[A_Index, num] := oGrid[A_Index+1, num]
oGrid[n, Num] := x
}
if (Dir="D"){ ; move column # num down
x := oGrid[n, Num]
loop, % n-1
oGrid[n+1-A_Index, num] := oGrid[n-A_Index, num]
oGrid[1, Num] := x
}
for r, obj in oGrid
for c, v in obj
oLocation[v] := {"R" : r, "C" : c}
if update
update_buttons(oGrid)
if !shuffled
return
Sleep % slp
MovesCount++
;~ WinSet, Redraw,, A
return
}
;------------------------------
CheckSolved(){
global
local r, c, v
if !Shuffled
return
cntr := 0
for R, obj in oGrid
for C, v in obj
if (oGrid[R, C]<>++cntr)
return false
Shuffled := 0
MsgBox Solved in %MovesCount% moves
return true
}
;------------------------------
update_buttons(oGrid){
for R, obj in oGrid
for C, v in obj
GuiControl,, % R "_" C, % oGrid[R, C] ; update buttons
}
;------------------------------
getButtonText(){
MouseGetPos, mx, my, mw, mc
if InStr(mc, "Button")
GuiControlGet, ButtonText,, % mc
return ButtonText
}
;------------------------------
Reset(){
global
local R, C, v
for R, obj in oGrid
for C, v in obj
GuiControl,, % R "_" C, % oGrid[R,C] := C + (R-1)*n
MovesCount := 0
}
;------------------------------
Shuffle(){
global
rows := ["R","L"], cols := ["U","D"], Shuffled := false
loop, 200 {
Random, num, 1, %n%
Random, dir, 1,2
Move(num, rows[dir], 0)
Move(num, cols[dir], 0)
if !Mod(A_Index, n )
update_buttons(oGrid)
}
update_buttons(oGrid)
Shuffled := true, MovesCount := 0
}
;------------------------------
grdBtn(){
global
m := StrSplit(A_GuiControl, "_")
oGridR:= m[1], oGridC:= m[2]
GuiControl, focus, % oGridR "_" oGridC
}
;------------------------------