After a "Rock paper scissors" game (https://autohotkey.com//boards/viewtopi ... 71#p188971)
I decided to write a more elaborate game : 15 Puzzle Collection
press space to shuffle the board game
you can choose between different arrangement (vertical, horizontal...)
Here is the code:
Code: Select all
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; 15 Puzzle Collection v1.0
; by Speedmaster
; AHK 1.1+
;
; (Class CtlColors) by Just_me
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
#singleinstance, force
gui, font, s20 bold
grid1:=new grid("",10,10,4,4,60,60,2,2,"gclickcell 0x201 BackGroundTrans border","z")
gui, font, s10 bold
grid2:=new grid("2",300,10,4,4,30,30,"-1","-1","0x201 BackGroundTrans border","z")
grid3:=new grid("3",300,150,1,1,130,30,0,0,"gclickcell 0x201 BackGroundTrans border","Horizontal")
grid4:=new grid("4",300,182,1,1,130,30,0,0,"gshuffle 0x201 BackGroundTrans border","Shuffle")
gui, font, s10
gui, font, csilver italic
gui, add, text, x315 y+30 , by Speedmaster
challenge:=1
board=
(
1, 2, 3, 4
5, 6, 7, 8
9,10,11,12
13,14,15, e
)
board_horizontal=
(
1, 2, 3, 4
5, 6, 7, 8
9,10,11,12
13,14,15, e
)
board_vertical=
(
1,5, 9,13
2,6,10,14
3,7,11,15
4,8,12, e
)
board_up_and_down=
(
4,5,12,13
3,6,11,14
2,7,10,15
1,8, 9, e
)
board_spiral=
(
7, 8, 9,10
6, 1, 2,11
5, 4, 3,12
e,15,14,13
)
board_peripheral=
(
1, 2, 3, 4
12,13,14, 5
11, e,15, 6
10, 9, 8, 7
)
board_diagonal=
(
7,11,14, e
4, 8,12,15
2, 5, 9,13
1, 3, 6,10
)
board_snake_swirl=
(
4, 3, 2,1
5, 6, 7,8
12,11,10,9
13,14,15,e
)
board_reverse=
(
e,15,14,13
12,11,10, 9
8, 7, 6, 5
4, 3, 2, 1
)
board_odd_first=
(
1, 3, 5, 7
9,11,13,15
2, 4, 6, 8
10,12,14, e
)
board_even_first=
(
2, 4, 6, 8
10,12,14, e
1, 3, 5, 7
9,11,13,15
)
board_odd_left=
(
1, 3, 2, 4
5, 7, 6, 8
9,11,10,12
13,15,14, e
)
board_Alternate_odd=
(
1, 3, 5, 7
2, 4, 6, 8
9,11,13,15
10,12,14, e
)
challenges:={ 1:"Horizontal", 2:"Vertical", 3:"Up_and_Down", 4:"Spiral", 5:"Peripheral", 6:"Diagonal", 7:"Snake_Swirl", 8:"Reverse", 9:"Odd_first", 10:"Even_first", 11:"Odd_left", 12:"Alternate_odd" }
AgLoadDataMap("board", ",", 4, 4)
for k, val in challenges
AgLoadDataMap("board_" val, ",", 4, 4)
rd:=0
AgDrawDataMap(databoard,, "drawchar")
AgDrawDataMap(databoard_horizontal,"2", "drawchar")
AgDrawDataMap(databoard_horizontal,"", "drawchar")
btl:="databoard_" challenges[challenge]
databoard3:=ObjFullyClone(%btl%)
CtlColors.attach(3_1_1, "F4EDBF", "black") ;button select puzzle
CtlColors.Attach(4_1_1, "8E200C", "white") ;button shuffle
gui, +resize
Gui, Color, 12500F
gui, show, autosize, 15 Puzzle Collection v1.0
return
;f2::
;debug:=!debug
;return
clickcell:
if (debug)
msgbox, % a_guicontrol
if (a_guicontrol="3_1_1")
{
databoard2:=[]
(challenge<challenges.maxindex()) ? (challenge++) : (challenge:=1)
drawchar("3_1_1", challenges[challenge])
btl:="databoard_" challenges[challenge]
AgDrawDataMap(%btl%,"2", "drawchar")
databoard2:=ObjFullyClone(databoard_horizontal)
AgDrawDataMap(databoard_horizontal,"", "drawchar")
databoard:=ObjFullyClone(databoard_horizontal)
}
databoard2:=[]
databoard3:=[]
databoard2:=ObjFullyClone(databoard)
databoard3:=ObjFullyClone(%btl%)
z:=a_guicontrol
play: ; game main loop
stringsplit,sp, % z, "_"
x:=sp1
y:=sp2
loop, 3
{
if (databoard[x][y+a_index]="e")
{
if (a_index>2)
databoard[x][y+3]:=databoard[x][y+2]
if (a_index>1)
databoard[x][y+2]:=databoard[x][y+1]
if (a_index>0)
databoard[x][y+1]:=databoard[x][y]
databoard[x][y]:="e"
}
if (databoard[x][y-a_index]="e")
{
if (a_index>2)
databoard[x][y-3]:=databoard[x][y-2]
if (a_index>1)
databoard[x][y-2]:=databoard[x][y-1]
if (a_index>0)
databoard[x][y-1]:=databoard[x][y]
databoard[x][y]:="e"
}
if (databoard[x+a_index][y]="e")
{
if (a_index>2)
databoard[x+3][y]:=databoard[x+2][y]
if (a_index>1)
databoard[x+2][y]:=databoard[x+1][y]
if (a_index>0)
databoard[x+1][y]:=databoard[x][y]
databoard[x][y]:="e"
}
if (databoard[x-a_index][y]="e")
{
if (a_index>2)
databoard[x-3][y]:=databoard[x-2][y]
if (a_index>1)
databoard[x-2][y]:=databoard[x-1][y]
if (a_index>0)
databoard[x-1][y]:=databoard[x][y]
databoard[x][y]:="e"
}
}
if (rd=0)
{
AgDrawDataMap(databoard,, "drawchar")
if (sp0<3)
checkwin()
}
return
shuffle:
~space::
rd:=1
databoard2:=[]
loop, 400
{
Random, rx, 1,4
Random, ry, 1,4
z:=rx "_" ry
gosub, play
}
rd:=0
gosub, play
return
guiclose:
~esc::
exitapp
return
checkwin()
{
global
win:=0
for i, j in databoard3
for k, l in j
{
cell:=i . "_" . k
if (databoard[i][k]=databoard3[i][k])
win++
}
if (win=16)
msgbox, Congratulations! `nYou solved the puzzle
}
class grid
{
__New(idname:=""
, gposx:=10
, gposy:=10
, cols=30
, rows:=20
, cellwidth:=""
, cellheight:=""
, wspacing:="-1"
, hspacing:="-1"
, options:="gclickcell BackGroundTrans"
, fill:="X")
{
global
this.idname:=idname
this.gposx:=gposx
this.gposy:=gposy
this.cols:=cols
this.rows:=rows
this.cellwidth:=cellwidth
this.cellheight:=cellheight
this.wspacing:=wspacing
this.hspacing:=hspacing
this.options:=options
this.fill:=fill
this.font:="bold s20"
if (idname)
this.hasname:=true
r:=0 c:=0
loop, % this.rows
{
r:= r+1
loop, % this.cols
{
c:= c+1
gui, add, text, % options (cellwidth ? " w"cellwidth : " ") (cellheight ? " h"cellheight : " ") (idname ? " v" idname "_" c "_" r " hwnd" idname "_" c "_" r : " v" c "_" r " hwnd" c "_" r ) ((c=1 && r=1) ? " x"gposx " y"gposy " section" : (c!=1 && r=1) ? " x+"wspacing " yp" : (c=1 && r!=1) ? " xs" " y+"hspacing : " x+"wspacing " yp"), %fill%
}
c:=0
}
R:=0 C:=0
} ; end off new
} ; end off class
;------------------------------------------------------------------------------------------
Even(n)
{
return mod(n, 2) = 0
}
disablecell(cell)
{
global
guicontrol, disable, %cell%
guicontrol, hide, %cell%
guicontrol, show, %cell%
}
AgLoadDataMap(InputGridMap:="Walls", colsep:="", cols:="maxcols_grid1", rows:="maxrows_grid1")
{
global
;create a col major data grid (note this function create a real 2d data matrix)
data%InputGridMap%:=[]
Loop, Parse, %InputGridMap%, `n
{
Row := A_Index
Loop, Parse, A_LoopField, %colsep% , %A_Space%%A_Tab%
{
Col := A_Index
Data%InputGridMap%[Col,Row] := A_LoopField
}
}
}
;------------------------------------------------------------
AgDrawDataMap(datagrid, gridnumber:="", function_name:="", Bypass_Values_List:="")
{
global
;funtion_name is the function to call for drawing the datas
For Col, Rows In datagrid
For Row, value In Rows
{
if (gridnumber)
cell_to_draw=%gridnumber%_%col%_%row%
else
cell_to_draw=%col%_%row%
if value not in %Bypass_Values_List%
if (databoard[col][row]!=databoard2[col][row])
%function_name%(cell_to_draw, value)
}
}
ObjFullyClone(obj)
{
nobj := obj.Clone()
for k,v in nobj
if IsObject(v)
nobj[k] := A_ThisFunc.(v)
return nobj
}
drawchar(varname, chartodraw:="@", color:="red")
{
global
stringsplit, draw, varname, _
if (draw0=2)
out:= draw1 . "_" . draw2
if (draw0=3)
out:= draw1 . "_" . draw2 . "_" draw3
guicontrol,, %out%, %chartodraw%
if (varname != "3_1_1")
if even(chartodraw)
{
showcell(varname)
CtlColors.change(%out%, "8B0000", "white")
}
else
if (chartodraw!="e")
{
showcell(varname)
CtlColors.change(%out%, "F4EDBF", "black")
}
else
if (chartodraw="e")
hidecell(varname)
}
HideCell(cell_to_hide)
{
guicontrol, hide1, %cell_to_hide%
}
ShowCell(cell_to_show)
{
guicontrol, hide0, %cell_to_show%
}
; https://autohotkey.com/boards/viewtopic.php?t=2197
; ======================================================================================================================
; AHK 1.1+
; ======================================================================================================================
; Function: Auxiliary object to color controls on WM_CTLCOLOR... notifications.
; Supported controls are: Checkbox, ComboBox, DropDownList, Edit, ListBox, Radio, Text.
; Checkboxes and Radios accept only background colors due to design.
; Namespace: CtlColors
; Tested with: 1.1.25.02
; Tested on: Win 10 (x64)
; Change log: 1.0.04.00/2017-10-30/just me - added transparent background (BkColor = "Trans").
; 1.0.03.00/2015-07-06/just me - fixed Change() to run properly for ComboBoxes.
; 1.0.02.00/2014-06-07/just me - fixed __New() to run properly with compiled scripts.
; 1.0.01.00/2014-02-15/just me - changed class initialization.
; 1.0.00.00/2014-02-14/just me - initial release.
; ======================================================================================================================
; This software is provided 'as-is', without any express or implied warranty.
; In no event will the authors be held liable for any damages arising from the use of this software.
; ======================================================================================================================
Class CtlColors {
; ===================================================================================================================
; Class variables
; ===================================================================================================================
; Registered Controls
Static Attached := {}
; OnMessage Handlers
Static HandledMessages := {Edit: 0, ListBox: 0, Static: 0}
; Message Handler Function
Static MessageHandler := "CtlColors_OnMessage"
; Windows Messages
Static WM_CTLCOLOR := {Edit: 0x0133, ListBox: 0x134, Static: 0x0138}
; HTML Colors (BGR)
Static HTML := {AQUA: 0xFFFF00, BLACK: 0x000000, BLUE: 0xFF0000, FUCHSIA: 0xFF00FF, GRAY: 0x808080, GREEN: 0x008000
, LIME: 0x00FF00, MAROON: 0x000080, NAVY: 0x800000, OLIVE: 0x008080, PURPLE: 0x800080, RED: 0x0000FF
, SILVER: 0xC0C0C0, TEAL: 0x808000, WHITE: 0xFFFFFF, YELLOW: 0x00FFFF}
; Transparent Brush
Static NullBrush := DllCall("GetStockObject", "Int", 5, "UPtr")
; System Colors
Static SYSCOLORS := {Edit: "", ListBox: "", Static: ""}
; Error message in case of errors
Static ErrorMsg := ""
; Class initialization
Static InitClass := CtlColors.ClassInit()
; ===================================================================================================================
; Constructor / Destructor
; ===================================================================================================================
__New() { ; You must not instantiate this class!
If (This.InitClass == "!DONE!") { ; external call after class initialization
This["!Access_Denied!"] := True
Return False
}
}
; ----------------------------------------------------------------------------------------------------------------
__Delete() {
If This["!Access_Denied!"]
Return
This.Free() ; free GDI resources
}
; ===================================================================================================================
; ClassInit Internal creation of a new instance to ensure that __Delete() will be called.
; ===================================================================================================================
ClassInit() {
CtlColors := New CtlColors
Return "!DONE!"
}
; ===================================================================================================================
; CheckBkColor Internal check for parameter BkColor.
; ===================================================================================================================
CheckBkColor(ByRef BkColor, Class) {
This.ErrorMsg := ""
If (BkColor != "") && !This.HTML.HasKey(BkColor) && !RegExMatch(BkColor, "^[[:xdigit:]]{6}$") {
This.ErrorMsg := "Invalid parameter BkColor: " . BkColor
Return False
}
BkColor := BkColor = "" ? This.SYSCOLORS[Class]
: This.HTML.HasKey(BkColor) ? This.HTML[BkColor]
: "0x" . SubStr(BkColor, 5, 2) . SubStr(BkColor, 3, 2) . SubStr(BkColor, 1, 2)
Return True
}
; ===================================================================================================================
; CheckTxColor Internal check for parameter TxColor.
; ===================================================================================================================
CheckTxColor(ByRef TxColor) {
This.ErrorMsg := ""
If (TxColor != "") && !This.HTML.HasKey(TxColor) && !RegExMatch(TxColor, "i)^[[:xdigit:]]{6}$") {
This.ErrorMsg := "Invalid parameter TextColor: " . TxColor
Return False
}
TxColor := TxColor = "" ? ""
: This.HTML.HasKey(TxColor) ? This.HTML[TxColor]
: "0x" . SubStr(TxColor, 5, 2) . SubStr(TxColor, 3, 2) . SubStr(TxColor, 1, 2)
Return True
}
; ===================================================================================================================
; Attach Registers a control for coloring.
; Parameters: HWND - HWND of the GUI control
; BkColor - HTML color name, 6-digit hexadecimal RGB value, or "" for default color
; ----------- Optional
; TxColor - HTML color name, 6-digit hexadecimal RGB value, or "" for default color
; Return values: On success - True
; On failure - False, CtlColors.ErrorMsg contains additional informations
; ===================================================================================================================
Attach(HWND, BkColor, TxColor := "") {
; Names of supported classes
Static ClassNames := {Button: "", ComboBox: "", Edit: "", ListBox: "", Static: ""}
; Button styles
Static BS_CHECKBOX := 0x2, BS_RADIOBUTTON := 0x8
; Editstyles
Static ES_READONLY := 0x800
; Default class background colors
Static COLOR_3DFACE := 15, COLOR_WINDOW := 5
; Initialize default background colors on first call -------------------------------------------------------------
If (This.SYSCOLORS.Edit = "") {
This.SYSCOLORS.Static := DllCall("User32.dll\GetSysColor", "Int", COLOR_3DFACE, "UInt")
This.SYSCOLORS.Edit := DllCall("User32.dll\GetSysColor", "Int", COLOR_WINDOW, "UInt")
This.SYSCOLORS.ListBox := This.SYSCOLORS.Edit
}
This.ErrorMsg := ""
; Check colors ---------------------------------------------------------------------------------------------------
If (BkColor = "") && (TxColor = "") {
This.ErrorMsg := "Both parameters BkColor and TxColor are empty!"
Return False
}
; Check HWND -----------------------------------------------------------------------------------------------------
If !(CtrlHwnd := HWND + 0) || !DllCall("User32.dll\IsWindow", "UPtr", HWND, "UInt") {
This.ErrorMsg := "Invalid parameter HWND: " . HWND
Return False
}
If This.Attached.HasKey(HWND) {
This.ErrorMsg := "Control " . HWND . " is already registered!"
Return False
}
Hwnds := [CtrlHwnd]
; Check control's class ------------------------------------------------------------------------------------------
Classes := ""
WinGetClass, CtrlClass, ahk_id %CtrlHwnd%
This.ErrorMsg := "Unsupported control class: " . CtrlClass
If !ClassNames.HasKey(CtrlClass)
Return False
ControlGet, CtrlStyle, Style, , , ahk_id %CtrlHwnd%
If (CtrlClass = "Edit")
Classes := ["Edit", "Static"]
Else If (CtrlClass = "Button") {
IF (CtrlStyle & BS_RADIOBUTTON) || (CtrlStyle & BS_CHECKBOX)
Classes := ["Static"]
Else
Return False
}
Else If (CtrlClass = "ComboBox") {
VarSetCapacity(CBBI, 40 + (A_PtrSize * 3), 0)
NumPut(40 + (A_PtrSize * 3), CBBI, 0, "UInt")
DllCall("User32.dll\GetComboBoxInfo", "Ptr", CtrlHwnd, "Ptr", &CBBI)
Hwnds.Insert(NumGet(CBBI, 40 + (A_PtrSize * 2, "UPtr")) + 0)
Hwnds.Insert(Numget(CBBI, 40 + A_PtrSize, "UPtr") + 0)
Classes := ["Edit", "Static", "ListBox"]
}
If !IsObject(Classes)
Classes := [CtrlClass]
; Check background color -----------------------------------------------------------------------------------------
If (BkColor <> "Trans")
If !This.CheckBkColor(BkColor, Classes[1])
Return False
; Check text color -----------------------------------------------------------------------------------------------
If !This.CheckTxColor(TxColor)
Return False
; Activate message handling on the first call for a class --------------------------------------------------------
For I, V In Classes {
If (This.HandledMessages[V] = 0)
OnMessage(This.WM_CTLCOLOR[V], This.MessageHandler)
This.HandledMessages[V] += 1
}
; Store values for HWND ------------------------------------------------------------------------------------------
If (BkColor = "Trans")
Brush := This.NullBrush
Else
Brush := DllCall("Gdi32.dll\CreateSolidBrush", "UInt", BkColor, "UPtr")
For I, V In Hwnds
This.Attached[V] := {Brush: Brush, TxColor: TxColor, BkColor: BkColor, Classes: Classes, Hwnds: Hwnds}
; Redraw control -------------------------------------------------------------------------------------------------
DllCall("User32.dll\InvalidateRect", "Ptr", HWND, "Ptr", 0, "Int", 1)
This.ErrorMsg := ""
Return True
}
; ===================================================================================================================
; Change Change control colors.
; Parameters: HWND - HWND of the GUI control
; BkColor - HTML color name, 6-digit hexadecimal RGB value, or "" for default color
; ----------- Optional
; TxColor - HTML color name, 6-digit hexadecimal RGB value, or "" for default color
; Return values: On success - True
; On failure - False, CtlColors.ErrorMsg contains additional informations
; Remarks: If the control isn't registered yet, Add() is called instead internally.
; ===================================================================================================================
Change(HWND, BkColor, TxColor := "") {
; Check HWND -----------------------------------------------------------------------------------------------------
This.ErrorMsg := ""
HWND += 0
If !This.Attached.HasKey(HWND)
Return This.Attach(HWND, BkColor, TxColor)
CTL := This.Attached[HWND]
; Check BkColor --------------------------------------------------------------------------------------------------
If (BkColor <> "Trans")
If !This.CheckBkColor(BkColor, CTL.Classes[1])
Return False
; Check TxColor ------------------------------------------------------------------------------------------------
If !This.CheckTxColor(TxColor)
Return False
; Store Colors ---------------------------------------------------------------------------------------------------
If (BkColor <> CTL.BkColor) {
If (CTL.Brush) {
If (Ctl.Brush <> This.NullBrush)
DllCall("Gdi32.dll\DeleteObject", "Prt", CTL.Brush)
This.Attached[HWND].Brush := 0
}
If (BkColor = "Trans")
Brush := This.NullBrush
Else
Brush := DllCall("Gdi32.dll\CreateSolidBrush", "UInt", BkColor, "UPtr")
For I, V In CTL.Hwnds {
This.Attached[V].Brush := Brush
This.Attached[V].BkColor := BkColor
}
}
For I, V In Ctl.Hwnds
This.Attached[V].TxColor := TxColor
This.ErrorMsg := ""
DllCall("User32.dll\InvalidateRect", "Ptr", HWND, "Ptr", 0, "Int", 1)
Return True
}
; ===================================================================================================================
; Detach Stop control coloring.
; Parameters: HWND - HWND of the GUI control
; Return values: On success - True
; On failure - False, CtlColors.ErrorMsg contains additional informations
; ===================================================================================================================
Detach(HWND) {
This.ErrorMsg := ""
HWND += 0
If This.Attached.HasKey(HWND) {
CTL := This.Attached[HWND].Clone()
If (CTL.Brush) && (CTL.Brush <> This.NullBrush)
DllCall("Gdi32.dll\DeleteObject", "Prt", CTL.Brush)
For I, V In CTL.Classes {
If This.HandledMessages[V] > 0 {
This.HandledMessages[V] -= 1
If This.HandledMessages[V] = 0
OnMessage(This.WM_CTLCOLOR[V], "")
} }
For I, V In CTL.Hwnds
This.Attached.Remove(V, "")
DllCall("User32.dll\InvalidateRect", "Ptr", HWND, "Ptr", 0, "Int", 1)
CTL := ""
Return True
}
This.ErrorMsg := "Control " . HWND . " is not registered!"
Return False
}
; ===================================================================================================================
; Free Stop coloring for all controls and free resources.
; Return values: Always True.
; ===================================================================================================================
Free() {
For K, V In This.Attached
If (V.Brush) && (V.Brush <> This.NullBrush)
DllCall("Gdi32.dll\DeleteObject", "Ptr", V.Brush)
For K, V In This.HandledMessages
If (V > 0) {
OnMessage(This.WM_CTLCOLOR[K], "")
This.HandledMessages[K] := 0
}
This.Attached := {}
Return True
}
; ===================================================================================================================
; IsAttached Check if the control is registered for coloring.
; Parameters: HWND - HWND of the GUI control
; Return values: On success - True
; On failure - False
; ===================================================================================================================
IsAttached(HWND) {
Return This.Attached.HasKey(HWND)
}
}
; ======================================================================================================================
; CtlColors_OnMessage
; This function handles CTLCOLOR messages. There's no reason to call it manually!
; ======================================================================================================================
CtlColors_OnMessage(HDC, HWND) {
Critical
If CtlColors.IsAttached(HWND) {
CTL := CtlColors.Attached[HWND]
If (CTL.TxColor != "")
DllCall("Gdi32.dll\SetTextColor", "Ptr", HDC, "UInt", CTL.TxColor)
If (CTL.BkColor = "Trans")
DllCall("Gdi32.dll\SetBkMode", "Ptr", HDC, "UInt", 1) ; TRANSPARENT = 1
Else
DllCall("Gdi32.dll\SetBkColor", "Ptr", HDC, "UInt", CTL.BkColor)
Return CTL.Brush
}
}