Flood Fill Crashing AHK Issue

Get help with using AutoHotkey and its commands and hotkeys
User avatar
Hellbent
Posts: 1184
Joined: 23 Sep 2017, 13:34

Flood Fill Crashing AHK Issue

26 Oct 2017, 09:48

I was working on a little game about a week ago. I was hoping to use this project as a way of starting to pick up Gdip, once I had the game working I would rewrite it using Gdip having had everything else already worked out.

Anyway, things were going smoothly until I got to the point of adding a function to reveal any blank squares (the game is mine sweeper btw) if I click on a square that has no mines in any of the adjacent squares. The function works fine for the most part, but if the number of squares to reveal is above 150-ish AHK crashes.

I have to admit that I don't write these kinds of operations often so it very likely is a error in my code, but I don't understand why it works perfectly if the number of squares is under 150-ish but then crashes over that amount. (sometimes it is around 140, other times it is around 170+).

I do have a work around for this (adding enough mines to the game so that the chances of more than 150 squares being adjacent is slim), but if I could find a real solution to this problem I think it would be better in the long run.

I have not touched the code in a few days, and this is my first draft so it is not pretty to look at lol.

The function in question is called "Look_Around()"

Code: Select all

#SingleInstance,Force
SetWorkingDir,%A_ScriptDir%\Mine Sweeper Assets
CoordMode,Mouse,Screen
SetBatchLines,-1

global Size_List:="10x10||20x20|30x30|"
global Difficulty_List:="Easy||Normal|Hard|Insane|"

global Grid_Array_Show:=[[],[]]
global Grid_Array_Trolls:=[[],[]]
global k:=0
global Flag:=0
New_Game:=New Game
New_Game.Game_Option_Settings()




return
;------------------  Labels
GuiClose:
	ExitApp
2GuiClose:
	ExitApp	
Submit_All:
	Gui,1:Submit,NoHide
	Tooltip,% Game_Size "`n" Game_Difficulty
	return
Start_New_Game:
	Board_S:=Game_Size*200
	Gui,1:Destroy
	New_Game.Game_Board(Board_S)
	return
Selected_Square:
	Loop,Parse,A_GuiControl,_
		{
			if(A_Index=1)
				Yy:=A_LoopField
			if(A_Index=2)
				Xx:=A_LoopField
		}
	if(Flag==1)
		{
			Flag:=0
			GuiControl,2:,%A_GuiControl%,Mark.png
			return
		}
	;~ Grid_Array_Show[Yy,Xx]:=1	
	New_Game.Look_Around(Yy,Xx)
		;~ GuiControl,2:,%A_GuiControl%,Test%Troll_Count%.png
	if(Grid_Array_Trolls[Yy,Xx]=1)
		{
			msgbox, Boom Bitch
		}
	;~ GuiControl,2:,%A_GuiControl%,Test.png
;~ MsgBox % Yy "`n" Xx
	return


;#############################        Game Class       ##########################
;################################################################################
Class Game
	{
		Game_Option_Settings()
			{
				global
				Gui,1:Destroy
				Gui,1:+AlwaysOnTop 
				Gui,1:Color,505050
				Gui,1:Font,cWhite s22 underline,Cooper Black
				Gui,1:Add,Text,x0 y0 w300 Center ,Troll Sweeper
				Gui,1:Font,
				Gui,1:Add,Groupbox,x20 y35 w260 h210
				Gui,1:Add,GroupBox,cWhite x60 y50 w180 h60 Center  ,Board Size
				Gui,1:Add,DDL,x120 y70 w60 r5 AltSubmit vGame_Size gSubmit_All,% Size_List
				
				Gui,1:Add,GroupBox,cWhite x60 y130 w180 h60 Center  ,Difficulty Level
				Gui,1:Add,DDL,x117 y150 w66 r5 AltSubmit vGame_Difficulty gSubmit_All,% Difficulty_List
				
				Gui,1:Add,Button,x70 y200 w160 h30 gStart_New_Game,Start
				
				Gui,1:Show,w300 h260,Mine Sweeper Menu
				Gui,1:Submit,NoHide
				
			}
		Game_Board(Board_S)
			{
				global
				Gui,2:Destroy
				Gui,2:+AlwaysOnTop 
				Gui,2:Color,Black ;505050
				
				Gui,2:Show,w%Board_S% h%Board_S%,Mine Sweeper Board
				
			}
		New_Grid()
			{
				global
				if(Game_Difficulty=1)
					{
						o:=1
						Loop % Game_Size*10
							{
								h:=1
								Loop % Game_Size*10
									{
										Grid_Array_Trolls[o,h]:=0
										Grid_Array_Show[o,h]:=0
										h++
									}
								o++	
							}
						Loop 40
							{
								Loop
									{
										Random,X,1,Game_Size*10
										Random,Y,1,Game_Size*10
										if(Grid_Array_Trolls[y,x]=0)
											{
												Grid_Array_Trolls[y,x]:=1
												break
											}
									}		
							}
					}
			}
		Game_Draw_Grid(Game_Size)
			{
				global
				GY:=1
				Y1:=1
				Grid_Size:=Game_Size*10
				Loop % Grid_Size
					{
						GX:=1
						X1:=1
						Loop % Grid_Size
							{
								;~ if(Grid_Array_Trolls[GY,GX]==1)
									;~ {
										;~ Gui,2:Add,Picture,x%X1% y%Y1% w18 h18 v%GY%_%GX% gSelected_Square,boom.png
									;~ }
								;~ else
									;~ {
										Gui,2:Add,Picture,x%X1% y%Y1% w18 h18 v%GY%_%GX% gSelected_Square,Black Square.png
									;~ }
								X1+=20
								GX++
							}
						Y1+=20
						GY++
					}
			}
		Look_Around(Yy,Xx)
			{
				if(Grid_Array_Trolls[Yy,Xx]=0)
					{
					;~ msgbox, here
						Troll_Count:=0
						j:=-1
						Loop 3
							{
								i:=-1
								Loop 3
									{
										if(Grid_Array_Trolls[Yy+j,Xx+i]=1) ;&&(J!=0&&I!=0))
											Troll_Count++
										i++
									}
								j++	
							}
						if(Grid_Array_Show[Yy,Xx]=0)
							{
								GuiControl,2:,%Yy%_%Xx%,Test%Troll_Count%.png
								Grid_Array_Show[Yy,Xx]:=1
							}
						Grid_Count:=0
						j:=-1
						Loop 3
							{
								i:=-1
								Loop 3
									{
										if(Grid_Array_Show[Yy+j,Xx+i]=1) ;&&(J!=0&&I!=0))
											Grid_Count++
										i++
									}
								j++	
							}
						if(Troll_Count=0&&Grid_Count<8) 
							{
								k++
								ToolTip,% k
								j:=-1
								Loop 3
									{
										i:=-1
										Loop 3
											{
												if(Grid_Array_Trolls[Yy+j,Xx+i]=0&&Grid_Array_Show[Yy+j,Xx+i]=0)
													{
														ty:=Yy+j
														tx:=Xx+i
														This.Look_Around(ty,tx)
													}
												i++
											}
										j++	
									}
							}
					}	
						
			}
		
	}
Show_Blanks(Yy,Xx)   ;not used right now
			{
				msgbox, here
				;~ Troll_Count:=0
						j:=-1
						Loop 3
							{
								i:=-1
								Loop 3
									{
										if(Grid_Array_Trolls[Yy+j,Xx+i]=0) ;&&Grid_Array_Show[Yy+j,Xx+i]=0&&(J!=0&&I!=0))
											{
												msgbox, here 2
												ty:=Yy+j
												tx:=Xx+i
												;Grid_Array_Show[Yy+j,Xx+i]:=1
												;~ GuiControl,2:,%ty%_%tx%,Test%Troll_Count%.png
												;~ GuiControl,2:,%A_GuiControl%,Test%Troll_Count%.png
												New_Game.Look_Around(ty,tx)
											}
										i++
									}
								j++	
							}
			}
2GuiContextMenu:
	Flag:=1
	gosub,Selected_Square
	return
numpad1::
	New_Game.Game_Board(Board_S)
	;~ msgbox, % Board_S
	New_Game.New_Grid()
	New_Game.Game_Draw_Grid(Game_Size)
	return

*^ESC::ExitApp
Any help would be appreciated.

Here are a few images that show the game board.
Image
Image

In the second image you can see that the function worked fine for 120 squares. (ok that was two clicks, but if it was one it would have been fine :) )
User avatar
LinearSpoon
Posts: 156
Joined: 29 Sep 2013, 22:55

Re: Flood Fill Crashing AHK Issue

26 Oct 2017, 22:37

I haven't investigated closely, but my guess is too many recursive calls. I don't really see any other code that could cause an issue in look_around. Here is a sample that reproduces the crash:

Code: Select all

myfn(a)
{
  if (mod(a, 50) == 0)
    msgbox % a
  myfn(a+1)
}

myfn(0)
One fix would be to rewrite look_around as a loop using an array as a stack containing the next tx, ty to look around.

Code: Select all

Look_Around(Yy,Xx)
{
   ; Initialize stack with first position
   stack := [ {x: Xx, y: Yy} ]
   ; Continue until no more positions in the stack
   while(stack.Length())
   {
      pos := stack.Pop()
      ; fill in look around code here using pos.x, pos.y
      
      ; Push another position to be considered next loop:
      stack.Push( {x: tx,y: ty } )
   }
}

Return to “Ask For Help”

Who is online

Users browsing this forum: hasantr, swrong, Xeo786 and 44 guests