I'm dealing with a problem in my Go Game project.
I have a board (goban), represented by 2D Array of chars. Before every next move, I would like to check for 'bubbles' in the array. Bubble should be an 4-connected area of identical chars surrounded in 4 directions by another group of specific identical chars. If this 'bubble' exists, the characters inside should be replaced by some others. But there could be more areas and not all of them are enclosed. For example, I have this board:
1 2 3 4 5 6 7 8 9 10 11 12 13
- - - - - - - - - - - - - - -
A | + + + + + + + + + + + + + |
B | + + + + + + + + + + + + + |
C | + + + + + + + + + + + + + |
D | + + + + + + + + + + + + + |
E | + + + + + + + + + + + + + |
F | + + O O O O + + + + + + + |
G | + O X X X X O + + + + + + |
H | + + O O X X O + + + + + + |
I | + + + + O X X O + + + + + |
J | + + + + O X O + + + + + + |
K | + + + + + O + + + + + + + |
L | + + + + + + + + + + + + + |
M | + + + + + + + + + + + + + |
- - - - - - - - - - - - - - -
And I would like to find the bubble of Xs, count them and replace them with 'Z's.
I've googled it and I think that some Connected-component labeling algorithm or FloodFill can do the job, but I'm not sure how to implement it. Is this the way or something less complicated could solve it? Thank you
Edit: I tried to find some pattern which could find the areas of specific character and count their liberties, but it always failed when the location was multilayered. Changing the data structure might be the solution, but if it is possible, I would like to do it as it is now.
My current solution idea:
public void solve(){
if (boardContainsEnclosedAreas(goban, onMovePlayerStone, oppositePlayerStone){
onMovePlayerScore += countElementsInAreaAndReplaceThem(onMovePlayerStone, 'Z');
}
}
public boolean boardContainsEnclosedAreas(char[][] playingBoard, char searchedChar, char surroundingChar){
// this method should find the bubble in the playingBoard array
}
public int countElementsInAreaAndReplaceThem(char searchedChar, char replacingChar){
// the method should go through the bubble and replace all inner chars
// returns amount of replaced chars
}
You can do that with a recursive method, indeed using the FloodFill theory.
Basically, run through your grid, and each time you find an X, replace it with a Z, as well as its 4 neighbours (if applicable). But the trick is: instead of just replacing them and having to loop again each time, call the same (calling) method again to do it. The recursivity will do the rest.
Here is a (quickly done) pseudo-code version of it: (assuming your grid is indexed from 0 to xmax, from 0 to ymax)
int numberOfBubbles = 0;
for (x = 0 to xmax) {
for (y = 0 to ymax) {
if (getCharAt(x, y) == "X") { // this if is needed because you want to count the bubbles. If not, you could just do handleBubble(x, y);
numberOfBubbles++;
handleBubble(x, y);
}
}
}
// Recursive method
void handleBubble(int x, int y) {
if (getCharAt(x, y) != "X") {
return; // exit condition
}
getCharAt(x, y) = "Z";
if (x > 0) handleBubble(x-1, y);
if (x < xmax) handleBubble(x+1, y);
if (y > 0) handleBubble(x, y-1);
if (y < ymax) handleBubble(x, y+1);
}
As far as I know, this is the only solution for this problem, which works whatever weird shape your bubble is. The complexity is not bad either.
This can be optimised further, as it currently checks for chars that are obviously not containing an X any more (because they've just been replaced with Z). This is left as an exercise to the reader :)
(NB: The minesweeper game, among other, is based on that solution)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With