Checking Grid Array for line patterns
Hi all!
I'm working on a puzzle game that has a grid of blocks, 5 blocks wide and 6 blocks high. Sliding the blocks into rows or columns of 4 or more of the same type 'destroys' these blocks.
Now, the problem I'm running into is my code to check whether a (or multiple) line of 4,5 or 6 of the same blocks exists, and to handle that situation. It's turning into quite the code block, so I'm wondering if there's not a simpler way, maybe with regular expressions or string searching or ... At the moment I'm doing a loooot of if...elseif...elseif...elseif...end code.
Does anyone have any experience in this area?
Thanks!
Thomas
Replies
That's what I'm doing now, but it's pretty heavy. Especially since I need to perform this check after every move (about every second).
Here's my code at the moment:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | local function CheckGrid() -- start by initialising the CheckArray grid for i = 1, 30 do CheckArray[i] = 0 -- this creates an array of 30 zeros, that we use for checking later on! end -- check 6 horizontal lines for quads for i = 0, 5 do -- read in tilerow local tile1 = Array[1+i*5] local tile2 = Array[2+i*5] local tile3 = Array[3+i*5] local tile4 = Array[4+i*5] local tile5 = Array[5+i*5] -- now check if (tile2 == tile1) and (tile3 == tile1) and (tile4 == tile1) then -- first 4 tiles in row are the same, now check if the fifth is also the same if (tile5 == tile1) then -- five tiles the same in this row! CheckArray[1+i*5] = CheckArray[1+i*5] +1 CheckArray[2+i*5] = CheckArray[2+i*5] +1 CheckArray[3+i*5] = CheckArray[3+i*5] +1 CheckArray[4+i*5] = CheckArray[4+i*5] +1 CheckArray[5+i*5] = CheckArray[5+i*5] +1 else -- only 4 first tiles the same! CheckArray[1+i*5] = CheckArray[1+i*5]+1 CheckArray[2+i*5] = CheckArray[2+i*5]+1 CheckArray[3+i*5] = CheckArray[3+i*5]+1 CheckArray[4+i*5] = CheckArray[4+i*5]+1 end elseif (tile3 == tile2) and (tile4 == tile2) and (tile5 == tile2) then -- only four last tiles the same! CheckArray[2+i*5] = CheckArray[2+i*5]+1 CheckArray[3+i*5] = CheckArray[3+i*5]+1 CheckArray[4+i*5] = CheckArray[4+i*5]+1 CheckArray[5+i*5] = CheckArray[5+i*5]+1 else -- none match end end -- then check 5 vertical lines for quads for i = 0, 4 do -- read in tilecolumn local tile1 = Array[1+i] local tile2 = Array[6+i] local tile3 = Array[11+i] local tile4 = Array[16+i] local tile5 = Array[21+i] local tile6 = Array[26+i] -- now check if (tile2 == tile1) and (tile3 == tile1) and (tile4 == tile1) then if (tile5==tile1) then if (tile6==tile1) then -- all 6 tiles match!!! CheckArray[1+i] = 1 CheckArray[6+i] = 1 CheckArray[11+i] = 1 CheckArray[16+i] = 1 CheckArray[21+i] = 1 CheckArray[26+i] = 1 else -- first 5 tiles match!!! CheckArray[1+i] = 1 CheckArray[6+i] = 1 CheckArray[11+i] = 1 CheckArray[16+i] = 1 CheckArray[21+i] = 1 end else -- first 4 tiles match!!! CheckArray[1+i] = 1 CheckArray[6+i] = 1 CheckArray[11+i] = 1 CheckArray[16+i] = 1 end elseif (tile3 == tile2) and (tile4 == tile2) and (tile5 == tile2) then if (tile6 == tile2) then -- last 5 tiles match!!! CheckArray[6+i] = 1 CheckArray[11+i] = 1 CheckArray[16+i] = 1 CheckArray[21+i] = 1 CheckArray[26+i] = 1 else -- middle 4 tiles match!!! CheckArray[6+i] = 1 CheckArray[11+i] = 1 CheckArray[16+i] = 1 CheckArray[21+i] = 1 end elseif (tile4 == tile3) and (tile5 == tile3) and (tile6 == tile3) then -- last 4 tiles match!!! CheckArray[11+i] = 1 CheckArray[16+i] = 1 CheckArray[21+i] = 1 CheckArray[26+i] = 1 else -- no tiles match!!! end end -- Now evaluate checkarray: Did something match??? print("check") local matchFound = false for i = 1, 30 do if (CheckArray[i] == 1) then matchFound = true end end PrintArray(CheckArray, "CheckArray") if (matchFound == true) then print("match") audio.play(matchSound) DestroyTiles() end end |
ive been working on an app that does something similar to this when i get home today ill send you some sample code. it goes though a grid of 7x9 and find matches of 2x2 or bigger
ive changed it to work with your 5x6 grid and 4+ in a row match
have not tested but if it doesnt work it should be close
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | -- set a random game board each number stands different color block gameData = {} for a = 1, 30 do gameData[a] = math.random( 1, 3 ) end function fnCheckBlocks() print( "fnCheckBlocks" ) popTable = {} for ct = 1, 30 do if ct%5 < 3 then -- no need to check pass 2nd column for row match if gameData[ct] == gameData[ct+1] and gameData[ct] == gameData[ct+2] and gameData[ct] == gameData[ct+3] then pop1 = { 0, 1, 2, 3 } for a = 1, #pop1 do table.insert( popTable, #popTable+1, ct+pop1[a] ) end end end if ct < 16 then --no need to check pass 3rd row for column match if gameData[ct] == gameData[ct+5] and gameData[ct] == gameData[ct+10] and gameData[ct] == gameData[ct+15] then pop2 = { 0, 5, 10, 15 } for a = 1, #pop2 do table.insert( popTable, #popTable+1, ct+pop2[a] ) end end end end --print table to terminal for a = 1, #popTable do print("popTable: "..popTable[a]) end --sort table table.sort( popTable ) --print sorted table to terminal for a = 1, #popTable do print("sorted popTable: "..popTable[a]) end --unique table, removes double entries from table local newTable = {} local ct = nil for k,v in pairs(popTable) do if ct ~= v then table.insert( newTable, #newTable+1, v ) end ct = v end --print table to terminal without double entries for a = 1, #popTable do print("unique entry popTable: "..popTable[a]) end popTable = nil popTable = {} popTable = newTable -- if #popTable > 0 then -- fnRemoveBlocks() -- end end ------------------------------------------------------------------- fnCheckBlocks() -- now just make function to go though the popTable and remove the blocks |
@thomas,
You are on the right track , but believe me that is Massive redundant code right there. You can modularize the checking into a function/s and reduce that into lesser lines of code.
Have a look at my game RetroBalls here (iTunes) or a video about it here and see that a lot of calculations have to be made on every level for every colour of the ball and also considering that there are blocks in between.
cheers,
?:)
Hi Jstrahan and Jayantv,
Thanks for the help! I just got to work (morning in Belgium now) but will check in detail tonight!
Jayantv, that game looks cool! Is it out yet?
ok if you use my code and have problems just let me know
@thomas,
The game was released in July and is universal, the same one runs on all iOS devices, iPhones or iPads.
you can find it here iTunes App Store link
cheers,
?:)
made a few changes to my code above
Thanks!
I just tried your code, took some tiny tiny tiny errors out of it and now it works like a charm.
Here's my adapted code, for detecting groups of 3 blocks (yep, I went from 4 to 3) in a horizontal row or vertical column:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | -- set a random game board each number stands different color block gameData = {} for a = 1, 30 do gameData[a] = math.random(5) end for y = 0,5 do print(gameData[1+y*5].." "..gameData[2+y*5].." "..gameData[3+y*5].." "..gameData[4+y*5].." "..gameData[5+y*5]) end print("---------") function fnCheckBlocks() popTable = {} for ct = 1, 30 do if (ct-1)%5 < 3 then -- no need to check pass 3rd column for row match if (gameData[ct] == gameData[ct+1]) and (gameData[ct] == gameData[ct+2]) then pop1 = { 0, 1, 2} for a = 1, 3 do table.insert( popTable, #popTable+1, ct+pop1[a] ) end end end if (ct < 21) then --no need to check pass 4th row for column match if (gameData[ct] == gameData[ct+5]) and (gameData[ct] == gameData[ct+10]) then pop2 = { 0, 5, 10} for a = 1, 3 do table.insert( popTable, #popTable+1, ct+pop2[a] ) end end end end --sort table table.sort(popTable) ---unique table, removes double entries from table local newTable = {} local lastNumber = 0 for ct = 1, #popTable do nextNumber = popTable[ct] if (nextNumber ~= lastNumber) then newTable[#newTable+1] = nextNumber end lastNumber = nextNumber end -- build Array with 1s where blocks match local popGrid = {} for i = 1, 30 do popGrid[i] = 0 end for i = 1, #newTable do popGrid[newTable[i]] = 1 end for y = 0,5 do print(popGrid[1+y*5].." "..popGrid[2+y*5].." "..popGrid[3+y*5].." "..popGrid[4+y*5].." "..popGrid[5+y*5]) end print("---------") end fnCheckBlocks() |
By the way, the biggest (little) bug in your code was in the line:
1 | if (ct-1)%5 < 3 then -- no need to check pass 3rd column for row match |
You said 'if ct%5 < 3' but it needs to be 'if (ct-1)%5 < 3', or your detection 'wraps around' the grid - for lack of better words!
Thanks again - this is a wonderful forum :-)
Thomas
glad you got it to work it works great with my 2x2 system also
I figured the 4 in a row would be a bit large for the grid you were using
like I said I didn't try it out just adopted it to fit for you
Guys, how should I alter the code if my grid is 6x5?
I am totally lost within the table code :)
Joakim
No!!! Let's have a true fun! Genetic algorithm or Neural Networks!!
http://www.neverreadpassively.com/2009/12/genetic-algorithm-in-lua.html
http://www.forums.evilmana.com/psp-lua-codebase/lua-neural-networks/
No I am totally lost....more then before... :)




Maybe iterate through the rows using a for loop ?