簡體   English   中英

在Java的2D字符數組中搜索“氣泡”

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM