Checking for rows and columns
Blitz3D Forums/Blitz3D Programming/Checking for rows and columns
| ||
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... |
| ||
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. |
| ||
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! |
| ||
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 |
| ||
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 FunctionIt 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 |
| ||
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 |
| ||
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 |
| ||
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! |
| ||
Yes but any of these could be modified for 4 or any amount you wished. |
| ||
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 |
| ||
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. |
| ||
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 |
| ||
Hmm this isnt going to work until I can post my code. Sure I must have a floppy somewhere... |
| ||
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 |
| ||
@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 |
| ||
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 |
| ||
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... |
| ||
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 :) |
| ||
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. |
| ||
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! :) |