16 puzzle game/autohotkey

Revision as of 18:30, 25 July 2022 by Alpha bravo (talk | contribs) (Added AutoHotkey)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

AutoHotkey

16 Puzzle Game Gui with Solver <lang AutoHotkey>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
=====================================================================================
------------------------------
  1. 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

  1. If
=====================================================================================
Solve By Using Arrow Keys
=====================================================================================
------------------------------
  1. 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

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

}

------------------------------</lang>