Checking Grid Array for line patterns

14 replies [Last post]
thomas6
User offline. Last seen 7 weeks 3 days ago. Offline
Joined: 17 Jun 2011

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

Danny
User offline. Last seen 13 weeks 6 days ago. Offline
Staff
Joined: 17 Aug 2011

Maybe iterate through the rows using a for loop ?

thomas6
User offline. Last seen 7 weeks 3 days ago. Offline
Joined: 17 Jun 2011

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

jstrahan
User offline. Last seen 1 hour 17 min ago. Offline
Joined: 29 Jul 2010

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

jstrahan
User offline. Last seen 1 hour 17 min ago. Offline
Joined: 29 Jul 2010

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

JayantV
User offline. Last seen 2 weeks 2 days ago. Offline
Joined: 31 Oct 2009

@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,

?:)

thomas6
User offline. Last seen 7 weeks 3 days ago. Offline
Joined: 17 Jun 2011

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?

jstrahan
User offline. Last seen 1 hour 17 min ago. Offline
Joined: 29 Jul 2010

ok if you use my code and have problems just let me know

JayantV
User offline. Last seen 2 weeks 2 days ago. Offline
Joined: 31 Oct 2009

@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,

?:)

jstrahan
User offline. Last seen 1 hour 17 min ago. Offline
Joined: 29 Jul 2010

made a few changes to my code above

thomas6
User offline. Last seen 7 weeks 3 days ago. Offline
Joined: 17 Jun 2011

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

jstrahan
User offline. Last seen 1 hour 17 min ago. Offline
Joined: 29 Jul 2010

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

jkrassman
User offline. Last seen 1 year 12 weeks ago. Offline
Joined: 4 Aug 2011

Guys, how should I alter the code if my grid is 6x5?

I am totally lost within the table code :)

Joakim

gtatarkin
User offline. Last seen 22 hours 7 min ago. Offline
Joined: 16 Dec 2010
jkrassman
User offline. Last seen 1 year 12 weeks ago. Offline
Joined: 4 Aug 2011

No I am totally lost....more then before... :)

Viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.