我正在处理Go Game项目中的问题。
我有一个电路板(goban),由2D数组字符表示。在每次下一步之前,我想检查数组中的“气泡”。气泡应该是由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 | + + + + + + + + + + + + + |
- - - - - - - - - - - - - - -
我想找到Xs的气泡,计算它们并用'Z'替换它们。
我已经使用Google搜索,我认为某些连接组件标记算法或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
}
答案 0 :(得分:1)
您可以使用递归方法,确实使用 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替换)。这留给读者一个练习:)
(注意:扫雷游戏,基于该解决方案)
答案 1 :(得分:0)
这是我用于类似图像分析需求的算法(伪代码):
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' ,将它们添加到新区域并堆叠为已发现。
最后,你将拥有一系列积分,每个积分代表一个“泡沫”。