Author Topic: Need help with this, Code works sometimes not always  (Read 1407 times)

0 Members and 1 Guest are viewing this topic.

Offline Cobalt

  • QB64 Developer
  • Forum Resident
  • Posts: 878
  • At 60 I become highly radioactive!
    • View Profile
Need help with this, Code works sometimes not always
« on: May 30, 2020, 10:24:49 am »
So I'm playing around with an idea on a Match-3 type puzzle game and while the function to find the match seem to work its not marking certain tiles sometimes, if it is a group of 3 and the function has to check up or down after finding a match to the right it just doesn't seem to want to mark the last tile. I've attached an image showing what I mean. if you uncomment the  _DELAYs in the function you can see that it checks the last tile in those groups but for some reason it doesn't set the Matched flag.

Code: QB64: [Select]
  1. TYPE Tile_Data
  2.  ID AS _BYTE 'tile sprite
  3.  Searched AS _BYTE 'has tile been matched
  4.  Matched AS _BYTE 'set when the total number of connected tiles is greater than Min_match
  5.  '                 used to remove matched tiles
  6.  
  7. CONST TRUE = -1, FALSE = NOT TRUE
  8. CONST Min_Match = 3
  9.  
  10. SCREEN 9: RANDOMIZE 183 'TIMER
  11. 'define the game board
  12. DIM SHARED Board(-1 TO 21, -1 TO 21) AS Tile_Data '1 space boarder buffer area
  13.  
  14. 'fill game board with data
  15. FOR X%% = 0 TO 20
  16.  FOR Y%% = 0 TO 20
  17.   Board(X%%, Y%%).ID = INT(RND * 6) + 1
  18.   Board(X%%, Y%%).Searched = 0
  19. NEXT Y%%, X%%
  20.  
  21. FOR X%% = 0 TO 20
  22.  FOR Y%% = 0 TO 20
  23.   IF NOT Board(X%%, Y%%).Searched THEN result%% = Check_Tiles(X%%, Y%%, Board(X%%, Y%%).ID)
  24.   display_board
  25.   IF INKEY$ = CHR$(27) THEN Y%% = 21: X%% = 21
  26. NEXT Y%%, X%%
  27.  
  28. SUB display_board
  29.  'display the board
  30.  LOCATE 1, 1
  31.  FOR X%% = 0 TO 20
  32.   FOR Y%% = 0 TO 20
  33.    IF Board(X%%, Y%%).Matched THEN COLOR 14 ELSE COLOR 7
  34.    LOCATE 1 + Y%%, 1 + X%% * 2: PRINT STR$(Board(X%%, Y%%).ID)
  35.  NEXT Y%%, X%%
  36.  _DELAY .25
  37.  
  38. FUNCTION Check_Tiles%% (StartTileX%%, StartTileY%%, Match%%)
  39.  STATIC Count%%, Depth%%
  40.  'StartTileX%%- the board X location to start the search from
  41.  'StartTileY%%- the board Y location to start the search from
  42.  'Match%%- the tile id to be looking for
  43.  'current run depth
  44.  Depth%% = Depth%% + 1
  45.  LOCATE 1, 50: PRINT Count%%
  46.  LINE (7 + 16 * StartTileX%%, 0 + 14 * (StartTileY%%))-STEP(7, 14), 4, B
  47.  '--------------------check tiles in 4 cardial directions------------------
  48.  'check up
  49.  IF Board(StartTileX%%, StartTileY%% - 1).ID = Match%% THEN 'we find a match
  50.   IF NOT Board(StartTileX%%, StartTileY%% - 1).Searched THEN 'this spot has not already been matched
  51.    Count%% = Count%% + 1 'Total number of matches
  52.    Board(StartTileX%%, StartTileY%% - 1).Searched = TRUE 'make sure the next function run(if any) does not match this location again
  53.    LINE (7 + 16 * StartTileX%%, 0 + 14 * (StartTileY%% - 1))-STEP(7, 13), 12, B
  54.    result%% = Check_Tiles(StartTileX%%, StartTileY%% - 1, Match%%) 'move to the matched tile
  55.   END IF
  56.  '_DELAY .25
  57.  'check down
  58.  IF Board(StartTileX%%, StartTileY%% + 1).ID = Match%% THEN 'we find a match
  59.   IF NOT Board(StartTileX%%, StartTileY%% + 1).Searched THEN 'this spot has not already been matched
  60.    Count%% = Count%% + 1 'Total number of matches
  61.    Board(StartTileX%%, StartTileY%% + 1).Searched = TRUE 'make sure the next function run(if any) does not match this location again
  62.    LINE (7 + 16 * StartTileX%%, 0 + 14 * (StartTileY%% + 1))-STEP(7, 13), 12, B
  63.    result%% = Check_Tiles(StartTileX%%, StartTileY%% + 1, Match%%) 'move to the matched tile
  64.   END IF
  65.  '_DELAY .25
  66.  'check left
  67.  IF Board(StartTileX%% - 1, StartTileY%%).ID = Match%% THEN 'we find a match
  68.   IF NOT Board(StartTileX%% - 1, StartTileY%%).Searched THEN 'this spot has not already been matched
  69.    Count%% = Count%% + 1 'Total number of matches
  70.    Board(StartTileX%% - 1, StartTileY%%).Searched = TRUE 'make sure the next function run(if any) does not match this location again
  71.    LINE (7 + 16 * (StartTileX%% - 1), 0 + 14 * StartTileY%%)-STEP(7, 13), 14, B
  72.    result%% = Check_Tiles(StartTileX%% - 1, StartTileY%%, Match%%) 'move to the matched tile
  73.   END IF
  74.  'check right
  75.  IF Board(StartTileX%% + 1, StartTileY%%).ID = Match%% THEN 'we find a match
  76.   IF NOT Board(StartTileX%% + 1, StartTileY%%).Searched THEN 'this spot has not already been matched
  77.    Count%% = Count%% + 1 'Total number of matches
  78.    Board(StartTileX%% + 1, StartTileY%%).Searched = TRUE 'make sure the next function run(if any) does not match this location again
  79.    LINE (7 + 16 * (StartTileX%% + 1), 0 + 14 * StartTileY%%)-STEP(7, 13), 14, B
  80.    result%% = Check_Tiles(StartTileX%% + 1, StartTileY%%, Match%%) 'move to the matched tile
  81.   END IF
  82.  '----------------------------------------------------------------------------
  83.  IF Count%% >= Min_Match THEN Board(StartTileX%%, StartTileY%%).Matched = TRUE
  84.  Check_Tiles = Count%% 'return how many tiles matched(only used by Main loop)
  85.  IF Depth%% = 1 THEN Count%% = 0: Depth%% = 0 ELSE Depth%% = Depth%% - 1
  86.  _DELAY .1
  87.  

too lazy to run it, here is a video of it running, though the quality is less than stellar.
« Last Edit: May 30, 2020, 11:49:20 am by Cobalt »
Granted after becoming radioactive I only have a half-life!

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Need help with this, Code works sometimes not always
« Reply #1 on: May 30, 2020, 02:07:55 pm »
How does this look?

  [ You are not allowed to view this attachment ]  

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: Need help with this, Code works sometimes not always
« Reply #2 on: May 30, 2020, 02:16:02 pm »
Hi Bplus, yours looks good. I'm also trying to figure it out. So far without success. What did you do with it?

Offline Cobalt

  • QB64 Developer
  • Forum Resident
  • Posts: 878
  • At 60 I become highly radioactive!
    • View Profile
Re: Need help with this, Code works sometimes not always
« Reply #3 on: May 30, 2020, 02:19:46 pm »
How does this look?

  [ You are not allowed to view this attachment ]

that looks like it should.
What did I goof?
Granted after becoming radioactive I only have a half-life!

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Need help with this, Code works sometimes not always
« Reply #4 on: May 30, 2020, 02:32:16 pm »
Quote
What did I goof?

Don't know, yours was too complicated so I went my own route, recursion is tricky!

Code: QB64: [Select]
  1. _TITLE "Match 3+ problem"
  2. DEFINT A-Z 'to avoid suffix
  3. TYPE Tile_Data
  4.     ID AS INTEGER 'tile sprite
  5.     Matched AS INTEGER 'tile will at least match itself when checked  0 indicates not checked yet
  6.  
  7.  
  8. SCREEN 9: RANDOMIZE 183 'TIMER   'same colors as screen 12?
  9. 'define the game b
  10. DIM SHARED b(-1 TO 21, -1 TO 21) AS Tile_Data '1 space board buffer area, good idea!
  11. DIM SHARED f(-1 TO 21, -1 TO 21) AS INTEGER 'finds board
  12.  
  13. 'fill game board with data
  14. FOR x = 0 TO 20
  15.     FOR y = 0 TO 20
  16.         b(x, y).ID = INT(RND * 6) + 1
  17.         b(x, y).Matched = 0 ' with udt good idea to zero init
  18.     NEXT
  19.  
  20. FOR x = 0 TO 20
  21.     FOR y = 0 TO 20
  22.         IF b(x, y).Matched = 0 THEN runSearch x, y, b(x, y).ID
  23.         display
  24.         IF INKEY$ = CHR$(27) THEN SYSTEM
  25.     NEXT
  26.  
  27. SUB display
  28.     CLS
  29.     FOR x = 0 TO 20
  30.         FOR y = 0 TO 20
  31.             IF b(x, y).Matched > 2 THEN COLOR 14 ELSE COLOR 7
  32.             LOCATE 1 + y, 1 + x * 2: PRINT STR$(b(x, y).ID)
  33.         NEXT
  34.     NEXT
  35.     '_DELAY 4
  36.  
  37. SUB runSearch (x, y, n)
  38.     ERASE f 'clear the finds board for next square
  39.     search x, y, n
  40.     'CLS
  41.     'count finds
  42.     FOR c = 0 TO 20
  43.         FOR r = 0 TO 20
  44.             IF f(c, r) = 1 THEN count = count + 1
  45.             'LOCATE r + 1, c * 2 + 1: PRINT STR$(f(c, r));
  46.         NEXT
  47.     NEXT
  48.     'now we have counted matches for cells found matching
  49.     FOR c = 0 TO 20
  50.         FOR r = 0 TO 20
  51.             IF f(c, r) = 1 THEN b(c, r).Matched = count
  52.         NEXT
  53.     NEXT
  54.     '_DELAY 2
  55.  
  56. SUB search (x, y, n)
  57.     IF b(x, y).ID = n THEN
  58.         IF b(x, y).Matched = 0 THEN
  59.             IF f(x, y) = 0 THEN
  60.                 f(x, y) = 1
  61.                 search x + 1, y, n
  62.                 search x - 1, y, n
  63.                 search x, y + 1, n
  64.                 search x, y - 1, n
  65.             END IF
  66.         END IF
  67.     END IF
  68.  
  69.  

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: Need help with this, Code works sometimes not always
« Reply #5 on: May 30, 2020, 02:40:37 pm »
Great job, BPlus!

Offline Cobalt

  • QB64 Developer
  • Forum Resident
  • Posts: 878
  • At 60 I become highly radioactive!
    • View Profile
Re: Need help with this, Code works sometimes not always
« Reply #6 on: May 30, 2020, 02:48:59 pm »
well that helps and doesn't help at the same time! :(

what exactly are you doing with f()?

and how do you keep track of tiles already searched so you don't waste time researching them say if they were right and left of each other?
I mean if there was only 2 so not a 3(or more) set.
Granted after becoming radioactive I only have a half-life!

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Need help with this, Code works sometimes not always
« Reply #7 on: May 30, 2020, 02:58:53 pm »
f() the finds array, is cleaned out for every non searched tile in the board.

Starting at that tile x, y not checked yet from b() board array, all matching tiles are marked with the recursive search sub that touch the start tile. The search sub will always at least mark the original tile as searched first and then branch left/right/up/down for another match. If another one is found (not already matched up in f() or b() then it is marked as match in f() and another search is issued around that square... keeps going until no more matches found or already matched up.

Then runSearch counts all tiles marked as matching and puts that count in the b().Matching for all those x, y tiles found in f() array.
« Last Edit: May 30, 2020, 03:00:50 pm by bplus »

Offline TempodiBasic

  • Forum Resident
  • Posts: 1792
    • View Profile
Re: Need help with this, Code works sometimes not always
« Reply #8 on: May 31, 2020, 07:24:14 am »
Hi Guys
execellent algorythm Bplus!

Hi Cobalt about the debugging of your algorythm
I have tryed to modify to my use your code to see where it makes the glicth but it is not necessary!. As you have already pointed out the issue is about to catch the right MATCHED tiles!

You can notice that

1. only after going to right at recursive way... in fact you loose the UP or the DOWN tile founded

so the issue is in the part of code that mark as MATCHED the tile!

Code: QB64: [Select]
  1. IF Count%% >= Min_Match THEN Board(StartTileX%%, StartTileY%%).Matched = TRUE

it is a single line of code, but why  does it loose the UP and DOWN tile after a RIGHT tile in n matched tiles? 
We can note that DEPTH%% and COUNT%% don't have always the same value, can this make the difference?

« Last Edit: May 31, 2020, 07:27:59 am by TempodiBasic »
Programming isn't difficult, only it's  consuming time and coffee

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Need help with this, Code works sometimes not always
« Reply #9 on: May 31, 2020, 11:50:18 am »
See, that was the problem. You don't mark the tiles until you know the count and you can't count properly unless you mark the tiles, a Catch-22 situation.

So I thought you needed another array f() for a temp storage array (SHARED so it is seen by every recursion instance of Search sub) to track the matching tiles found for the particular tile you are searching from, that's how my f() array came about.
« Last Edit: May 31, 2020, 11:53:43 am by bplus »

Offline TempodiBasic

  • Forum Resident
  • Posts: 1792
    • View Profile
Re: Need help with this, Code works sometimes not always
« Reply #10 on: June 01, 2020, 03:56:20 am »
Yes this is the reason that let me say excellent  to your solution,
 IMHO you touch the problem in its essence.

I have tried to chunk down the part of  code about searching but the issue is in the evaluation of matched (marking the tile) tile.
I was thinking about to use  3 different code for the flag .search of tile  and a flag to sign when count is over cutoff (2 in this homework) but I need a fresh mind to go on with this idea. Surely the evaluation task must be put out of searching block code!

Interesting lesson about the traps of recursion!  :-)
Programming isn't difficult, only it's  consuming time and coffee

Offline TempodiBasic

  • Forum Resident
  • Posts: 1792
    • View Profile
Re: Need help with this, Code works sometimes not always
« Reply #11 on: June 01, 2020, 04:51:13 am »
Yes I got it! :-)

A fresh mind is the best tool to code!  ;)

here the solution of code of Cobalt using a Flag%% for output and evaluating the tiles out of the recursive function and plus options for the flag of status of tile .searched.

  [ You are not allowed to view this attachment ]  

it seems to work well.

and here the code chunked down to my habit

Code: QB64: [Select]
  1. TYPE Tile_Data
  2.     ID AS _BYTE 'tile sprite
  3.     Searched AS _BYTE 'has tile been matched
  4.  
  5. CONST TRUE = -1, FALSE = NOT TRUE
  6. CONST Min_Match = 3, InSearch = 10, Matched = 20, ToSearch = 30, Done = 40
  7.  
  8. SCREEN 9: RANDOMIZE 183 'TIMER
  9. 'define the game board 23x23 with  borders -1 and 21
  10. DIM SHARED Board(-1 TO 21, -1 TO 21) AS Tile_Data '1 space boarder buffer area
  11. DIM SHARED Flag%%, Count%%
  12.  
  13. Initialize
  14.  
  15. ' main search loop
  16. FOR X%% = 0 TO 20
  17.     FOR Y%% = 0 TO 20
  18.         Flag%% = FALSE
  19.         Count%% = 0
  20.         IF Board(X%%, Y%%).Searched = ToSearch THEN result%% = Check_Tiles(X%%, Y%%, Board(X%%, Y%%).ID)
  21.         display_board
  22.         ' escape option
  23.         IF INKEY$ = CHR$(27) THEN Y%% = 21: X%% = 21
  24. NEXT Y%%, X%%
  25. END ' a logical end always must be put
  26.  
  27. '.....................SUB/FUNCTIONs..........
  28. SUB display_board
  29.     'display the board
  30.     LOCATE 23, 40: PRINT Flag%%;
  31.     LOCATE 1, 1
  32.     FOR X%% = 0 TO 20
  33.         FOR Y%% = 0 TO 20
  34.             ' this marks the tile to show them
  35.             IF Flag%% AND Board(X%%, Y%%).Searched = InSearch THEN Board(X%%, Y%%).Searched = Matched
  36.             ' this lets free the tiles with InSearch when No flag is set
  37.             IF (NOT Flag%%) AND Board(X%%, Y%%).Searched = InSearch THEN Board(X%%, Y%%).Searched = Done
  38.             ' this shows the board
  39.             IF Board(X%%, Y%%).Searched = Matched THEN COLOR 14 ELSE COLOR 7
  40.             LOCATE 1 + Y%%, 1 + X%% * 2: PRINT STR$(Board(X%%, Y%%).ID)
  41.     NEXT Y%%, X%%
  42.     LOCATE 24, 1: PRINT "Press ESC to escape";
  43.     _DELAY .25
  44.  
  45. FUNCTION Check_Tiles%% (StartTileX%%, StartTileY%%, Match%%)
  46.     ''    STATIC Count%%, Depth%%
  47.     'StartTileX%%- the board X location to start the search from
  48.     'StartTileY%%- the board Y location to start the search from
  49.     'Match%%- the tile id to be looking for
  50.  
  51.     LOCATE 1, 50: PRINT Count%%; "  "; Match%%; "   "; Flag%%
  52.     LINE (7 + 16 * StartTileX%%, 0 + 14 * (StartTileY%%))-STEP(7, 14), 4, B
  53.     '--------------------check tiles in 4 cardial directions------------------
  54.     'check up
  55.     EvaluateTile StartTileX%%, StartTileY%% - 1, Match%%
  56.     'check down
  57.     EvaluateTile StartTileX%%, StartTileY%% + 1, Match%%
  58.     'check left
  59.     EvaluateTile StartTileX%% - 1, StartTileY%%, Match%%
  60.     'check right
  61.     EvaluateTile StartTileX%% + 1, StartTileY%%, Match%%
  62.     '----------------------------------------------------------------------------
  63.     Check_Tiles = Count%% 'return how many tiles matched(only used by Main loop)
  64.     _DELAY .1
  65.  
  66. SUB EvaluateTile (X%%, Y%%, Match%%)
  67.     'we find a match
  68.     IF Board(X%%, Y%%).ID = Match%% AND Board(X%%, Y%%).Searched = ToSearch THEN 'this spot has not already been matched
  69.  
  70.         ' if we get a match we can increase count of matched tiles founded
  71.         Count%% = Count%% + 1
  72.  
  73.         ' we activate the flag for output
  74.         IF Count%% >= Min_Match THEN Flag%% = TRUE
  75.  
  76.         'make sure the next function run(if any) does not match this location again
  77.         Board(X%%, Y%%).Searched = InSearch
  78.         LINE (7 + 16 * X%%, 0 + 14 * (Y%% - 1))-STEP(7, 13), 12, B
  79.         result%% = Check_Tiles(X%%, Y%%, Match%%) 'move to the matched tile
  80.     END IF
  81.  
  82. SUB Initialize
  83.     'fill game board with data
  84.     FOR X%% = 0 TO 20
  85.         FOR Y%% = 0 TO 20
  86.             Board(X%%, Y%%).ID = INT(RND * 6) + 1
  87.             Board(X%%, Y%%).Searched = ToSearch
  88.     NEXT Y%%, X%%
  89.     Flag%% = FALSE
  90.     Count%% = 0

As you can see no more STATIC variables Depth%% & Count%% but just a SHARED Count%% and I have left Check_Tiles as Function but it is a real SUB because the result now is dummy.
Thanks to read and try
Programming isn't difficult, only it's  consuming time and coffee