Jump to content

Recommended Posts

Posted (edited)

Taquin image.png.6f601d02ed9686ab431e00921909b9f8.png

The Taquin is a solitary puzzle game, popular since the late 19th century, that challenges the player's logic and patience. This code implements a digital version of the Taquin, where the goal is to rearrange a set of 15 numbered tiles from 1 to 15 into ascending order by moving the tiles one at a time, in a frame of 16 spaces. The game is played on a simple and intuitive graphical interface.

Goal of the Game

The goal of Taquin is to rearrange the 15 tiles into numerical order (from 1 to 15), with an empty space, starting from a randomly shuffled configuration. The player must move the tiles using the empty space by clicking on tiles adjacent to the empty space.

Game Features

  • Graphical Interface (GUI): The game uses AutoIt to create a simple graphical interface, where the game board consists of 15 numbered tiles. The interface allows the user to see the tiles and easily move them to solve the puzzle.
  • Game Mechanics: Tiles can only be moved if they are adjacent to the empty space. By clicking on a tile, it moves into the empty space, and the game updates the display after each move.
  • Solution Verification: The game continuously checks if the tiles are in the correct order, and a victory notification is displayed when the tiles are correctly arranged.
  • Random Shuffle: At the start of the game, the tiles are randomly arranged to create a different challenge with each game.
  • Ease of Use: The game is designed to be simple to use, with controls based on mouse clicks to move the tiles.

Game Rules

  • Tile Movement: A player can move a tile by clicking on it if it is adjacent to the empty space. The objective is to move the tiles into ascending order.
  • Solution: The game ends when the tiles are arranged in the following order: 1, 2, 3, ..., 15, with the empty space at the end.

History of the Game

The Taquin was invented in the United States around 1870, before being popularized in Europe and becoming widely recognized. The invention was claimed by Sam Loyd in 1891, when the game became a global phenomenon. It is now a classic among puzzle games.

#include-once
#AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6
#include <GUIConstantsEx.au3>
#include <GDIPlus.au3>
#include "AutoItObject.au3"
#include <Array.au3>
; #INDEX# =======================================================================================================================
; Title .........: Puzzle Game
; AutoIt Version : 3.3
; AutoItObject Version : v1.2.8.2
; Language ......: English
; Description ...: This script implements a puzzle game using AutoIt and AutoItObject.au3.
; Dependencies ..: AutoItObject.au3, GDIPlus.au3
; Author ........: Numeric
; =======================================================================================================================
; Game Overview:
;   - The game consists of a grid of tiles.
;   - The objective is to arrange the tiles in numerical order by swapping them.
;   - The game ends when all tiles are correctly arranged.
;   - Tiles are shuffled randomly at the start, and the player can interact with them via mouse clicks.
; Controls:
;   - Mouse Click: Select a tile to move.
;   - Tiles swap when an adjacent empty tile is clicked.
; Enjoy solving the puzzle!
; =======================================================================================================================

_AutoItObject_Startup()
_GDIPlus_Startup()

; Classe Ligne
Func CreateLine($startX, $startY, $endX, $endY, $color = 0xFF00FF00, $thickness = 1)
    If $color = Default Or $color = "" Or Not $color Then $color = 0xFF00FF00

    Local $lineObject = _AutoItObject_Class()
    With $lineObject
        .AddProperty("StartX", $ELSCOPE_PUBLIC, $startX)
        .AddProperty("StartY", $ELSCOPE_PUBLIC, $startY)
        .AddProperty("EndX", $ELSCOPE_PUBLIC, $endX)
        .AddProperty("EndY", $ELSCOPE_PUBLIC, $endY)
        .AddProperty("Color", $ELSCOPE_PUBLIC, $color)
        .AddProperty("Thickness", $ELSCOPE_PUBLIC, $thickness)
    EndWith
    Return $lineObject.Object
EndFunc   ;==>CreateLine


Func CreateTile($xPosition, $yPosition, $size, $color = 0xFFFFFFFF)
    Local $squareObject = _AutoItObject_Class()
    Local $radius = $size / 2
    Local $lines[0]
    With $squareObject
        .Create()
        .AddProperty("Lines", $ELSCOPE_PUBLIC, $lines)
        .AddProperty("Type", $ELSCOPE_PUBLIC, "Square")
        .AddProperty("Number", $ELSCOPE_PUBLIC, 0)
        .AddProperty("X", $ELSCOPE_PUBLIC, $xPosition)
        .AddProperty("Y", $ELSCOPE_PUBLIC, $yPosition)
        .AddProperty("Size", $ELSCOPE_PUBLIC, $size)
        .AddProperty("Color", $ELSCOPE_PUBLIC, $color)
        .AddProperty("CircleRadius", $ELSCOPE_PUBLIC, $radius)
        .AddMethod("AddLine", "AddLineToSquare")
        .AddMethod("DisplayNumber", "DisplayNumberOnSquare")
        .AddMethod("Move", "MoveSquare")
        .AddMethod("Resize", "ResizeSquare")
        .AddMethod("CheckCollision", "CheckSquareCollision")
        .AddMethod("ContainsPoint", "PointInsideSquare")
    EndWith
    Return $squareObject.Object
EndFunc   ;==>CreateTile

Func AddLineToSquare($this, $line)
    Local $lineArray = $this.Lines
    _ArrayAdd($lineArray, $line)
    $this.Lines = $lineArray
EndFunc   ;==>AddLineToSquare

Func DisplayNumberOnSquare($this, $number)
    Local $lineArray[0]
    $this.Lines = $lineArray
    If $number = 0 Then $number = ""

    Local $segmentSize = $this.Size / 3
    Local $centerX = $this.X + ($this.Size / 2)
    Local $centerY = $this.Y + ($this.Size / 2)

    Local $segmentPatterns[10][7] = [ _
            [1, 1, 1, 1, 1, 1, 0], _ ; 0
            [0, 1, 1, 0, 0, 0, 0], _ ; 1
            [1, 1, 0, 1, 1, 0, 1], _ ; 2
            [1, 1, 1, 1, 0, 0, 1], _ ; 3
            [0, 1, 1, 0, 0, 1, 1], _ ; 4
            [1, 0, 1, 1, 0, 1, 1], _ ; 5
            [1, 0, 1, 1, 1, 1, 1], _ ; 6
            [1, 1, 1, 0, 0, 0, 0], _ ; 7
            [1, 1, 1, 1, 1, 1, 1], _ ; 8
            [1, 1, 1, 1, 0, 1, 1] _ ; 9
            ]

    Local $segmentCoords[7][4] = [ _
            [-0.4, -0.4, 0.4, -0.4], _ ; Haut
            [0.4, -0.4, 0.4, 0.0], _ ; Haut-droite
            [0.4, 0.0, 0.4, 0.4], _ ; Bas-droite
            [-0.4, 0.4, 0.4, 0.4], _ ; Bas
            [-0.4, 0.0, -0.4, 0.4], _ ; Bas-gauche
            [-0.4, -0.4, -0.4, 0.0], _ ; Haut-gauche
            [-0.4, 0.0, 0.4, 0.0] _ ; Milieu
            ]

    Local $currentOffsetX = -($segmentSize * (StringLen($number) - 1) / 2)
    For $digitIndex = 0 To StringLen($number) - 1
        Local $digit = Number(StringMid($number, $digitIndex + 1, 1))
        For $segmentIndex = 0 To 6
            If $segmentPatterns[$digit][$segmentIndex] Then
                Local $x1 = $centerX + $currentOffsetX + $segmentCoords[$segmentIndex][0] * $segmentSize
                Local $y1 = $centerY + $segmentCoords[$segmentIndex][1] * $segmentSize
                Local $x2 = $centerX + $currentOffsetX + $segmentCoords[$segmentIndex][2] * $segmentSize
                Local $y2 = $centerY + $segmentCoords[$segmentIndex][3] * $segmentSize
                $this.AddLine(CreateLine($x1, $y1, $x2, $y2, Default, 2))
            EndIf
        Next
        $currentOffsetX += $segmentSize * 1.2
    Next
EndFunc   ;==>DisplayNumberOnSquare

Func PointInsideSquare($this, $pointX, $pointY)
    Return ($pointX >= $this.X And $pointX <= $this.X + $this.Size) And _
            ($pointY >= $this.Y And $pointY <= $this.Y + $this.Size)
EndFunc   ;==>PointInsideSquare

Func CheckSquareCollision($this, $otherSquare)
    If $this.Type = "Square" And $otherSquare.Type = "Square" Then
        Local $isAdjacentHorizontally = ($this.Y = $otherSquare.Y And $this.Size = $otherSquare.Size) And _
                (($this.X + $this.Size = $otherSquare.X) Or ($this.X = $otherSquare.X + $otherSquare.Size))

        Local $isAdjacentVertically = ($this.X = $otherSquare.X And $this.Size = $otherSquare.Size) And _
                (($this.Y + $this.Size = $otherSquare.Y) Or ($this.Y = $otherSquare.Y + $otherSquare.Size))

        Return $isAdjacentHorizontally Or $isAdjacentVertically
    EndIf
    Return False
EndFunc   ;==>CheckSquareCollision


Func CreatePuzzleGame($backgroundColor = 0xFF0000FF)
    Local $window = GUICreate("Puzzle Game", 400, 400)
    GUISetState()

    Local $windowSize = WinGetClientSize($window)
    Local $windowWidth = $windowSize[0]
    Local $windowHeight = $windowSize[1]

    Local $graphicsContext[]
    $graphicsContext["Graphics"] = _GDIPlus_GraphicsCreateFromHWND($window)
    $graphicsContext["Bitmap"] = _GDIPlus_BitmapCreateFromGraphics($windowWidth, $windowHeight, $graphicsContext["Graphics"])
    $graphicsContext["GraphicsObject"] = _GDIPlus_ImageGetGraphicsContext($graphicsContext["Bitmap"])
    $graphicsContext["BackgroundBrush"] = _GDIPlus_BrushCreateSolid($backgroundColor)

    Local $tileSize = Int($windowWidth / 4)
    Local $tiles[]

    Local $index = 0
    Local $numbers[16] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 10, 11, 12, 13, 14, 15]
    _ArrayShuffle($numbers)

    For $row = 0 To 3
        For $col = 0 To 3
            Local $tile = CreateTile($col * $tileSize, $row * $tileSize, $tileSize)
            $tile.Number = $numbers[$index]
            $tile.DisplayNumber($tile.Number)
            $index += 1
            $tiles[$index] = $tile
        Next
    Next

    Local $game = _AutoItObject_Class()
    With $game
        .Create()
        .AddProperty("Tiles", $ELSCOPE_PUBLIC, $tiles)
        .AddProperty("GraphicsContext", $ELSCOPE_PUBLIC, $graphicsContext)
        .AddProperty("Window", $ELSCOPE_PUBLIC, $window)
        .AddProperty("WindowWidth", $ELSCOPE_PUBLIC, $windowWidth)
        .AddProperty("WindowHeight", $ELSCOPE_PUBLIC, $windowHeight)
        .AddMethod("Render", "RenderPuzzle")
        .AddMethod("Reset", "ResetPuzzle")
        .AddMethod("CheckVictory", "VerifyWinCondition")
        .AddMethod("Run", "StartGameLoop")

        .AddMethod("HandleClick", "ProcessMouseClick")
        .AddMethod("GetTileAtPosition", "FindTileAtCoordinates")
        .AddMethod("GetEmptyAdjacentTile", "FindEmptyNeighbor")
        .AddMethod("SwapTiles", "ExchangeTiles")
        .AddMethod("UpdateDisplay", "RefreshDisplay")

        .AddDestructor("ReleaseResources")
    EndWith
    Return $game.Object
EndFunc   ;==>CreatePuzzleGame

Func StartGameLoop($this)
    Local $msg
    While 1
        $msg = GUIGetMsg(1)
        Switch $msg[0]
            Case $GUI_EVENT_CLOSE
                ExitLoop

            Case $GUI_EVENT_PRIMARYDOWN
                $this.HandleClick($msg[3], $msg[4])
                $this.Render()
        EndSwitch
        $this.Render()
    WEnd
EndFunc   ;==>StartGameLoop


; Gestion des clics de souris
Func ProcessMouseClick($this, $x, $y)
    Local $clickedTileIndex = $this.GetTileAtPosition($x, $y)
    If Not $clickedTileIndex Then Return

    Local $emptyTileIndex = $this.GetEmptyAdjacentTile($clickedTileIndex)
    If $emptyTileIndex Then
        $this.SwapTiles($clickedTileIndex, $emptyTileIndex)
        $this.UpdateDisplay()
        If $this.CheckVictory() Then
            MsgBox(0, "Congratulations!", "You have solved the puzzle")
            $this.Reset()
        EndIf
    EndIf
EndFunc   ;==>ProcessMouseClick

; Trouve une tuile à une position donnée
Func FindTileAtCoordinates($this, $x, $y)
    For $tileKey In MapKeys($this.Tiles)
        Local $tile = $this.Tiles[$tileKey]

        If $tile.ContainsPoint($x, $y) Then
            Return $tileKey
        EndIf
    Next
    Return Null
EndFunc   ;==>FindTileAtCoordinates

; Trouve une tuile vide adjacente
Func FindEmptyNeighbor($this, $tileKey)
    Local $currentTile = $this.Tiles[$tileKey]
    Local $tileKeys = MapKeys($this.Tiles)

    For $key In $tileKeys
        Local $neighbor = $this.Tiles[$key]
        If $neighbor.Number = 0 And _
                $neighbor <> $currentTile And _
                $currentTile.CheckCollision($neighbor) Then
            Return $key
        EndIf
    Next
    Return Null
EndFunc   ;==>FindEmptyNeighbor

; Échange les numéros entre deux tuiles
Func ExchangeTiles($this, $tile1Key, $tile2Key)
    Local $tiles = $this.Tiles
    Local $temp = $tiles[$tile1Key].Number

    $tiles[$tile2Key].Number = $temp
    $tiles[$tile1Key].Number = 0
    $this.Tiles = $tiles
EndFunc   ;==>ExchangeTiles

; Met à jour l'affichage des tuiles
Func RefreshDisplay($this)
    For $tile In $this.Tiles
        $tile.DisplayNumber($tile.Number)
    Next
EndFunc   ;==>RefreshDisplay

; Affiche le plateau de jeu
Func RenderPuzzle($this)
    Local $graphicsContext = $this.GraphicsContext
    Local $graphics = $graphicsContext["GraphicsObject"]
    Local $pen = _GDIPlus_PenCreate(0xFFFF0000, 2)
    _GDIPlus_GraphicsClear($graphics, 0xFF000000)

    Local $tiles = $this.Tiles
    For $tile In $tiles
        _GDIPlus_GraphicsDrawRect($graphics, $tile.X, $tile.Y, $tile.Size, $tile.Size, $pen)
        For $line In $tile.Lines
            Local $linePen = _GDIPlus_PenCreate($line.Color, $line.Thickness)
            _GDIPlus_GraphicsDrawLine($graphics, $line.StartX, $line.StartY, $line.EndX, $line.EndY, $linePen)
            _GDIPlus_PenDispose($linePen)
        Next
    Next

    _GDIPlus_PenDispose($pen)
    _GDIPlus_GraphicsDrawImageRect($graphicsContext["Graphics"], $graphicsContext["Bitmap"], 0, 0, $this.WindowWidth, $this.WindowHeight)
EndFunc   ;==>RenderPuzzle

Func ResetPuzzle($this)
    Local $numbers[16] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 10, 11, 12, 13, 14, 15]
    _ArrayShuffle($numbers)

    Local $tiles = $this.Tiles
    For $i = 0 To UBound($tiles) - 1
        $tiles[$i].Number = $numbers[$i]
        $tiles[$i].DisplayNumber($tiles[$i].Number)
    Next
EndFunc   ;==>ResetPuzzle

; Vérifie la condition de victoire
Func VerifyWinCondition($this)
    Local $tiles = $this.Tiles
    For $i = 1 To UBound($tiles) - 1
        ; Les cases doivent être triées de 1 à 15, avec la dernière case vide (0)
        If $tiles[$i].Number <> $i Then
            Return False
        EndIf
    Next
    Return True
EndFunc   ;==>VerifyWinCondition

; Libère les ressources
Func ReleaseResources($this)
    Local $graphicsContext = $this.GraphicsContext
    _GDIPlus_BrushDispose($graphicsContext["BackgroundBrush"])
    _GDIPlus_GraphicsDispose($graphicsContext["Graphics"])
    _GDIPlus_BitmapDispose($graphicsContext["Bitmap"])
    GUIDelete($graphicsContext["BoardWindow"])
    _GDIPlus_Shutdown()
EndFunc   ;==>ReleaseResources

Global $game = CreatePuzzleGame()
$game.Run()
$game = 0

Have fun! 

Edited by Numeric1

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
  • Recently Browsing   0 members

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