Jump to content

AutoIt Mahjong game


james3mg
 Share

Recommended Posts

Hey all-

Just a little challenge to myself- I wanted to see if I could make a Mahjong game. Turns out, it was pretty easy!

Understand, this is based on the version of Mahjong that comes in Vista, which, if the description on wikipedia of Mahjong is accurate, is nothing like the actual game. This version is even further removed- for now, I've only got the numbered tiles (no dragons, seasons or flowers), and I used colors instead of the actual suites (bamboo, etc)

I kind of consider this the working framework on which someone could build a good game- it would be easy to add in the missing tiles, replace the labels with picture controls, etc. I do intend to add the ability for tiles to be staggered vertically in the future, rather than a pure grid arrangement.

One thing I had a problem with using labels as the tiles is that I had to disable the tiles that were not playable, or the tiles above them were hard to select. But if I disabled them, the text got grayed out. The only way I could prevent that was using the "simple" style, which shrunk the tiles to just the size of the text and lost the frames and other styles I'd applied to make it look better. If I can figure out a better control to use, I'll update the script here. :P

Oh, one last warning; I'm still using AutoIt 3.2.8.2, so this is all pre-3.2.10 syntax.Fixed- this code is now playable in v3.2.12.1, at least. (the only difference were some of the #include files...nice) :(

I have found a bug since posting this that I can't run down- if you choose to play another game after winning or losing, the script seems to mark some pieces as "free" (playable) that shouldn't be. If I can get that fixed, I'll update here.Fixed

Here's the code:

#include <SQLite.dll.au3>
#include <SQLite.au3>
#include <WindowsConstants.au3>
#include <GUIConstantsEx.au3>

_SQLite_Startup()
_SQLite_Open()
Global $aResult, $iRows, $iCols
Global $xSize=35, $ySize=60
Global $Suites[3]=[0xFF0000,0x00BB00,0x6666FF]

$GameGUI=GUICreate("AutoIt Mahjong by james3mg",9*$xSize,9*$ySize+20,-1,-1,$GUI_SS_DEFAULT_GUI + $WS_SIZEBOX + $WS_MAXIMIZEBOX)
GUISetBkColor(0x006600)
$StatusBar=GUICtrlCreateLabel("",0,9*$ySize,9*$xSize,20)
GUICtrlSetBkColor(-1,0xBBBBBB)
GUICtrlSetResizing(-1,576)
GUISetState()
While 1
    If Play()=7 Then Exit
WEnd

Func Play()
_SQLite_Exec(-1,"DROP TABLE IF EXISTS `pieces`")
_SQLite_Exec(-1,"CREATE TABLE `pieces` (`value`,`suite`,`x`,`y`,`z`,`GID` UNIQUE,`vis`,`free`)")

Global $NumCombos=0
;0=point,1=fortress,2=command,3=flower,4=I [heart] U
Global $Boards[5][108][2] = _;[board layount #][piece 1, piece 2, ... piece 108][x,y]
    [[[4,0],[2,1],[3,1],[4,1],[5,1],[6,1],[1,2],[2,2],[3,2],[4,2],[5,2],[6,2],[7,2],[0,3],[1,3],[2,3],[3,3],[4,3],[5,3],[6,3],[7,3],[8,3],[0,4],[1,4],[2,4],[3,4],[4,4],[5,4],[6,4],[7,4],[8,4],[0,5],[1,5],[2,5],[3,5],[4,5],[5,5],[6,5],[7,5],[8,5],[1,6],[2,6],[3,6],[4,6],[5,6],[6,6],[7,6],[2,7],[3,7],[4,7],[5,7],[6,7],[4,8], _
    [2,2],[3,2],[4,2],[5,2],[6,2],[1,3],[2,3],[3,3],[4,3],[5,3],[6,3],[7,3],[1,4],[2,4],[3,4],[4,4],[5,4],[6,4],[7,4],[1,5],[2,5],[3,5],[4,5],[5,5],[6,5],[7,5],[2,6],[3,6],[4,6],[5,6],[6,6], _
    [2,3],[3,3],[4,3],[5,3],[6,3],[2,4],[3,4],[4,4],[5,4],[6,4],[2,5],[3,5],[4,5],[5,5],[6,5], _
    [3,3],[4,3],[5,3],[3,4],[4,4],[5,4],[3,5],[4,5],[6,5]], _
    [[0,0],[1,0],[2,0],[3,0],[4,0],[5,0],[6,0],[7,0],[8,0],[8,1],[8,2],[8,3],[8,4],[8,5],[8,6],[8,7],[8,8],[7,8],[6,8],[5,8],[4,8],[3,8],[2,8],[1,8],[0,8],[0,7],[0,6],[0,5],[0,4],[0,3],[0,2],[0,1],[3,3],[4,3],[5,3],[5,4],[5,5],[4,5],[3,5],[3,4], _
    [0,2],[0,1],[0,0],[1,0],[2,0],[6,0],[7,0],[8,0],[8,1],[8,2],[8,6],[8,7],[8,8],[7,8],[6,8],[2,8],[1,8],[0,8],[0,7],[0,6],[3,5],[4,5],[5,5],[5,4],[5,3],[4,3],[3,3],[3,4],[0,4],[4,0],[8,4],[4,8], _
    [0,1],[0,0],[1,0],[7,0],[8,0],[8,1],[8,7],[8,8],[7,8],[1,8],[0,8],[0,7],[3,5],[4,5],[5,5],[5,4],[5,3],[4,3],[3,3],[3,4], _
    [3,3],[4,3],[5,3],[5,4],[5,5],[4,5],[3,5],[3,4],[0,0],[8,0],[8,8],[0,8], _
    [3,3],[5,3],[5,5],[3,5]], _
    [[0,0],[1,0],[2,0],[3,0],[4,0],[5,0],[6,0],[7,0],[8,0],[2,1],[3,1],[4,1],[5,1],[6,1],[1,2],[2,2],[3,2],[4,2],[5,2],[6,2],[7,2],[1,3],[2,3],[3,3],[4,3],[5,3],[6,3],[7,3],[1,4],[2,4],[3,4],[4,4],[5,4],[6,4],[7,4],[8,4],[1,5],[2,5],[3,5],[4,5],[5,5],[6,5],[7,5],[1,6],[2,6],[3,6],[4,6],[5,6],[6,6],[7,6],[2,7],[3,7],[4,7],[5,7],[6,7],[0,8],[1,8],[2,8],[3,8],[4,8],[5,8],[6,8],[7,8],[8,8], _
    [3,2],[4,2],[5,2],[2,3],[3,3],[4,3],[5,3],[6,3],[2,4],[3,4],[4,4],[5,4],[6,4],[7,4],[8,4],[2,5],[3,5],[4,5],[5,5],[6,5],[3,6],[4,6],[5,6], _
    [3,3],[4,3],[5,3],[3,4],[4,4],[5,4],[6,4],[7,4],[8,4],[3,5],[4,5],[5,5], _
    [4,3],[5,3],[4,4],[5,4],[6,4],[7,4],[8,4],[4,5],[5,5]], _
    [[5,2],[6,1],[7,0],[4,1],[3,0],[4,3],[3,4],[6,3],[7,4],[5,3],[5,4],[6,2],[7,2],[5,1],[5,0],[4,2],[3,2],[5,5],[5,6],[4,6],[4,7],[4,8],[0,8],[1,8],[2,8],[3,8],[5,8],[6,8],[7,8],[8,8],[6,5], _
    [5,4],[4,3],[3,2],[4,1],[5,0],[6,1],[7,2],[6,3],[4,2],[5,1],[6,2],[5,2],[5,3],[5,5],[5,6],[6,5],[4,6],[4,7],[0,8],[1,8],[2,8],[3,8],[4,8],[5,8],[6,8],[7,8],[8,8], _
    [5,2],[4,1],[5,1],[6,1],[4,2],[6,2],[4,3],[5,3],[6,3], _
    [5,2],[3,0],[5,0],[7,0],[4,1],[5,1],[6,1],[3,2],[4,2],[5,2],[6,2],[7,2],[4,3],[5,3],[6,3],[3,4],[5,4],[7,4],[5,5],[6,5],[5,6],[4,6],[4,7],[0,8],[1,8],[2,8],[3,8],[4,8],[5,8],[6,8],[7,8],[8,8], _
    [4,1],[5,1],[6,1],[4,2],[5,2],[6,2],[5,3],[4,3],[6,3]], _
    [[0,0],[0,1],[0,2],[0,3],[8,5],[8,6],[8,7],[7,8],[6,7],[6,6],[6,5],[4,2],[3,1],[2,2],[2,3],[3,4],[4,5],[5,4],[6,3],[6,2],[5,1], _
    [0,0],[0,1],[0,2],[0,3],[3,1],[5,1],[4,2],[2,2],[2,3],[3,4],[4,5],[5,4],[6,3],[6,2],[6,5],[6,6],[6,7],[7,8],[8,7],[8,6],[8,5], _
    [0,0],[0,1],[0,2],[0,3],[4,2],[3,1],[2,2],[2,3],[3,4],[4,5],[5,4],[6,3],[6,2],[5,1],[6,5],[6,6],[6,7],[7,8],[8,7],[8,6],[8,5], _
    [0,0],[0,1],[0,2],[0,3],[4,2],[3,1],[2,2],[2,3],[3,4],[4,5],[5,4],[6,3],[6,2],[5,1],[6,5],[6,6],[6,7],[7,8],[8,7],[8,6],[8,5], _
    [0,0],[0,1],[0,2],[0,3],[4,2],[3,1],[2,2],[2,3],[3,4],[4,5],[5,4],[6,3],[6,2],[5,1],[6,5],[6,6],[6,7],[7,8],[8,7],[8,6],[8,5],[3,1],[5,1],[4,5]]]
    
;this loop will assign the pieces' positions
Local $SelBoard=InputBox("Select board","Please enter the number of the board you wish to play: (0-"&UBound($Boards)-1&")",0)
If @error OR $SelBoard >= UBound($Boards) Then Exit
For $i=0 To 3
    For $s=0 To 2
        For $n=1 To 9
            Local $pos=Random(0,UBound($Boards,2)-1,1)
            _SQLite_GetTable2d(-1,"SELECT * FROM `pieces` WHERE `x`='"&$Boards[$SelBoard][$pos][0]*$xSize&"' AND `y`='"&$Boards[$SelBoard][$pos][1]*$ySize&"'",$aResult,$iRows,$iCols)
            _SQLite_Exec(-1,"INSERT INTO `pieces` (`value`,`suite`,`x`,`y`,`z`) VALUES ('"&$n&"','"&$s&"','"&$Boards[$SelBoard][$pos][0]*$xSize&"','"&$Boards[$SelBoard][$pos][1]*$ySize&"','"&$iRows&"')")
            For $a=$pos To UBound($Boards,2)-2
                $Boards[$SelBoard][$a][0]=$Boards[$SelBoard][$a+1][0]
                $Boards[$SelBoard][$a][1]=$Boards[$SelBoard][$a+1][1]
            Next
            If UBound($Boards,2)=1 Then ExitLoop
            ReDim $Boards[UBound($Boards,1)][UBound($Boards,2)-1][2]
        Next
    Next
Next

;this loop will create the pieces in the positions determined above and store them in the database
_SQLite_GetTable2d(-1,"SELECT * FROM `pieces` ORDER BY `z`,`y`,`x`",$aResult,$iRows,$iCols)
For $i=1 To $iRows
    Local $GID=GUICtrlCreateLabel($aResult[$i][0],$aResult[$i][2]+$aResult[$i][4]*3,$aResult[$i][3]+$aResult[$i][4]*3,$xSize,$ySize,0x0B)
    GUICtrlSetFont(-1,30,400,2)
    GUICtrlSetBkColor($GID,$Suites[$aResult[$i][1]])
    GUICtrlSetState($GID,$GUI_DISABLE)
    _SQLite_Exec(-1,"UPDATE `pieces` SET `GID`='"&$GID&"' WHERE `x`='"&$aResult[$i][2]&"' AND `y`='"&$aResult[$i][3]&"' AND `z`='"&$aResult[$i][4]&"'")
;Sleep(15)
Next

SetPieceState()

;now we start the actual "running" section
While 1
    Sleep(30)
    $msg=GUIGetMsg()
    If $msg=-3 Then Exit
    If $msg>0 Then
        GUICtrlSetBkColor($msg,0xFFFFFF)
        Local $FirstPiece=$msg,$FirstPieceResult,$SecondPieceResult
        While 1
            $msg=GUIGetMsg()
            If $msg=-3 Then Exit
            If $msg>0 Then
                _SQLite_GetTable2d(-1,"SELECT `GID`,`value`,`suite` FROM `pieces` WHERE `GID`='"&$FirstPiece&"'",$FirstPieceResult,$iRows,$iCols)
                _SQLite_GetTable2d(-1,"SELECT `GID`,`value`,`suite` FROM `pieces` WHERE `GID`='"&$msg&"'",$SecondPieceResult,$iRows,$iCols)
                If $SecondPieceResult[1][1] == $FirstPieceResult[1][1] AND $SecondPieceResult[1][2] == $FirstPieceResult[1][2] AND $msg <> $FirstPiece Then
                    GUICtrlDelete($msg)
                    GUICtrlDelete($FirstPiece)
                    _SQLite_Exec(-1,"DELETE FROM `pieces` WHERE `GID`='"&$FirstPiece&"'")
                    _SQLite_Exec(-1,"DELETE FROM `pieces` WHERE `GID`='"&$msg&"'")
                    Local $ReturnVal=SetPieceState()
                    If $ReturnVal <> 0 Then
                        _SQLite_GetTable2d(-1,"SELECT `GID` FROM `pieces`",$aResult,$iRows,$iCols)
                        For $i=1 To $iRows
                            GUICtrlDelete($aResult[$i][0])
                        Next
                        Local $newSize=WinGetClientSize($GameGUI)
                        $xSize=Floor($newSize[0]/9)
                        $ySize=Floor(($newSize[1]-20)/9)
                        Return $ReturnVal
                    EndIf
                Else
                    GUICtrlSetBkColor($FirstPiece,$Suites[$FirstPieceResult[1][2]])
                EndIf
                ExitLoop
            EndIf
        WEnd
    EndIf
WEnd
EndFunc

Func SetPieceState()
;first, find all the visible (topmost) pieces, and set `vis` accordingly
    _SQLite_Exec(-1,"UPDATE `pieces` SET `vis`='False'")
    _SQLite_Exec(-1,"UPDATE `pieces` SET `free`='False'")
    Local $PiecesArray,$vis,$free
    _SQLite_GetTable2d(-1,"SELECT * FROM `pieces`",$PiecesArray,$iRows,$iCols)
    For $i=1 To $iRows
        _SQLite_GetTable2d(-1,"SELECT * FROM `pieces` WHERE `x`='"&$PiecesArray[$i][2]&"' AND `y`='"&$PiecesArray[$i][3]&"' AND `z`='"&$PiecesArray[$i][4]+1&"'",$aResult,$vis,$iCols)
        _SQLite_Exec(-1,"UPDATE `pieces` SET `vis`='"&NOT $vis&"' WHERE `GID`='"&$PiecesArray[$i][5]&"'")
    Next
;now `vis` is set...time to set `free` on all the pieces which are playable
    _SQLite_GetTable2d(-1,"SELECT `GID`,`x`,`y`,`z` from `pieces` where `vis`='True'",$PiecesArray,$iRows,$iCols)
    For $i=1 To $iRows
        _SQLite_GetTable2d(-1,"SELECT `GID` FROM `pieces` WHERE `x`='"&$PiecesArray[$i][1]-$xSize&"' AND `y`='"&$PiecesArray[$i][2]&"' AND `z`='"&$PiecesArray[$i][3]&"' UNION SELECT `GID` FROM `pieces` WHERE `x`='"&$PiecesArray[$i][1]+$xSize&"' AND `y`='"&$PiecesArray[$i][2]&"' AND `z`='"&$PiecesArray[$i][3]&"'",$aResult,$free,$iCols)
        If $free < 2 Then
            _SQLite_Exec(-1,"UPDATE `pieces` SET `free`='True' WHERE `GID`='"&$PiecesArray[$i][0]&"'")
            If BitAND(GUICtrlGetState($PiecesArray[$i][0]),$GUI_DISABLE) Then;only doing this if it's necessary reduces flicker between moves.
                GUICtrlSetState($PiecesArray[$i][0],$GUI_ENABLE)
                GUICtrlSetCursor($PiecesArray[$i][0],0)
            EndIf
        EndIf
    Next
;now `free` is set...time to count possible moves
    $NumCombos=0
    Local $FreePieces,$iFreePieces
    _SQLite_Exec(-1,"DROP TABLE IF EXISTS `combos`")
    _SQLite_Exec(-1,"CREATE TABLE `combos` (`GID`)")
    _SQLite_GetTable2d(-1,"SELECT `GID`,`value`,`suite` FROM `pieces` WHERE `free`='True'",$FreePieces,$iFreePieces,$iCols)
    For $i=1 To $iFreePieces
        _SQLite_GetTable2d(-1,"SELECT `GID` FROM `pieces` WHERE `value`='"&$FreePieces[$i][1]&"' AND `suite`='"&$FreePieces[$i][2]&"' AND `GID` != '"&$FreePieces[$i][0]&"' AND `free`='True' EXCEPT SELECT `GID` FROM `combos`",$aResult,$iRows,$iCols)
        $NumCombos+=$iRows
        _SQLite_Exec(-1,"INSERT into `combos` values('"&$FreePieces[$i][0]&"')")
        For $n=1 To $iRows
            _SQLite_Exec(-1,"INSERT into `combos` values('"&$aResult[$n][0]&"')")
        Next
    Next
    TraySetToolTip($NumCombos & " moves available")
    GUICtrlSetData($StatusBar,$NumCombos & " moves available")
    _SQLite_GetTable2d(-1,"SELECT `GID` FROM `pieces`",$aResult,$iRows,$iCols)
    If $iRows=0 Then Return MsgBox(36,"Winner!","You won!"&@CRLF&@CRLF&"Play again?")
    If $NumCombos=0 Then Return MsgBox(36,"Game over","You lost...there are no more valid moves!"&@CRLF&@CRLF&"Play again?")
    Return 0
EndFunc
Edited by james3mg
"There are 10 types of people in this world - those who can read binary, and those who can't.""We've heard that a million monkeys at a million keyboards could produce the complete works of Shakespeare; now, thanks to the Internet, we know that is not true." ~Robert Wilensky0101101 1001010 1100001 1101101 1100101 1110011 0110011 1001101 10001110000101 0000111 0001000 0001110 0001101 0010010 1010110 0100001 1101110
Link to comment
Share on other sites

Can you create a compiled version, or a .zip with a compiled version? Just makes it all easier :(

No space left to upload :P
"There are 10 types of people in this world - those who can read binary, and those who can't.""We've heard that a million monkeys at a million keyboards could produce the complete works of Shakespeare; now, thanks to the Internet, we know that is not true." ~Robert Wilensky0101101 1001010 1100001 1101101 1100101 1110011 0110011 1001101 10001110000101 0000111 0001000 0001110 0001101 0010010 1010110 0100001 1101110
Link to comment
Share on other sites

Wow, this is pretty nice :(

AlmarM

EDIT:

The

"0101101 1001010 1100001 1101101 1100101 1110011 0110011 1001101 1000111

0000101 0000111 0001000 0001110 0001101 0010010 1010110 0100001 1101110"

Whats the name of that 'language'? :P

Its called 'Binary' ?

Edited by AlmarM

Minesweeper

A minesweeper game created in autoit, source available.

_Mouse_UDF

An UDF for registering functions to mouse events, made in pure autoit.

2D Hitbox Editor

A 2D hitbox editor for quick creation of 2D sphere and rectangle hitboxes.

Link to comment
Share on other sites

Thanks :P It's been updated now too, so it runs the latest syntax. I've discovered one bug I noted in the OP, and I'll see if I can't track that down next.

Edited by james3mg
"There are 10 types of people in this world - those who can read binary, and those who can't.""We've heard that a million monkeys at a million keyboards could produce the complete works of Shakespeare; now, thanks to the Internet, we know that is not true." ~Robert Wilensky0101101 1001010 1100001 1101101 1100101 1110011 0110011 1001101 10001110000101 0000111 0001000 0001110 0001101 0010010 1010110 0100001 1101110
Link to comment
Share on other sites

Wow, this is pretty nice :(

AlmarM

EDIT:

The

"0101101 1001010 1100001 1101101 1100101 1110011 0110011 1001101 1000111

0000101 0000111 0001000 0001110 0001101 0010010 1010110 0100001 1101110"

Whats the name of that 'language'? :P

Its called 'Binary' ?

Yep. Binary is the language that computers run off, and consist of only 1s and 0s.

Sweet thanks for the update, for the newest version :idea:

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...