棋盤

棋盤

學習練習

簡介

在 Go 裡,你可以搭配索引並使用 for 對 slice 進行疊代,也可以使用 range。range 還能讓你對 map 進行疊代。

每次疊代都會回傳兩個值:索引/鍵,以及該索引/鍵對應元素的副本。

對 slice 進行疊代

對 slice 執行迴圈輕而易舉,順序也和預期的一樣。

xi := []int{10, 20, 30}
for i, x := range xi {
  fmt.Println(i, x)
}
// outputs:
// 0, 10
// 1, 20
// 2, 30

對 map 進行疊代

對 map 進行疊代則會出現新的問題:順序變成隨機的。

hash := map[int]int{9: 10, 99: 20, 999: 30}
for k, v := range hash {
  fmt.Println(k, v)
}
// outputs, for example:
// 99 20
// 999 30
// 9 10
Note

上面的輸出看起來可能不太對,因為大家會預期在 map 宣告中排第一個的鍵/值組合 9 10 應該最先印出,而不是最後印出。 然而,map 本質上是無序的,並沒有所謂的第一個或最後一個鍵/值組合。 因此,對 map 的項目進行疊代時,項目的存取順序是隨機的,不會依循任何特定模式。 這表示上面的輸出是可能發生的,但你實際執行時得到的結果可能不同。 想了解更多,請參閱 Go 語言規格:range 子句。

略過鍵或值的疊代

在 Go 裡,未使用的變數會在建置時產生錯誤。 有時你只需要值,就像第一個範例那樣:

xi := []int{10, 20, 30}
for i, x := range xi {
  fmt.Println(x)
}
// Go build failed: i declared but not used

你可以用 _ 取代 i,告訴編譯器我們不使用那個值:

xi := []int{10, 20, 30}
for _, x := range xi {
  fmt.Println(x)
}
// outputs:
// 10
// 20
// 30

如果你只想印出索引,可以用 _ 取代 x,或是乾脆省略宣告:

xi := []int{10, 20, 30}
// for i, _ := range xi {
for i := range xi {
  fmt.Println(i)
}
// outputs:
// 0
// 1
// 2

定義型別

型別定義會建立一個新的具名型別,它和所有其他型別都不相同,即使底層型別一模一樣也一樣。

type File []bool

這裡的 File 指的是棋盤上單一的垂直行,通常標示為 A 到 H。這一行裡的每個格子都用一個布林值表示,標記該格是否被佔用。現在 File 定義好了,我們就可以在其他定義裡使用它:

type Chessboard map[string]File

board := Chessboard{
    "A": File{true, false, true},
    "B": File{false, true, false},
}

Chessboard 把行的識別碼對應到 File 值。每個 File 都是由布林值組成的 slice,代表某一行棋盤裡的格子。少了這些型別定義,board 就會是 map[string][]bool,這樣一來就更難理解我們實際表示的內容了。

說明

身為西洋棋愛好者,你會想寫一個屬於自己的版本。 沒錯,網路上或許已經有許多現成的西洋棋實作,但你的版本會是獨一無二的!

棋盤上的每個方格都用一組字母與數字來標示:

  • 水平排列的方格列稱為橫列,編號從 1 到 8。
  • 垂直排列的方格行稱為直行,標示從 A 到 H。
   A B C D E F G H
 8 # _ _ _ # _ _ # 8
 7 _ _ _ _ _ _ _ _ 7
 6 _ _ _ _ # _ _ # 6
 5 _ # _ _ _ _ _ # 5
 4 _ _ _ _ _ _ # # 4
 3 # _ # _ _ _ _ # 3
 2 _ _ _ _ _ _ _ # 2
 1 # _ _ _ _ _ _ # 1
   A B C D E F G H

1. 給定一個 Chessboard 和一個直行,計算有多少個方格被佔據

實作CountInFile(board Chessboard, file string) int函式。 它應該走訪 map,計算被佔據方格的總數。 回傳一個整數。 如果 map 中找不到指定的直行,就回傳零(0)。

CountInFile(board, "A")
// => 3

2. 給定一個 Chessboard 和一個橫列,計算有多少個方格被佔據

實作CountInRank(board Chessboard, rank int) int函式。 它應該走訪指定的橫列,計算被佔據方格的總數。 回傳一個整數。 如果指定的橫列不是有效的橫列(不在1到8之間,含),就回傳零(0)。

CountInRank(board, 2)
// => 1

3. 計算指定的棋盤上有多少個方格

實作CountAll(board Chessboard) int函式。 它應該計算棋盤上有多少個方格,並回傳一個整數。 由於你不需要檢查方格的內容,可以考慮使用 range 並同時省略index與value。

CountAll(board)
// => 64

4. 計算指定的棋盤上有多少個方格被佔據

實作CountOccupied(board Chessboard) int函式。 它應該計算棋盤上有多少個方格被佔據。 回傳一個整數。

CountOccupied(board)
// => 15
透過 GitHub 編輯 連結會在新視窗或分頁中開啟
Go Exercism

準備好開始 棋盤 了嗎?

註冊 Exercism,透過 34 個概念166 個練習 和真人引導來學習並精通 Go,全部免費。