Numeric1 Posted 11 hours ago Posted 11 hours ago (edited) While browsing through old scientific magazine archives, I stumbled upon a very interesting subject: GASP. This captivating puzzle, introduced in Jeux & Stratégie magazine issue 38 (April/May 1986), combines simple rules with complex strategies. It’s the perfect challenge for logical minds, curious puzzle enthusiasts, and programmers looking for innovative implementations. Game Rules Objective: The goal is to flip all the pieces on the board so that they display a uniform color (e.g., all black or all white). Initial Setup: The game is played on an n x n grid. Each square contains a two-colored piece (one black side and one white side). At the start, all pieces are black-side up. Gameplay Mechanics: On each turn, the player selects a square on the grid. The pieces located in the neighboring squares of the selected square then flip their color (but the selected square itself does not flip). The definition of neighboring squares depends on the square's position: Center squares: 8 neighbors. Edge squares: 5 neighbors. Corner squares: 3 neighbors. Winning Condition: The player wins when all the pieces on the grid display the same color, whether black or white. Dependencies: AutoItObject.au3 expandcollapse popup#include-once #AutoIt3Wrapper_Au3Check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 ; ======================================================================================================================= ; Title .........: GASP Puzzle Game ; AutoIt Version : 3.3 ; AutoItObject Version : v1.2.8.2 ; Language ......: English ; Description ...: A digital adaptation of the GASP puzzle, a game first introduced in Jeux & Stratégie magazine in 1986. ; Dependencies ..: AutoItObject.au3, GDIPlus.au3 ; Author ........: Numeric ; ======================================================================================================================= #include <GUIConstantsEx.au3> #include <GDIPlus.au3> #include "AutoItObject.au3" #include <Array.au3> #include <Math.au3> #include <WinAPISysWin.au3> _AutoItObject_Startup() _GDIPlus_Startup() Func CreateSquare($x, $y, $size, $color = 0xFFFFFFFF) Local $squareObj = _AutoItObject_Class() Local $radius = $size / 2 ; Circle radius = half the smallest square dimension With $squareObj .Create() .AddProperty("Type", $ELSCOPE_PUBLIC, "Square") .AddProperty("isClicked", $ELSCOPE_PUBLIC, False) .AddProperty("X", $ELSCOPE_PUBLIC, $x) .AddProperty("Y", $ELSCOPE_PUBLIC, $y) .AddProperty("Size", $ELSCOPE_PUBLIC, $size) .AddProperty("Color", $ELSCOPE_PUBLIC, $color) .AddProperty("CircleRadius", $ELSCOPE_PUBLIC, $radius) .AddMethod("Move", "_MoveSquare") .AddMethod("Resize", "_ResizeSquare") .AddMethod("CollideWith", "_CollideWithSquare") .AddMethod("ContainsPoint", "_ContainsPointSquare") EndWith Return $squareObj.Object EndFunc ;==>CreateSquare Func _ContainsPointSquare($this, $px, $py) ; Checks if the point is within the square boundaries Return ($px >= $this.X And $px <= $this.X + $this.Size) And _ ($py >= $this.Y And $py <= $this.Y + $this.Size) EndFunc ;==>_ContainsPointSquare Func _CollideWithSquare($this, $otherShape) If $this.Type = "Square" And $otherShape.Type = "Square" Then ; Square-to-square collision Return Not ( _ $this.X + $this.Size < $otherShape.X Or _ $this.X > $otherShape.X + $otherShape.Size Or _ $this.Y + $this.Size < $otherShape.Y Or _ $this.Y > $otherShape.Y + $otherShape.Size) ElseIf $this.Type = "Square" And $otherShape.Type = "Circle" Then ; Square-to-circle collision Local $closestX = _Max($this.X, _Min($otherShape.X, $this.X + $this.Size)) Local $closestY = _Max($this.Y, _Min($otherShape.Y, $this.Y + $this.Size)) Local $dx = $otherShape.X - $closestX Local $dy = $otherShape.Y - $closestY Return ($dx * $dx + $dy * $dy) <= ($otherShape.Radius * $otherShape.Radius) EndIf Return False EndFunc ;==>_CollideWithSquare Func CheckWinner($this) If $this.essai <= 2 Then Return False Local $squares = $this.Squares Local $firstColor = $squares[0].Color ; Check if all circles have the same color For $square In $squares If $square.Color <> $firstColor Then Return False EndIf Next Return True EndFunc ;==>CheckWinner Func CreateMaze($backgroundColor = 0xFF000000) Local $board = GUICreate("GASP", 400, 400) GUISetState() Local $boardDimensions = WinGetClientSize($board) Local $boardWidth = $boardDimensions[0] Local $boardHeight = $boardDimensions[1] Local $gdiMap[] $gdiMap["hGraphics"] = _GDIPlus_GraphicsCreateFromHWND($board) $gdiMap["hBitmap"] = _GDIPlus_BitmapCreateFromGraphics($boardWidth, $boardHeight, $gdiMap["hGraphics"]) $gdiMap["hGraphicsContext"] = _GDIPlus_ImageGetGraphicsContext($gdiMap["hBitmap"]) ; Add squares to a 4x4 grid Local $squareSize = Int($boardWidth / 4) ; Size of a square Local $squares[0] For $iLine = 0 To 3 For $iCol = 0 To 3 ; Calculate the position (x, y) for each square Local $x = $iCol * $squareSize Local $y = $iLine * $squareSize ; Add a square with the specified dimensions and color Local $square = CreateSquare($x, $y, $squareSize) _ArrayAdd($squares, $square) Next Next Local $mazeObj = _AutoItObject_Class() With $mazeObj .Create() .AddProperty("bkColor", $ELSCOPE_PUBLIC, $backgroundColor) .AddProperty("essai", $ELSCOPE_PUBLIC, 0) .AddProperty("Squares", $ELSCOPE_PUBLIC, $squares) .AddProperty("GdiMap", $ELSCOPE_PUBLIC, $gdiMap) .AddProperty("Board", $ELSCOPE_PUBLIC, $board) .AddProperty("BoardWidth", $ELSCOPE_PUBLIC, $boardWidth) .AddProperty("BoardHeight", $ELSCOPE_PUBLIC, $boardHeight) .AddMethod("DrawStage", "_DrawStage") .AddMethod("ResetGame", "_ResetGame") .AddMethod("RunGameLoop", "_RunGameLoop") .AddMethod("CleanUpResources", "_CleanUpResources") .AddMethod("CheckWinner", "CheckWinner") .AddDestructor("_CleanUpResources") EndWith Return $mazeObj.Object EndFunc ;==>CreateMaze Func _DrawStage($this) Local $gdiMap = $this.GdiMap Local $hGraphicsCtx = $gdiMap["hGraphicsContext"] Local $hPen = _GDIPlus_PenCreate(0xFFFF0000, 2) _GDIPlus_GraphicsClear($hGraphicsCtx, $this.bkColor) ; Draw each square and centered circle For $square In $this.Squares _GDIPlus_GraphicsDrawRect($hGraphicsCtx, $square.X, $square.Y, $square.Size, $square.Size, $hPen) Local $circleX = $square.X + ($square.Size / 2) - ($square.CircleRadius / 2) Local $circleY = $square.Y + ($square.Size / 2) - ($square.CircleRadius / 2) Local $hBrush = _GDIPlus_BrushCreateSolid($square.Color) _GDIPlus_GraphicsFillEllipse($hGraphicsCtx, $circleX, $circleY, $square.CircleRadius, $square.CircleRadius, $hBrush) _GDIPlus_BrushDispose($hBrush) Next _GDIPlus_PenDispose($hPen) _WinAPI_SetWindowText($this.Board, "GASP: Number of attempts: " & $this.essai) ; Redraw the image on the graphics context _GDIPlus_GraphicsDrawImageRect($gdiMap["hGraphics"], $gdiMap["hBitmap"], 0, 0, $this.BoardWidth, $this.BoardHeight) EndFunc ;==>_DrawStage Func _RunGameLoop($this) Local $msg While 1 $msg = GUIGetMsg(1) Switch $msg[0] Case $GUI_EVENT_CLOSE ExitLoop Case $GUI_EVENT_PRIMARYDOWN Local $selectedSquare = Null Local $x = $msg[3] Local $y = $msg[4] For $square In $this.Squares If $square.ContainsPoint($x, $y) And $square.isClicked = False Then $selectedSquare = $square ExitLoop EndIf Next If Null <> $selectedSquare Then $this.essai += 1 For $square In $this.Squares $square.isClicked = False $selectedSquare.isClicked = True If $selectedSquare.CollideWith($square) And $square <> $selectedSquare Then Switch $square.Color Case -1 $square.Color = 0xFFFFFF00 Case -256 $square.Color = 0xFFFFFFFF EndSwitch EndIf Next EndIf ; Check if the player has won If $this.CheckWinner() Then MsgBox(0, "Congratulations", "You won! All squares have the same color.") ExitLoop EndIf EndSwitch $this.DrawStage() WEnd EndFunc ;==>_RunGameLoop Func _ResetGame($this) ; Resets all squares to their default color (white) For $square In $this.Squares $square.Color = 0xFFFFFFFF ; White Next $this.essai = 0 ; Reset the number of attempts $this.DrawStage() EndFunc ;==>_ResetGame Func _CleanUpResources($this) ; Releases all GDI+ resources and destroys the GUI window Local $gdiMap = $this.GdiMap _GDIPlus_GraphicsDispose($gdiMap["hGraphicsContext"]) _GDIPlus_BitmapDispose($gdiMap["hBitmap"]) _GDIPlus_GraphicsDispose($gdiMap["hGraphics"]) GUIDelete($this.Board) EndFunc ;==>_CleanUpResources Global $maze = CreateMaze() $maze.RunGameLoop() Edited 6 hours ago by Numeric1 Fixed the issue of successive clicks.
argumentum Posted 10 hours ago Posted 10 hours ago Thanks for sharing. Now, if I click twice the same square I win. I like that. Am a sore looser. But am sure that there must be something in the rules like don't play alone or 2 player board or something to make it challenging. Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting.
Somerset Posted 10 hours ago Posted 10 hours ago 12 minutes ago, argumentum said: Thanks for sharing. Now, if I click twice the same square I win. I like that. Am a sore looser. But am sure that there must be something in the rules like don't play alone or 2 player board or something to make it challenging. don't hurt yourself if you come in 3rd.
argumentum Posted 10 hours ago Posted 10 hours ago ..pardon the late reply @Somerset. Had to change the keyboard. I was WASD the keyboard and the game did nothing, NOTHING. ...it got out of hand. Funny enough, it's played with the mouse Anyway. Got it. I won !. Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting.
Numeric1 Posted 5 hours ago Author Posted 5 hours ago 4 hours ago, argumentum said: Thanks for sharing. Now, if I click twice the same square I win. I like that. Am a sore looser. But am sure that there must be something in the rules like don't play alone or 2 player board or something to make it challenging. Thank you for pointing that out! I've just fixed the issue with successive clicks on the same square, so now you can't win by clicking the same square twice. 😊 As for the rules, you're absolutely right—adding a two-player mode or some extra challenges could make the game much more engaging. I’ll definitely consider adding those features in future updates! argumentum 1
argumentum Posted 5 hours ago Posted 5 hours ago ..still, a corner, the opposite diagonal corner and that too is a win. Therefore dClick is not the only way. It's a pickle. That is why I was asking for the complete rules from the article. Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting.
Numeric1 Posted 5 hours ago Author Posted 5 hours ago 4 hours ago, argumentum said: ..pardon the late reply @Somerset. Had to change the keyboard. I was WASD the keyboard and the game did nothing, NOTHING. ...it got out of hand. Funny enough, it's played with the mouse Anyway. Got it. I won !. @argumentum End the random victories 🕶️. And most importantly, don't forget the mouse this time, it’s going to work a lot now. Yep... it was a bug 😂. argumentum 1
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now