简体   繁体   English

在Java的2D字符数组中搜索“气泡”

[英]Searching for 'bubbles' in 2D array of chars in Java

I'm dealing with a problem in my Go Game project. 我正在处理Go Game项目中的问题。

I have a board (goban), represented by 2D Array of chars. 我有一个棋盘(goban),以2D字符数组表示。 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. Bubble应该是4个连接的相同字符区域,在4个方向上被另一组特定的相同字符包围。 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. 我想找到X的气泡,将其计数并用'Z'代替。

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. 我已经在Google上搜索了,我认为某些Connected-component标签算法或FloodFill可以完成这项工作,但我不确定如何实现它。 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. 您可以使用递归方法(实际上是使用FloodFill理论)来做到这一点。

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). 基本上,遍历整个网格,每次找到一个X时,将其替换为Z及其4个邻居(如果适用)。 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) 这是它的(快速完成的)伪代码版本:(假定网格的索引从0到xmax,从0到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). 这可以进一步优化,因为它当前检查显然不再包含X的字符(因为它们刚刚被Z取代)。 This is left as an exercise to the reader :) 这留给读者练习:)

(NB: The minesweeper game, among other, is based on that solution) (注意: 扫雷游戏以及其他基于该解决方案的游戏)

Here's an algorithm (in pseudocode) that I've used for similar image analysis needs: 这是我用于类似图像分析需求的一种算法(伪代码):

regions = Collection<Set<Point>>
foreach (Point p : allBoardLocations)
  if (charAtLocation(p) != 'X') continue
  foundInRegion = false
  for (Set<Point> s : regions)
    if (s.contains(p))
      foundInRegion=true
      break;
  if (!foundInRegion)
    newRegion = new Set<Point>()
    stack = new Stack<Point>()
    stack.push(p)
    while (!stack.empty())
      foreach (Point n : neighboringPoints(stack.pop()))
        if (charAtLocation(n) == 'X')
          if (!newRegion.contains(n))
            newRegion.add(n);
            stack.push(n);

Bascially, you maintain a collection of sets of points where each set represents a "bubble" of contiguous points on the board. 基本上,您维护一组点的集合,其中每个点代表板上的连续点的“泡沫”。 Scan each location on the board and if it's an 'X' and it is not already in a region then create a new region and a stack containing the location and while there is any item on the stack, visit its neighbors searching for unvisited 'X's, adding them to the new region and stack as discovered. 扫描板上的每个位置,如果它是“ X”并且尚未存在于某个区域中,则创建一个新区域和一个包含该位置的堆栈,并且当堆栈中有任何项目时,请访问其邻居以寻找未访问的“ X” ,将它们添加到新区域并按发现的顺序堆叠。

At the end the you'll have a collection of sets of points, each representing a "bubble". 最后,您将拥有一组点集,每个点集代表一个“气泡”。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM