Checking for rows and columns

Blitz3D Forums/Blitz3D Programming/Checking for rows and columns

_PJ_(Posted 2005) [#1]
I have an array (2 dimensions each with 10 units) each cell of the array could be a number from 1 to 8

I need to check from a particular location in the array, whether or not the cels adjacent (horiz and vert, not diagonal) are the same number, and if they make a sequence of three or more of the same number in a row.
Does this make sense?

Unfortunately, I cant paste the code I have because that's on my lappy at home, and I cant bring that in here to work.

here's an example anyway....

(imagine the test is based on the central cel of the portion of the array displayed)

13315
45642
48216 = POSITIVE - the '2's in column 3
21275
21242


21452
25178
82145 = NEGATIVE - no sets of 3 in a row
57216
82751

16524
82444
72145 = NEGATIVE - the row of '4's does not include the central cel
13361
87215

87215
21563
33331 = POSITIVE - the '3's count because they include the central cel
42156
24152

28351
21562
14341 = NEGATIVE - The '3's are only two in a row.
32345
21785

Anyone got any functions or routines to help with this?

I will try and get my code on a floppy and bring it to work so I can post it here...


Rob Farley(Posted 2005) [#2]
It's pretty simple to do, you've just got to test each bit.

ie Pseudo code:

function checknumber(num,x,y,xd,yd)

if array(x,y) = num then
xx=x
yy=y
count = 1

repeat
xx=xx+xd
yy=yy+yd
if xx<0 or xx>4 or yy<0 or yy>4 then exit
if array(xx,yy) = num then count = count + 1
until array (xx,yy) <> num

return count

end function

then use this function for each thingy

for x=0 to 4
for y=0 to 4
for n=1 to 8
r= checknum(n,1,0,x,y)
r= checknum(n,1,1,x,y)
r= checknum(n,0,1,x,y)
r= checknum(n,-1,1,x,y)
etc
etc

That sort of thing.

I would suggest adding an extra element to the array so you can highlight easily without having to retun each time.

IE, if it finds a line the it marks those items in the array itself.

[edit]Sorry.. didn't read the central cell bit... same kind of thing, just much simpler.


_PJ_(Posted 2005) [#3]
Okay, I think I get that. My array uses digits from 1-8 (0 has a special use), I intend also to mark the valid cells by changing them to '9'.

However, one thing I must be careful of is that it is possible to have a sequence of valid cells that could be up to all 10 cells in a row/column. Also, I need to avoid instances where there is more than one sequence of 3 or more of the same value, but only one sequence is actually valid...

i.e. (Imagine the X being the check cell, and the value is '5'


2187547821
2558562187
2155687216
26X8721578
2572168572
6552365842
3251562381
3256568228
3257476242
6312757812

Note that in column '2', the top sequence of '5's is valid because the two above the X plus the X makes 3, but the '7' below the X is a gap making the bottom sequence of '5's invalid.

------------sorry it's quite simple in theory, but really hard to explain I think!


BlackJumper(Posted 2005) [#4]
Some thoughts: {although I'm not sure exactly what you are planning to do with it... Connect4 ??}

(1) Have 2 'shadow arrays' - each copy deals with a different direction (horizontal or vertical) and records how many adjacent cells match the target cell

Now you can have quite simple code to check each cell...

for x = 0 to 9
    for y = 0 to 9
        neighbours = 0
        ;checking the horiz_direction
        xx = x+1
        while (xx < 10) And (array(xx, y) = array(x,y))
              xx = xx + 1
              neighbours = neighbours + 1
        wend
        horiz_array(x,y) = neighbours

        ; similar code for vertical
 
    next ; y
next ; x


(2) Use a type to record the same information... since you have a square grid, you always know that neighbours are t-1, t+1, t-10, t+10:
Type targetcell
     field t                 ; the ID of the cell
     field value             ; holds digit 1-8
     field vert_neighbours  ; count of consecutive matches below
     field horiz_neighbours  ; etc.
End Type


(3) You could use a 2 digit value to combine the information, so 36 would mean 3(horizontal) + 6(vertical) neighbours.

(4) If the direction from the central cell is important you could use 4 shadow arrays; add north_dir, south_dir, east_dir, west_dir; or a 4 digit value

Hope this helps


Rook Zimbabwe(Posted 2005) [#5]
I use this the check for 3 in a horizontal or vertical array of 10X10...
Function check_three()
ClearWorld(entities) ; to reset the world and NOT redraw the entitys on top 
; of each other AGAIN!!!
;
;To Check  UP and DOWN
For flirt=0 To 9
	For fart=0 To 7
		a=board(flirt,fart)
		b=board(flirt,fart+1)
		c=board(flirt,fart+2)
			If a = b Then
				If b = c Then
				kl=fart
				board(flirt,fart)=0
				board(flirt,fart+1)=0
				board(flirt,fart+2)=0
				For lk = kl To kl+2
					te=3
					CSP_LaunchParticle(0,tex,2,boardx(flirt),yf+3,boardz(lk),1,10,0.1,1,1,1,0,1.0)
				Next
				; maybe some points and a sound
				score = score+(35*sval)
				PlaySound yeah
				matchlev = matchlev+1
				EndIf			
			EndIf
	Next		
Next
; to check LEFT and RIGHT
For flirt=0 To 7
	For fart=0 To 9
		a=board(flirt,fart)
		b=board(flirt+1,fart)
		c=board(flirt+2,fart)
			If a = b Then
				If b = c Then
				kl = flirt
				board(flirt,fart)=0
				board(flirt+1,fart)=0
				board(flirt+2,fart)=0
				For lk = kl To kl+2
				te=3
				CSP_LaunchParticle(0,tex,2,boardx(lk),yf+3,boardz(fart),1,10,0.1,1,1,1,0,1.0)
				Next
				; maybe some points and a sound
				score = score+(55*sval)
				PlaySound happy	
				Animate wahoo,3
				matchlev=matchlev+1			
				EndIf	
			EndIf
	Next		
Next
End Function
It does other things if a sequenbce of 3 is found... If it finds L and R first the code is ended... it could be rewritten to find BOTH but I don't want to do that right now.
--RZ


big10p(Posted 2005) [#6]
Someone asked for something similar to this, back along. Here's the code I came up with:

	SeedRnd MilliSecs() 

	Const END_ROW = 9
	Const END_COL = 9
	Dim grid(END_ROW,END_COL) ; A 10x10 grid.

	Repeat

		Print
		For r = 0 To END_ROW
			For c = 0 To END_COL
				grid(r,c) = Rand(0,1)
				Write grid(r,c) + " "
			Next
			Print
		Next
	
		most_in_a_row% = 0
		
		For r = 0 To END_ROW
			For c = 0 To END_COL
				connected = in_a_row(r,c)
				If connected > most_in_a_row Then most_in_a_row = connected
			Next
		Next
	
		Print : Print "Most in-a-row values " + most_in_a_row
		WaitKey()
	
	Until KeyHit(1)
	
	End

;
; Finds the largest amount of in-a-row values connected
; to the value at row,col in grid() array.
;
; Params:
; row,col - Position in grid() array of where to find largest
;           amount of matching, in-a-row values.
;
; Returns:
; Largest amount of matching in_a_row values found.
;
Function in_a_row(row%, col%)
	
	match = grid(row,col)
	
	For n = 0 To 3	; 4 directions to check: horz, vert & 2 diags.
	
		dx = Sgn(n) : dy = Sgn(n-2)		
		connected = 1
		
		For j = 1 To 2
			trow = row : tcol = col

			Repeat
				trow = trow + dx : tcol = tcol + dy
				out_of_bounds = (trow<0)+(trow>END_ROW)+(tcol<0)+(tcol>END_COL)
				If out_of_bounds Then Exit
				If grid(trow,tcol) <> match Then Exit
				connected = connected + 1
			Forever
					
			dx = -dx : dy = -dy ; Reverse checking direction.
		Next

		If connected > most_in_a_row Then most_in_a_row = connected
						
	Next
	
	Return most_in_a_row
	
End Function



Rook Zimbabwe(Posted 2005) [#7]
I would like to compliment everyone that has shared code on theis question thus far... I don't see that on a lot of boards where everyone hunches over their projects like a starving dog gnawing a bone. I hope this helps EVERYONE who wants to search an array.
-Z


_PJ_(Posted 2005) [#8]
Yeah, thanks - it's really helpful. I know it's not so clear what I was after, and in fact it's a lot more complicated than it first seems.

It's easy to find if there's 3 like values in a row around the target cell of the array. It's easy to find out how many like values are in a consecutive row in any row/column,
but the difficulty comes when you need to include the rows/columns with 3 or more like values in a row, but ONLY when the target cell is part of that series.


__________________________________________


BlackJumper - that code would ignore the fact that a gap in like cells would interrupt the count.

Rook - That's nice, but needs to extend to more than 3 if there are more in a row, plus both horiz and vertical MUST be accounted for


Big10p - Diagonals arent needed, and I am not too concerned with how many like values there are, just that each cell containing a valid result is accounted for.

---------------------------------

See what I mean? It's not that simple is it???

I haven't been able to get at my code again for a coupla days, but hopefully tonight Il have another bash at it! Thanks for all your help guys!


Rook Zimbabwe(Posted 2005) [#9]
Yes but any of these could be modified for 4 or any amount you wished.


BlackJumper(Posted 2005) [#10]
BlackJumper - that code would ignore the fact that a gap in like cells would interrupt the count.


I don't think so... the line
while (xx < 10) And (array(xx, y) = array(x,y))

will only continue to count along the line if the next cell equals the target cell.

By starting TopLeft and working right and down, you should cover every cell as the new target, and will know if it forms a long chain. What you wont know is which direction the chain runs in (unless you adopt the idea in (4) to encode the direction as well)

Here is a full example, showing that it does indeed count the 'chains'
Dim array(10,10)
Dim shadow(10,10)

Graphics 640, 480
For xval = 0 To 9
	display$ = ""
    For yval = 0 To 9
		array (xval, yval) = Rand(3)
		display$ = display$ + "   " + array(xval, yval)
	Next
	Print display$
Next



For x = 0 To 9
    For y = 0 To 9
        right_neighbours = 0
        ;checking the horiz_direction
        xx = x+1
        While (xx < 10) And (array(xx, y) = array(x,y))
              xx = xx + 1
              right_neighbours = right_neighbours + 1
        Wend
        shadow(x,y) = right_neighbours

        ; similar code for vertical
	 bottom_neighbours = 0
        ;checking the horiz_direction
        yy = y+1
        While (yy < 10) And (array(x, yy) = array(x,y))
              yy = yy + 1
              bottom_neighbours = bottom_neighbours + 1
        Wend
        shadow(x,y) = bottom_neighbours*10 + shadow(x,y)
    Next ; y
Next ; x
Print

For xval = 0 To 9
	display$ = ""
    For yval = 0 To 9
;		If shadow(xval,yval) = 0 Then
;			display$ = display$ + "  . "
;		Else
			display$ = display$ + " " + RSet$(shadow(xval, yval),3)
;		EndIf
	Next		
	Print display$
Next


WaitKey


Notice that at present the target cell is not included in the total, so a run of 8888 is recorded as a chain of '3' in the location of the target cell.

uncomment the lines at the end to ignore single examples with no neighbours


Apocalypse(Posted 2005) [#11]
Here's my 2 cents worth...Actually I was bored and just wanted to code my own example. This code will check the board for the first set of 3 it finds. You could modify the function to keep checking for further results but this is just a simple example..



I strongly recommend making any algorithms like this one as a function. It will save you time in the future and makes for easier to read and debug code.


Rook Zimbabwe(Posted 2005) [#12]
Apoc... Why do you return -1 in your algo? I see the pattern you have set up but I don't understand that bit...
-RZ


_PJ_(Posted 2005) [#13]
Hmm this isnt going to work until I can post my code. Sure I must have a floppy somewhere...


_PJ_(Posted 2005) [#14]
To further explain what I am trying to do, if you have Sky TV, there is a game called 'Jumble' in which you have a grid of fruits and must switch fruits with adjacent ones to make sections of rows or columns with the same fruits all in a line. If you get more than 3 in a row, they disappear for points and are filled with more fruit falling from above.

couldnt find any screenies or anything, but this might help...
http://www.sky.com/skycom/article/0,,90125-1078969,00.html


Apocalypse(Posted 2005) [#15]
@Rook: I return -1 so you know when the function doesn't find a 3 in a row. You can say...
Result=Check3InRow%()
if Result=-1 then
  'No triple found
  'continue here
else
  'Found Triple
  'Process Bonus 
  'Use Result to know which trip was found
endif



Rook Zimbabwe(Posted 2005) [#16]
I figured it was something like that! :) Your algo looks very nice. I am going to try it for a pick game I have in mind.
-RZ


_PJ_(Posted 2005) [#17]
THIS IS IT!!!

http://www.miniclip.com/fruitsmash.htm

This is exactly what I am trying to recreate. I need to identify all the fruits that may need to be destroyed...


_PJ_(Posted 2005) [#18]
Well - I did it. Somehow.

In short, I checked across the horizontal up to the check cell, counting how many were in a row (resetting the count as soon as a non-like fruit was found). Then, I checked the horizontal AFTER the check cell. Instead of resetting the count after, I just stopped the loop.

By setting a variable to the start of the like-fruits' location, (this was also reset if a break was found BEFORE the check cell), I then had a start position and length of the consecutive like-fruits in the horizontal row.

By then repeating the above for the vertical, I had specific boundaries for the relevant horizontal and vertical valid cells.

By putting these values back into some For/Next loops, I replaced the relevant cells with a '9' value then continued to the 'scoring' routines.

Thanks for all your help, peeps. It's difficult when the program itself isnt in front of me :)


Damien Sturdy(Posted 2005) [#19]
Excelent
I would have done it using a for/next and checked with angle/sin commands. For c=-1 to 1 transformed to sin(angle) meant i can check all angles from the centre using the same small piece of code.

I will check this out later as it could prove cleaner.


_PJ_(Posted 2005) [#20]
Well in this case, only vert and horiz was needed. However, I like the idea!

At some point, I'l adjust my code, clean it up and stick it in the Code Arcs. Im sure it will come in handy...



Oh - and I am SO glad arrays are global by default. I had so much fun trying

Global Dim a(10,10)
Dim Global a(10,10)

Global a
Dim a(10,10)

and others! :)