Checking Grid Array for line patterns

14 replies [Last post]
thomas6
User is online Online
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 41 weeks 1 day ago. Offline
Staff
Joined: 17 Aug 2011

Maybe iterate through the rows using a for loop ?

thomas6
User is online Online
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 20 hours 20 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 20 hours 20 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 4 days 1 hour 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 is online Online
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 20 hours 20 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 4 days 1 hour 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 20 hours 20 min ago. Offline
Joined: 29 Jul 2010

made a few changes to my code above

thomas6
User is online Online
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 20 hours 20 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 39 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 16 hours 18 min ago. Offline
Joined: 16 Dec 2010
jkrassman
User offline. Last seen 1 year 39 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.