2017-04-04 98 views
1

我是Scala和函數式編程的新手。我正在製作一個井字遊戲('Seven Words in Seven Weeks'(書))的第一天),我想知道如何以功能的方式做'檢查是否贏得'方法。在Scala中使用array.exists()

我想使'checkrow'部分(第一部分)像'checkcolumn'(第二部分)部分,但我正在嘗試不工作。

這裏我的(工作)代碼:

def checkGame() { 
    for (y <- board.indices) { 
     // checks a row 
     checkRow(y) 
    } 
    for (x <- board(0).indices) { 
     // checks a column 
     if(!board.exists(y => y(x) != 'x')){ 
     println("You have won mate! (column: " + x + ")") 
     } 
    } 
    } 

def checkRow(y: Integer) { 
var isWon = true 
for (x <- board(y).indices) { 

    if (board(y)(x) != 'x') { 
    isWon = false 
    } 
} 
if (isWon) println("You have won mate! (row: " + y + ")") 
} 

注:板是一個2維陣列。

我得到了什麼至今(不工作):

if(!board.exists(x => x(y) != 'x')){ 
     println("You have won mate! (row: " + x + ")") 
} 
+1

如果您使用'for'lopps和變量突變,您不會以「功能性方式」執行此操作。 – RichouHunter

回答

6

具有如exists高階函數的全部要點是避免穿越你的Array使用索引。

這裏是我會做:

def wonRow(row: Array[Char]): Boolean = row.forall(c => c == 'x') 

這使用forall方法,來檢查,如果陣列中的所有元素滿足謂詞(在這裏,所有的元素都必須'x')。

def wonSomeRow(board: Array[Array[Char]]: Boolean = board.exists(row => wonRow(row)) 

在這裏,我們認爲,一些行做一個雙贏如果陣列(所以任何行)的任何元素滿足謂詞(在這裏,是一個成功的行)

對於列,這是莫名其妙更復雜,所以最簡單的方法就是做你開始:

def wonColumn(board: Array[Array[Char]], col: Int) = board.forall(row => row(i) == 'x') 

def wonSomeColumn(board: Array[Array[Char]]) = (0 until board(0).size).exists(i => wonColumn(board, i)) 

不過,我強烈建議你通過一些恆定在你的代碼的頂部更換board(0).size,避免了收到的一些錯誤。事實上,這種假設

  • 1)board具有第一行
  • 2)board所有的行必須在列表的大小board(0).size

當然,這兩個假設都是在Tic- OK Tac-Toe,但在函數式編程中,這種編譯時的假設應該放在類型系統中,以便在編譯時進行驗證。然而,這將會是開始用這種類型的東西開始函數式編程的一個步驟(只知道它們存在)。

編輯

我只記得有關於陣列的方法transpose,這樣你就可以做(對於列)

def wonSomeCol(board: Array[Array[Char]]) = wonSomeRow(board.transpose) 
1

嗯...一個功能性的方法可以是使用foldLeft。在這裏,您從Int的兩個Set開始,每個對於包含所有行和列的winRows和winColumns。

然後,您將遊戲盤摺疊以消除不符合勝利條件的rowscolumns

def findVictoryRowsAndColumns(board: Array[Array[Char]], height: Int, width: Int): (Set[Int], Set[Int]) = { 
    val winRowsInit = (1 to height).toSet 
    val winColumnsInit = (1 to width).toSet 

    val (winRows, winColumns) = board.zipWithIndex.foldLeft((winRowsInit, winColumnsInit))({ 
    case ((winRows1, winColumns1), (row, rowIndex)) => row.zipWithIndex.foldLeft(winRows1, winColumns1)({ 
     case ((winRows2, winColumns2), (cell, columnIndex)) => cell match { 
     case 'x' => (winRows2, winColumns2) 
     case _ => (winRows2 - rowIndex, winColumns2 - columnIndex) 
     } 
    }) 
    }) 

    (winRows, winColumns) 
} 

def checkGame(board: Array[Array[Char]], height: Int, width: Int): Unit = { 
    val (winRows, winColumns) = findVictoryRowsAndColumns(board, height, width) 

    winRows.foreach(i => println("You have won in Row : " + i)) 
    winColumns.foreach(i => println("You have won in Column : " + i)) 
}