Minesweeper - Felder aufdecken Bug

  • Hi Community,

    ich habe versucht Minesweeper zu programmieren. Allerdings hänge ich zur Zeit an einem Problem. Ich habe es einmal versucht in einem Video ständlich zu zeigen.

    Es werden nicht alle Felder, die an freie Felder grenzen, aufgedeckt (extra nochmal ein Bild im Anhang). Im Quellcode ist die Funktion "_OpenField($iY, $iX)" für das Aufdecken verantwortlich.

    Funktion: _OpenField($iY, $iX) mit der Funktion "_IsPosRange($iY,$iX)":

    [autoit]


    Func _OpenField($iY, $iX)
    ;ConsoleWriteError("+> Row: " & $iY & " Column: " & $iX & @CRLF)
    If $aGameField[$iY][$iX] = 0 And $aGameField[$iY][$iX] <> 9 Then
    ; ------------------------------------------------
    ; INFO:
    ;
    ; - $aGameField[$iY][$iX] = 0 -> freies Feld
    ; - $aGameField[$iY][$iX] = 9 -> Bombe auf Feld
    ; - $aGameField[$iY][$iX] = 1 -> Feld hat Nummer 1
    ; - $aGameField[$iY][$iX] = 2 -> Feld hat Nummer 2
    ; - ....
    ; - $aGameField[$iY][$iX] = 8 -> Feld hat Nummer 8
    ; ------------------------------------------------
    ; - $aOpenFields[$iY][$iX] = 1 -> Feld ist "offen" und wird angezeigt
    ; - $aOpenFields[$iY][$iX] = 0 -> Feld ist noch verschlossen und wird nicht angezeigt
    ; ------------------------------------------------

    [/autoit][autoit][/autoit][autoit]

    If $aOpenFields[$iY][$iX] = 0 Then
    ConsoleWriteError("+> Debug_Open - " & "X: " & $iX & " - Y: " & $iY & @CRLF)
    $aOpenFields[$iY][$iX] = 1
    If _IsPosRange($iY, $iX + 1) Then _OpenField($iY, $iX + 1)
    If _IsPosRange($iY, $iX - 1) Then _OpenField($iY, $iX - 1)
    If _IsPosRange($iY + 1, $iX) Then _OpenField($iY + 1, $iX)
    If _IsPosRange($iY - 1, $iX) Then _OpenField($iY - 1, $iX)
    If _IsPosRange($iY - 1, $iX - 1) Then $aOpenFields[$iY - 1][$iX - 1] = 1
    If _IsPosRange($iY + 1, $iX - 1) Then $aOpenFields[$iY + 1][$iX - 1] = 1
    If _IsPosRange($iY - 1, $iX + 1) Then $aOpenFields[$iY - 1][$iX + 1] = 1
    If _IsPosRange($iY + 1, $iX + 1) Then $aOpenFields[$iY + 1][$iX + 1] = 1
    EndIf
    EndIf
    EndFunc ;==>_OpenField

    [/autoit][autoit][/autoit][autoit]

    Func _IsPosRange($iY, $iX)
    If $iX >= 0 And $iY >= 0 And $iX <= $iColumn - 1 And $iY <= $iRow - 1 Then
    Return True
    Else
    Return False
    EndIf
    EndFunc ;==>_IsPosRange

    [/autoit]

    Der gesamte Spiel-Quellcode:

    Spoiler anzeigen
    [autoit]


    #include <Array.au3>
    #include <GDIPlus.au3>
    #include <GUIConstantsEx.au3>
    #include <WindowsConstants.au3>
    #include <StaticConstants.au3>

    [/autoit] [autoit][/autoit] [autoit]

    Opt("GuiOnEventMode", 1)

    [/autoit] [autoit][/autoit] [autoit]

    HotKeySet("u", "_UnhideMap")
    HotKeySet("h", "_HideMap")

    [/autoit] [autoit][/autoit] [autoit]

    Global Const $iRow = 11 ; Reihe
    Global Const $iColumn = 11 ; Spalte
    Global Const $iMaxY = $iRow - 1
    Global Const $iMaxX = $iColumn - 1
    Global $aGameField[$iRow][$iColumn]
    Global $aOpenFields[$iRow][$iColumn]
    Global $aGameFieldPic[$iRow][$iColumn]
    Global $iShift_X = 16
    Global $iShift_Y = 80
    Global $iHSX = 5
    Global $iTimer = 0
    Global $iMines[3] = [10, 40, 99]

    [/autoit] [autoit][/autoit] [autoit]

    Global $iGameMode = 0
    ; 0 - Anfänger
    ; 1 - Fortgeschrittener
    ; 2 - Profi

    [/autoit] [autoit][/autoit] [autoit]

    Global $iDebug_Partner = 0

    [/autoit] [autoit][/autoit] [autoit]

    Global $hWindow_Main = GUICreate("Minesweeper", 252, 335)
    GUISetIcon("C:\Users\johannes\Documents\[Prog] Minesweeper\icons\bomb.ico")
    GUISetOnEvent(-3, "_Exit")
    $MenuItem = GUICtrlCreateMenu("&Spiel")
    GUICtrlCreateLabel("", 36 + $iHSX, 16, 43, 29, $WS_BORDER)
    GUICtrlSetBkColor(-1, 0x000000)
    $hIcon_Smiley = GUICtrlCreateIcon(@ScriptDir & "\icons\big_smile.ico", -1, 100 + $iHSX, 8, 48, 48, BitOR($SS_NOTIFY, $WS_GROUP))
    GUICtrlCreateLabel("", 164 + $iHSX, 16, 43, 29, $WS_BORDER)
    GUICtrlSetBkColor(-1, 0x000000)
    GUISetState(@SW_SHOW, $hWindow_Main)

    [/autoit] [autoit][/autoit] [autoit]

    _GDIPlus_Startup()
    Global $aGraphic_Dig = _CreateImages(@ScriptDir & "\digital_num.gif", 9, 21, 11, 21)
    Global $aGraphic_Item = _CreateImages(@ScriptDir & "\items.gif", 12, 20, 20, 20)

    [/autoit] [autoit][/autoit] [autoit]

    $hGraphic = _GDIPlus_GraphicsCreateFromHWND($hWindow_Main)
    _GDIPlus_GraphicsDrawImage($hGraphic, $aGraphic_Dig[0], 40 + $iHSX, 20)
    _GDIPlus_GraphicsDrawImage($hGraphic, $aGraphic_Dig[0], 52 + $iHSX, 20)
    _GDIPlus_GraphicsDrawImage($hGraphic, $aGraphic_Dig[0], 64 + $iHSX, 20)

    [/autoit] [autoit][/autoit] [autoit]

    _GDIPlus_GraphicsDrawImage($hGraphic, $aGraphic_Dig[2], 168 + $iHSX, 20)
    _GDIPlus_GraphicsDrawImage($hGraphic, $aGraphic_Dig[3], 180 + $iHSX, 20)
    _GDIPlus_GraphicsDrawImage($hGraphic, $aGraphic_Dig[9], 192 + $iHSX, 20)

    [/autoit] [autoit][/autoit] [autoit]

    _CreateGameField(1)

    [/autoit] [autoit][/autoit] [autoit]

    ;_OpenField()

    [/autoit] [autoit][/autoit] [autoit]

    AdlibRegister("_Timer", 1000)
    ;_ArrayDisplay($aGameFieldPic)
    While 1
    Sleep(20000)
    WEnd

    [/autoit] [autoit][/autoit] [autoit]

    Func _CreateGameField($iMode = -1)
    For $iY = 0 To $iRow - 1
    For $iX = 0 To $iColumn - 1
    _GDIPlus_GraphicsDrawImage($hGraphic, $aGraphic_Item[0], 20 * $iX + $iShift_X, 20 * $iY + $iShift_Y)
    If $iMode = 1 Then
    $aGameFieldPic[$iY][$iX] = GUICtrlCreatePic("", 20 * $iX + $iShift_X, 20 * $iY + $iShift_Y, 20, 20)
    GUICtrlSetOnEvent(-1, "_ClickField")
    EndIf
    $aGameField[$iY][$iX] = 0
    Next
    Next
    _SetMines()
    Opt("GuiOnEventMode", 1)
    EndFunc ;==>_CreateGameField

    [/autoit] [autoit][/autoit] [autoit]

    Func _SetMines()
    $i = 0
    Do
    $iY = Random(0, $iRow - 1, 1)
    $iX = Random(0, $iColumn - 1, 1)
    If $aGameField[$iY][$iX] <> 9 Then
    $aGameField[$iY][$iX] = 9
    _SetNeighbors($iY, $iX)
    $i += 1
    EndIf
    Until $iMines[$iGameMode] = $i
    EndFunc ;==>_SetMines

    [/autoit] [autoit][/autoit] [autoit]

    Func _GetNeighbors($iY, $iX)
    Local $aNeighboars[8]

    [/autoit] [autoit][/autoit] [autoit]

    If $iDebug_Partner = 1 Then ConsoleWrite("________________________________________________________" & @CRLF)

    [/autoit] [autoit][/autoit] [autoit]

    ;1
    If $iY > 0 And $iX > 0 Then
    $aNeighboars[0] = $aGameField[$iY - 1][$iX - 1]
    If $iDebug_Partner = 1 Then ConsoleWrite("1 - OK!" & @CRLF)
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    ;2
    If $iY > 0 Then
    $aNeighboars[1] = $aGameField[$iY - 1][$iX]
    If $iDebug_Partner = 1 Then ConsoleWrite("2 - OK!" & @CRLF)
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    ;3
    If $iY > 0 And $iX < $iColumn - 1 Then
    $aNeighboars[2] = $aGameField[$iY - 1][$iX + 1]
    If $iDebug_Partner = 1 Then ConsoleWrite("3 - OK!" & @CRLF)
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    ;4
    If $iX < $iRow - 1 Then
    $aNeighboars[3] = $aGameField[$iY][$iX + 1]
    If $iDebug_Partner = 1 Then ConsoleWrite("4 - OK!" & @CRLF)
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    ;5
    If $iY < $iRow - 1 And $iX < $iColumn - 1 Then
    $aNeighboars[4] = $aGameField[$iY + 1][$iX + 1]
    If $iDebug_Partner = 1 Then ConsoleWrite("5 - OK!" & @CRLF)
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    ;6
    If $iY < $iColumn - 1 Then
    $aNeighboars[5] = $aGameField[$iY + 1][$iX]
    If $iDebug_Partner = 1 Then ConsoleWrite("6 - OK!" & @CRLF)
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    ;7
    If $iY < $iRow - 1 And $iX > 0 Then
    $aNeighboars[6] = $aGameField[$iY + 1][$iX - 1]
    If $iDebug_Partner = 1 Then ConsoleWrite("7 - OK!" & @CRLF)
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    ;8
    If $iX > 0 Then
    $aNeighboars[7] = $aGameField[$iY][$iX - 1]
    If $iDebug_Partner = 1 Then ConsoleWrite("8 - OK!" & @CRLF)
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    If $iDebug_Partner = 1 Then ConsoleWrite("________________________________________________________" & @CRLF)

    [/autoit] [autoit][/autoit] [autoit]

    Return $aNeighboars
    EndFunc ;==>_GetNeighbors

    [/autoit] [autoit][/autoit] [autoit]

    Func _SetNeighbors($iY, $iX)
    If $iDebug_Partner = 1 Then ConsoleWrite("________________________________________________________" & @CRLF)
    ;1
    If $iY > 0 And $iX > 0 Then
    If _IsMine($iY - 1, $iX - 1) Then $aGameField[$iY - 1][$iX - 1] += 1
    If $iDebug_Partner = 1 Then ConsoleWrite("1 - OK!" & @CRLF)
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    ;2
    If $iY > 0 Then
    If _IsMine($iY - 1, $iX) Then $aGameField[$iY - 1][$iX] += 1
    If $iDebug_Partner = 1 Then ConsoleWrite("2 - OK!" & @CRLF)
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    ;3
    If $iY > 0 And $iX < $iColumn - 1 Then
    If _IsMine($iY - 1, $iX + 1) Then $aGameField[$iY - 1][$iX + 1] += 1
    If $iDebug_Partner = 1 Then ConsoleWrite("3 - OK!" & @CRLF)
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    ;4
    If $iX < $iRow - 1 Then
    If _IsMine($iY, $iX + 1) Then $aGameField[$iY][$iX + 1] += 1
    If $iDebug_Partner = 1 Then ConsoleWrite("4 - OK!" & @CRLF)
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    ;5
    If $iY < $iRow - 1 And $iX < $iColumn - 1 Then
    If _IsMine($iY + 1, $iX + 1) Then $aGameField[$iY + 1][$iX + 1] += 1
    If $iDebug_Partner = 1 Then ConsoleWrite("5 - OK!" & @CRLF)
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    ;6
    If $iY < $iColumn - 1 Then
    If _IsMine($iY + 1, $iX) Then $aGameField[$iY + 1][$iX] += 1
    If $iDebug_Partner = 1 Then ConsoleWrite("6 - OK!" & @CRLF)
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    ;7
    If $iY < $iRow - 1 And $iX > 0 Then
    If _IsMine($iY + 1, $iX - 1) Then $aGameField[$iY + 1][$iX - 1] += 1
    If $iDebug_Partner = 1 Then ConsoleWrite("7 - OK!" & @CRLF)
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    ;8
    If $iX > 0 Then
    If _IsMine($iY, $iX - 1) Then $aGameField[$iY][$iX - 1] += 1
    If $iDebug_Partner = 1 Then ConsoleWrite("8 - OK!" & @CRLF)
    EndIf
    If $iDebug_Partner = 1 Then ConsoleWrite("________________________________________________________" & @CRLF)
    EndFunc ;==>_SetNeighbors

    [/autoit] [autoit][/autoit] [autoit]

    Func _IsMine($iY, $iX)
    If $aGameField[$iY][$iX] = 9 Then
    Return False
    Else
    Return True
    EndIf
    EndFunc ;==>_IsMine

    [/autoit] [autoit][/autoit] [autoit]

    Func _ClickField()
    Opt("GuiOnEventMode", 1)
    Local $aNeighboars[8]
    $iAktuelleFeldID = @GUI_CtrlId - 7
    $iAktuell_X = Mod($iAktuelleFeldID, $iColumn)
    $iAktuell_Y = Int($iAktuelleFeldID / $iRow)
    ;MsgBox(1, "", "Reihe: " & $iAktuell_Y & " Spalte: " & $iAktuell_X)
    $aNeighboars = _GetNeighbors($iAktuell_Y, $iAktuell_X)

    [/autoit] [autoit][/autoit] [autoit]

    If $aGameField[$iAktuell_Y][$iAktuell_X] = 9 Then
    _GameEnd()
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    If $aGameField[$iAktuell_Y][$iAktuell_X] = 0 And $aGameField[$iAktuell_Y][$iAktuell_X] <> 9 Then
    _OpenField($iAktuell_Y, $iAktuell_X)
    EndIf
    _PrintOpenFields()
    EndFunc ;==>_ClickField

    [/autoit] [autoit][/autoit] [autoit]

    Func _OpenField($iY, $iX)
    ;ConsoleWriteError("+> Row: " & $iY & " Column: " & $iX & @CRLF)
    If $aGameField[$iY][$iX] = 0 And $aGameField[$iY][$iX] <> 9 Then
    ; ------------------------------------------------
    ; INFO:
    ;
    ; - $aGameField[$iY][$iX] = 0 -> freies Feld
    ; - $aGameField[$iY][$iX] = 9 -> Bombe auf Feld
    ; - $aGameField[$iY][$iX] = 1 -> Feld hat Nummer 1
    ; - $aGameField[$iY][$iX] = 2 -> Feld hat Nummer 2
    ; - ....
    ; - $aGameField[$iY][$iX] = 8 -> Feld hat Nummer 8
    ; ------------------------------------------------
    ; - $aOpenFields[$iY][$iX] = 1 -> Feld ist "offen" und wird angezeigt
    ; - $aOpenFields[$iY][$iX] = 0 -> Feld ist noch verschlossen und wird nicht angezeigt
    ; ------------------------------------------------

    [/autoit] [autoit][/autoit] [autoit]

    If $aOpenFields[$iY][$iX] = 0 Then
    ConsoleWriteError("+> Debug_Open - " & "X: " & $iX & " - Y: " & $iY & @CRLF)
    $aOpenFields[$iY][$iX] = 1
    If _IsPosRange($iY, $iX + 1) Then _OpenField($iY, $iX + 1)
    If _IsPosRange($iY, $iX - 1) Then _OpenField($iY, $iX - 1)
    If _IsPosRange($iY + 1, $iX) Then _OpenField($iY + 1, $iX)
    If _IsPosRange($iY - 1, $iX) Then _OpenField($iY - 1, $iX)
    If _IsPosRange($iY - 1, $iX - 1) Then $aOpenFields[$iY - 1][$iX - 1] = 1
    If _IsPosRange($iY + 1, $iX - 1) Then $aOpenFields[$iY + 1][$iX - 1] = 1
    If _IsPosRange($iY - 1, $iX + 1) Then $aOpenFields[$iY - 1][$iX + 1] = 1
    If _IsPosRange($iY + 1, $iX + 1) Then $aOpenFields[$iY + 1][$iX + 1] = 1
    EndIf
    EndIf
    EndFunc ;==>_OpenField

    [/autoit] [autoit][/autoit] [autoit]

    Func _IsPosRange($iY, $iX)
    If $iX >= 0 And $iY >= 0 And $iX <= $iColumn - 1 And $iY <= $iRow - 1 Then
    Return True
    Else
    Return False
    EndIf
    EndFunc ;==>_IsPosRange

    [/autoit] [autoit][/autoit] [autoit]

    Func _CreateImages($sF_Path = "", $iImages = -1, $iF_X = -1, $iF_LX = -1, $iF_Y = -1)
    Local $aGraphics[$iImages + 1]
    If $sF_Path <> "" Then
    $hBitmap = _GDIPlus_ImageLoadFromFile($sF_Path)
    For $i = 0 To $iImages
    $aGraphics[$i] = _GDIPlus_BitmapCloneArea($hBitmap, 0, $i * $iF_X, $iF_LX, $iF_Y, $GDIP_PXF24RGB)
    Next
    EndIf
    _WinAPI_DeleteObject($hBitmap)
    Return $aGraphics
    EndFunc ;==>_CreateImages

    [/autoit] [autoit][/autoit] [autoit]

    Func _GameEnd()
    _PrintAllMines()
    Opt("GuiOnEventMode", 0)
    ConsoleWrite("-> You lose! .. A new game will start!" & @CRLF)
    AdlibUnRegister("_Timer")
    ConsoleWrite("-> Please wait ..." & @CRLF & @CRLF)
    _CreateGameField()
    ConsoleWrite("-> New Game!" & @CRLF)
    EndFunc ;==>_GameEnd

    [/autoit] [autoit][/autoit] [autoit]

    Func _PrintAllMines()
    For $iY = 0 To $iRow - 1
    For $iX = 0 To $iColumn - 1
    If $aGameField[$iY][$iX] = 9 Then _GDIPlus_GraphicsDrawImage($hGraphic, $aGraphic_Item[10], 20 * $iX + $iShift_X, 20 * $iY + $iShift_Y)
    Next
    Next
    EndFunc ;==>_PrintAllMines

    [/autoit] [autoit][/autoit] [autoit]

    Func _PrintOpenFields()
    For $iY = 0 To $iRow - 1
    For $iX = 0 To $iColumn - 1
    If $aOpenFields[$iY][$iX] = 1 Then _GDIPlus_GraphicsDrawImage($hGraphic, $aGraphic_Item[$aGameField[$iY][$iX] + 1], 20 * $iX + $iShift_X, 20 * $iY + $iShift_Y)
    Next
    Next
    EndFunc ;==>_PrintOpenFields

    [/autoit] [autoit][/autoit] [autoit]

    Func _UnHideMap()
    For $iY = 0 To $iRow - 1
    For $iX = 0 To $iColumn - 1
    _GDIPlus_GraphicsDrawImage($hGraphic, $aGraphic_Item[$aGameField[$iY][$iX] + 1], 20 * $iX + $iShift_X, 20 * $iY + $iShift_Y)
    Next
    Next
    EndFunc ;==>_UnHideMap

    [/autoit] [autoit][/autoit] [autoit]

    Func _HideMap()
    For $iY = 0 To $iRow - 1
    For $iX = 0 To $iColumn - 1
    $aOpenFields[$iY][$iX] = 0
    _GDIPlus_GraphicsDrawImage($hGraphic, $aGraphic_Item[0], 20 * $iX + $iShift_X, 20 * $iY + $iShift_Y)
    Next
    Next
    EndFunc ;==>_HideMap

    [/autoit] [autoit][/autoit] [autoit]

    Func _Timer()
    $iTimer += 1
    ;ConsoleWrite($iTimer & @CRLF)
    _GDIPlus_GraphicsDrawImage($hGraphic, $aGraphic_Dig[StringRight($iTimer, 1)], 64 + $iHSX, 20)
    If $iTimer >= 10 And $iTimer <= 100 Then
    _GDIPlus_GraphicsDrawImage($hGraphic, $aGraphic_Dig[StringTrimRight($iTimer, 1)], 52 + $iHSX, 20)
    ;ConsoleWrite(StringTrimRight($iTimer, 1)& @CRLF)
    Else
    _GDIPlus_GraphicsDrawImage($hGraphic, $aGraphic_Dig[StringTrimLeft(StringTrimRight($iTimer, 1), 1)], 52 + $iHSX, 20)
    EndIf
    If $iTimer >= 100 Then _GDIPlus_GraphicsDrawImage($hGraphic, $aGraphic_Dig[StringTrimRight($iTimer, 2)], 40 + $iHSX, 20)
    If $iTimer >= 999 Then
    ;_GameEnd()
    EndIf
    EndFunc ;==>_Timer

    [/autoit] [autoit][/autoit] [autoit]

    Func _Exit()
    _GDIPlus_GraphicsDispose($hGraphic)
    For $i = 0 To 9
    _GDIPlus_ImageDispose($aGraphic_Dig[$i])
    Next
    _GDIPlus_Shutdown()
    Exit
    EndFunc ;==>_Exit

    [/autoit] [autoit][/autoit] [autoit]

    Func _Shuffle(ByRef $aArray)
    Local $n, $k, $tmp
    $n = UBound($aArray) - 1
    While $n > 1
    $k = Random(0, $n - 1, 1)
    $tmp = $aArray[$n];
    $aArray[$n] = $aArray[$k];
    $aArray[$k] = $tmp;
    $n -= 1
    WEnd
    Return True
    EndFunc ;==>_Shuffle

    [/autoit]

    Vielen Dank, ist vielleicht etwas kompliziert, aber komme nicht selbst drauf :)