[英]Searching for 'bubbles' in 2D array of chars in Java
我正在处理Go Game项目中的问题。
我有一个棋盘(goban),以2D字符数组表示。 在进行下一步操作之前,我想检查数组中的“气泡”。 Bubble应该是4个连接的相同字符区域,在4个方向上被另一组特定的相同字符包围。 如果存在此“气泡”,则应将其替换为其他字符。 但是可能会有更多区域,但并非所有区域都被封闭。 例如,我有这个板子:
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 | + + + + + + + + + + + + + |
- - - - - - - - - - - - - - -
我想找到X的气泡,将其计数并用'Z'代替。
我已经在Google上搜索了,我认为某些Connected-component标签算法或FloodFill可以完成这项工作,但我不确定如何实现它。 这是解决问题的方法还是较简单的方法? 谢谢
编辑:我试图找到一些模式,可以找到特定角色的区域并计算其自由度,但是当位置多层时,它总是失败。 更改数据结构可能是解决方案,但如果可能的话,我想照现在做。
我目前的解决方案是:
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
}
您可以使用递归方法(实际上是使用FloodFill理论)来做到这一点。
基本上,遍历整个网格,每次找到一个X时,将其替换为Z及其4个邻居(如果适用)。 但是诀窍是:与其再次替换它们而不必每次都循环,不如再次调用相同的(调用)方法来执行此操作。 递归将完成其余的工作。
这是它的(快速完成的)伪代码版本:(假定网格的索引从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);
}
据我所知,这是解决此问题的唯一方法 ,无论泡沫形状如何怪异,该方法都有效。 复杂度也不错。
这可以进一步优化,因为它当前检查显然不再包含X的字符(因为它们刚刚被Z取代)。 这留给读者练习:)
(注意: 扫雷游戏以及其他基于该解决方案的游戏)
这是我用于类似图像分析需求的一种算法(伪代码):
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);
基本上,您维护一组点的集合,其中每个点代表板上的连续点的“泡沫”。 扫描板上的每个位置,如果它是“ X”并且尚未存在于某个区域中,则创建一个新区域和一个包含该位置的堆栈,并且当堆栈中有任何项目时,请访问其邻居以寻找未访问的“ X” ,将它们添加到新区域并按发现的顺序堆叠。
最后,您将拥有一组点集,每个点集代表一个“气泡”。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.