対象読者
「ビットボード初心者がオセロをさくっと実装してみること」に重点を置いてます
"ビットボード"を知らない人は、まず以下あたりを読むと良いかもしれません
ビットボードの凄さをざっくりと解説してみる
本記事は上記リンクからもう少し踏み込んで、初歩的な部分に関する実装例をまとめました
解説というよりも、"サンプルコード紹介"の意味合いが強い記事です
(ひっくり返す処理のサンプルであり、戻るや進むなどの処理は省略しています)
ちなみに
更なる高みを目指す場合は「edax (世界最高峰のオセロソフト)」などを眺めると幸せになれます。
ビットボードのロジックもはるかに綺麗な実装になっています。
Null Window Search等の探索アルゴリズム、空きマス別メソッド、book構築などなど色々参考になります
2進数で表す
0と1しかないので、黒・白・空の3種類は表現できない
そこで、黒番と白番とで手番ごとに盤面を表現するのが上手い
画像の出典:iOSアプリ「詰めオセロOrca」
石:1,空:0 で以下のように表現できる (A1から順に)
-黒番から見たボード-
00000000 00100000 00000010 00000100 00001100 01011100 00001100 0000000
-白番から見たボード-
00000000 00010000 01111000 01111000 00100000 00110000 00010000 0000000
16進数で表す
上記の2進数は長くて見にくいので、16進数で表現しなおす
数字4つごとに0〜F(15)に直すと以下のようになる
-黒番から見たボード-
00 20 02 04 9C 0C 00 00
すなわち 「0x002002049C0C0000」
-白番から見たボード-
00 10 70 78 20 30 10 00
すなわち 「0x0010707820301000」
*頭の「0x」は、「この数字は16進数だよ」という意味
基本的には、16進数で盤面を表現していく
盤面の空きマス
ひとまず
手番側の盤面: P (PlayerBoardに由来)
相手側の盤面: O (OpponentBoardに由来)
とすると、
この2つの盤面から、盤面の空きマスを生成するには、
~(P|O)
これで、空:1, 石:0とした盤面を取得できる
P|O
で論理和をとり、石:1,空:0の盤面を生成
そして、~
(否定)によって、その0と1を反転させている
こんな感じで全てを細かく説明しているとキリがないので、もうコード紹介に入ります
石をひっくり返す
今回のメイン
ビットボードであれば、再帰処理を書かずに石をひっくり返せる
例えばA4に置きたい場合、以下の流れをたどる
- "A4"をビットに変換 →「0x0000008000000000」
- 「0x0000008000000000」が着手可能な場所かを調べる
- 可能なら着手し、石をひっくり返す
- パスの判定
- 終局の判定
- 手番を交代
Swift4で実装していく
ファイルは以下の2つを作る
- Board.swift : Boardクラス定義ファイル
- bit.swift : ビット関連の関数定義ファイル
Boardクラスを作る
以下のようなBoardクラスを前提とする
import Foundation
class Board {
//MARK: Constant
let BLACK_TURN = 100
let WHITE_TURN = -100
//MARK: Properties
var nowTurn : Int // 現在の手番
var nowIndex : Int // 現在何手目か
var playerBoard : UInt64 // player側ビットボード
var opponentBoard : UInt64 // opponent側ビットボード
//MARK: Initialization
init() {
self.nowTurn = BLACK_TURN
self.nowIndex = 1
// 一般的な初期配置を指定
self.playerBoard = 0x0000000810000000
self.opponentBoard = 0x0000001008000000
}
}
座標をビットに変換
「C8」や「D1」という座標文字列をビットに変換
/**
* @brief 座標をbitに変換する
* @param x 横座標(A~H)
* @param y 縦座標(1~8)
* @return 着手箇所のみにフラグが立っている64ビット
*/
func coordinateToBit(x: String, y: String) -> UInt64 {
var mask: UInt64 = 0x8000000000000000
// X方向へのシフト
switch x {
case "A":
break
case "B":
mask = mask >> 1
case "C":
mask = mask >> 2
case "D":
mask = mask >> 3
case "E":
mask = mask >> 4
case "F":
mask = mask >> 5
case "G":
mask = mask >> 6
case "H":
mask = mask >> 7
default:
break
}
// Y方向へのシフト
let intY = Int(y)
mask = mask >> ( (intY! - 1) * 8)
return mask
}
着手できるかを判定
/**
* @brief 着手可否の判定
* @param put 置いた位置のみにフラグが立っている64ビット
* @return 着手可能ならtrue
*/
func canPut (put: UInt64) -> Bool {
// 着手可能なマスにフラグが立っている合法手ボードを生成
let legalBoard : UInt64 = makeLegalBoard(board: self)
// 今回の着手が、その合法手ボードに含まれれば着手可能
return (put & legalBoard) == put
}
合法手ボードの生成はビットボードの醍醐味の1つ。
手番側のボードを8方向それぞれにずらし、置ける場所にフラグを立てる。
番人として、最初に相手側ボードと特定のビットで積を取っている。これは、盤外に置ける可能性を排除するため。
/**
* @brief 手番側の合法手ボードを生成
* @param board Boardインスタンス
* @return Uint64 playerから見て、置けるマスのみにフラグが立っている64ビット
*/
private func makeLegalBoard(board: Board) -> UInt64 {
//左右端の番人
let horizontalWatchBoard : UInt64 = board.opponentBoard & 0x7e7e7e7e7e7e7e7e
//上下端の番人
let verticalWatchBoard : UInt64 = board.opponentBoard & 0x00FFFFFFFFFFFF00
//全辺の番人
let allSideWatchBoard : UInt64 = board.opponentBoard & 0x007e7e7e7e7e7e00
//空きマスのみにビットが立っているボード
let blankBoard : UInt64 = ~(board.playerBoard | board.opponentBoard)
//隣に相手の色があるかを一時保存する
var tmp : UInt64
//返り値
var legalBoard : UInt64
//8方向チェック
// ・一度に返せる石は最大6つ ・高速化のためにforを展開(ほぼ意味ないけどw)
//左
tmp = horizontalWatchBoard & (board.playerBoard << 1)
tmp |= horizontalWatchBoard & (tmp << 1)
tmp |= horizontalWatchBoard & (tmp << 1)
tmp |= horizontalWatchBoard & (tmp << 1)
tmp |= horizontalWatchBoard & (tmp << 1)
tmp |= horizontalWatchBoard & (tmp << 1)
legalBoard = blankBoard & (tmp << 1)
//右
tmp = horizontalWatchBoard & (board.playerBoard >> 1)
tmp |= horizontalWatchBoard & (tmp >> 1)
tmp |= horizontalWatchBoard & (tmp >> 1)
tmp |= horizontalWatchBoard & (tmp >> 1)
tmp |= horizontalWatchBoard & (tmp >> 1)
tmp |= horizontalWatchBoard & (tmp >> 1)
legalBoard |= blankBoard & (tmp >> 1)
//上
tmp = verticalWatchBoard & (board.playerBoard << 8)
tmp |= verticalWatchBoard & (tmp << 8)
tmp |= verticalWatchBoard & (tmp << 8)
tmp |= verticalWatchBoard & (tmp << 8)
tmp |= verticalWatchBoard & (tmp << 8)
tmp |= verticalWatchBoard & (tmp << 8)
legalBoard |= blankBoard & (tmp << 8)
//下
tmp = verticalWatchBoard & (board.playerBoard >> 8)
tmp |= verticalWatchBoard & (tmp >> 8)
tmp |= verticalWatchBoard & (tmp >> 8)
tmp |= verticalWatchBoard & (tmp >> 8)
tmp |= verticalWatchBoard & (tmp >> 8)
tmp |= verticalWatchBoard & (tmp >> 8)
legalBoard |= blankBoard & (tmp >> 8)
//右斜め上
tmp = allSideWatchBoard & (board.playerBoard << 7)
tmp |= allSideWatchBoard & (tmp << 7)
tmp |= allSideWatchBoard & (tmp << 7)
tmp |= allSideWatchBoard & (tmp << 7)
tmp |= allSideWatchBoard & (tmp << 7)
tmp |= allSideWatchBoard & (tmp << 7)
legalBoard |= blankBoard & (tmp << 7)
//左斜め上
tmp = allSideWatchBoard & (board.playerBoard << 9)
tmp |= allSideWatchBoard & (tmp << 9)
tmp |= allSideWatchBoard & (tmp << 9)
tmp |= allSideWatchBoard & (tmp << 9)
tmp |= allSideWatchBoard & (tmp << 9)
tmp |= allSideWatchBoard & (tmp << 9)
legalBoard |= blankBoard & (tmp << 9)
//右斜め下
tmp = allSideWatchBoard & (board.playerBoard >> 9)
tmp |= allSideWatchBoard & (tmp >> 9)
tmp |= allSideWatchBoard & (tmp >> 9)
tmp |= allSideWatchBoard & (tmp >> 9)
tmp |= allSideWatchBoard & (tmp >> 9)
tmp |= allSideWatchBoard & (tmp >> 9)
legalBoard |= blankBoard & (tmp >> 9)
//左斜め下
tmp = allSideWatchBoard & (board.playerBoard >> 7)
tmp |= allSideWatchBoard & (tmp >> 7)
tmp |= allSideWatchBoard & (tmp >> 7)
tmp |= allSideWatchBoard & (tmp >> 7)
tmp |= allSideWatchBoard & (tmp >> 7)
tmp |= allSideWatchBoard & (tmp >> 7)
legalBoard |= blankBoard & (tmp >> 7)
return legalBoard
}
着手し、石を反転する
/**
* @brief 着手し,反転処理を行う
* @param put: 着手した場所のみにフラグが立つ64ビット
*/
func reverse(put: UInt64) {
//着手した場合のボードを生成
var rev : UInt64 = 0
for k in 0..<8 {
var rev_ : UInt64 = 0
var mask : UInt64 = transfer(put: put, k: k)
while (mask != 0) && ((mask & opponentBoard) != 0) {
rev_ |= mask
mask = transfer(put: mask, k: k)
}
if (mask & playerBoard) != 0 {
rev |= rev_
}
}
//反転する
playerBoard ^= put | rev
opponentBoard ^= rev
//現在何手目かを更新
nowIndex = self.nowIndex + 1
}
/**
* @brief 反転箇所を求める
* @param put 着手した場所のビット値
* @param k 反転方向(8つ)
* @return 反転箇所にフラグが立っている64ビット
*/
private func transfer(put: UInt64, k: Int) -> UInt64 {
switch k {
case 0: //上
return (put << 8) & 0xffffffffffffff00
case 1: //右上
return (put << 7) & 0x7f7f7f7f7f7f7f00
case 2: //右
return (put >> 1) & 0x7f7f7f7f7f7f7f7f
case 3: //右下
return (put >> 9) & 0x007f7f7f7f7f7f7f
case 4: //下
return (put >> 8) & 0x00ffffffffffffff
case 5: //左下
return (put >> 7) & 0x00fefefefefefefe
case 6: //左
return (put << 1) & 0xfefefefefefefefe
case 7: //左上
return (put << 9) & 0xfefefefefefefe00
default:
return 0
}
}
パスの判定
パスとは、「手番側の合法手ボードのみにフラグが1つも立っていない状態」である
相手側もパスの場合は、終局になってしまうため
/**
* @brief パス判定 (= プレイヤーのみが置けない時)
* @return パスならtrue
*/
func isPass() -> Bool {
// 手番側の合法手ボードを生成
let playerLegalBoard = makeLegalBoard(board: self)
// 相手側の合法手ボードを生成
let tmpBoard = Board()
tmpBoard.nowTurn = nowTurn
tmpBoard.nowIndex = nowIndex
tmpBoard.playerBoard = opponentBoard
tmpBoard.opponentBoard = playerBoard
let opponentLegalBoard = makeLegalBoard(board: tmpBoard)
// 手番側だけがパスの場合
return playerLegalBoard == 0x0000000000000000 && opponentLegalBoard != 0x0000000000000000
}
終局の判定
終局とは、「両手番の合法手ボードに1つもフラグが立っていない状態」である
/**
* @brief 終局判定 (= 二人ともが置けない時)
* @return 終局ならtrue
*/
func isGameFinished() -> Bool {
let playerLegalBoard = makeLegalBoard(board: self)
let tmpBoard = Board()
tmpBoard.nowTurn = nowTurn
tmpBoard.nowIndex = nowIndex
tmpBoard.playerBoard = playerBoard
tmpBoard.opponentBoard = opponentBoard
let opponentLegalBoard = makeLegalBoard(board: tmpBoard)
// 両手番とも置く場所がない場合
return playerLegalBoard == 0x0000000000000000 && opponentLegalBoard == 0x0000000000000000
}
手番交代
/**
* @brief 手番の入れ替え
*/
func swapBoard() {
//ボードの入れ替え
let tmp = playerBoard
playerBoard = opponentBoard
opponentBoard = tmp
//色の入れ替え
nowTurn = nowTurn * -1
}
終局結果の取得
勝者手番(色)と石数の取得メソッドを実装しておく
/**
* @brief 結果を取得する
* @return blackScore 黒石の数
* @return whiteScore 白石の数
* @return winner 勝ち手番
*/
func getResult() -> (blackScore: Int, whiteScore: Int, winner: String) {
//石数を取得
var blackScore = bitCount(playerBoard)
var whiteScore = bitCount(opponentBoard)
if nowTurn == WHITE_TURN {
let tmp = blackScore
blackScore = whiteScore
whiteScore = tmp
}
// 勝敗情報を取得
var winner = "黒番"
let isWhiteWin = whiteScore >= blackScore
if isWhiteWin {
winner = "白番"
}
return (blackScore, whiteScore, winner)
}
/**
* @brief ビットカウント
* @param num 64ビット
* @return 立ってるフラグの数[Int]
*/
public func bitCount(_ num: UInt64) -> Int {
let BOARDSIZE = 64
var mask: UInt64 = 0x8000000000000000
var count: Int = 0
for _ in 0..<BOARDSIZE {
if mask & num != 0 {
count += 1
}
mask = mask >> 1
}
return count
}
まとめ
import Foundation
class Board {
//MARK: Constant
let BLACK_TURN = 100
let WHITE_TURN = -100
//MARK: Properties
var nowTurn : Int // 現在の手番
var nowIndex : Int // 現在何手目か
var playerBoard : UInt64 // player側ビットボード
var opponentBoard : UInt64 // opponent側ビットボード
//MARK: Initialization
init() {
self.nowTurn = BLACK_TURN
self.nowIndex = 1
// 一般的な初期配置を指定
self.playerBoard = 0x0000000810000000
self.opponentBoard = 0x0000001008000000
}
//MARK: Instance Function
/**
* @brief 着手可否の判定
* @param put 置いた位置のみにフラグが立っている64ビット
* @return 着手可能ならtrue
*/
func canPut (put: UInt64) -> Bool {
// 着手可能なマスにフラグが立っている合法手ボードを生成
let legalBoard : UInt64 = makeLegalBoard(board: self)
// 今回の着手が、その合法手ボードに含まれれば着手可能
return (put & legalBoard) == put
}
/**
* @brief 着手し,反転処理を行う
* @param put 着手した場所のみにフラグが立つ64ビット
*/
func reverse(put: UInt64) {
//着手した場合のボードを生成
var rev : UInt64 = 0
for k in 0..<8 {
var rev_ : UInt64 = 0
var mask : UInt64 = transfer(put: put, k: k)
while (mask != 0) && ((mask & opponentBoard) != 0) {
rev_ |= mask
mask = transfer(put: mask, k: k)
}
if (mask & playerBoard) != 0 {
rev |= rev_
}
}
//反転する
self.playerBoard ^= put | rev
self.opponentBoard ^= rev
//現在何手目かを更新
self.nowIndex = self.nowIndex + 1
}
/**
* @brief パス判定 (= プレイヤーのみが置けない時)
* @return パスならtrue
*/
func isPass() -> Bool {
// 手番側の合法手ボードを生成
let playerLegalBoard = makeLegalBoard(board: self)
// 相手側の合法手ボードを生成
let tmpBoard = Board()
tmpBoard.nowTurn = nowTurn
tmpBoard.nowIndex = nowIndex
tmpBoard.playerBoard = playerBoard
tmpBoard.opponentBoard = opponentBoard
let opponentLegalBoard = makeLegalBoard(board: tmpBoard)
// 手番側だけがパスの場合
return playerLegalBoard == 0x0000000000000000 && opponentLegalBoard != 0x0000000000000000
}
/**
* @brief 終局判定 (= 二人ともが置けない時)
* @return 終局ならtrue
*/
func isGameFinished() -> Bool {
let playerLegalBoard = makeLegalBoard(board: self)
let tmpBoard = Board()
tmpBoard.nowTurn = nowTurn
tmpBoard.nowIndex = nowIndex
tmpBoard.playerBoard = playerBoard
tmpBoard.opponentBoard = opponentBoard
let opponentLegalBoard = makeLegalBoard(board: tmpBoard)
// 両手番とも置く場所がない場合
return playerLegalBoard == 0x0000000000000000 && opponentLegalBoard == 0x0000000000000000
}
/**
* @brief 手番の入れ替え
*/
func swapBoard() {
//ボードの入れ替え
let tmp = playerBoard
playerBoard = opponentBoard
opponentBoard = tmp
//色の入れ替え
nowTurn = nowTurn * -1
}
/**
* @brief 結果を取得する
* @return blackScore 黒石の数
* @return whiteScore 白石の数
* @return winner 勝ち手番
*/
func getResult() -> (blackScore: Int, whiteScore: Int, winner: String) {
//石数を取得
var blackScore = bitCount(playerBoard)
var whiteScore = bitCount(opponentBoard)
if self.nowTurn == WHITE_TURN {
let tmp = blackScore
blackScore = whiteScore
whiteScore = tmp
}
// 勝敗情報を取得
var winner = "黒番"
let isWhiteWin = whiteScore >= blackScore
if isWhiteWin {
winner = "白番"
}
return (blackScore, whiteScore, winner)
}
}
//MARK: Private Function
/**
* @brief 反転箇所を求める
* @param put 着手した場所のみにフラグが立つ64ビット
* @param k 反転方向(8つ)
* @return 反転箇所にフラグが立っている64ビット
*/
private func transfer(put: UInt64, k: Int) -> UInt64 {
switch k {
case 0: //上
return (put << 8) & 0xffffffffffffff00
case 1: //右上
return (put << 7) & 0x7f7f7f7f7f7f7f00
case 2: //右
return (put >> 1) & 0x7f7f7f7f7f7f7f7f
case 3: //右下
return (put >> 9) & 0x007f7f7f7f7f7f7f
case 4: //下
return (put >> 8) & 0x00ffffffffffffff
case 5: //左下
return (put >> 7) & 0x00fefefefefefefe
case 6: //左
return (put << 1) & 0xfefefefefefefefe
case 7: //左上
return (put << 9) & 0xfefefefefefefe00
default:
return 0
}
}
/**
* @brief 手番側の合法手ボードを生成
* @param board Boardインスタンス
* @return playerから見て、置ける場所のみにフラグが立っている64ビット
*/
private func makeLegalBoard(board: Board) -> UInt64 {
//左右端の番人
let horizontalWatchBoard : UInt64 = board.opponentBoard & 0x7e7e7e7e7e7e7e7e
//上下端の番人
let verticalWatchBoard : UInt64 = board.opponentBoard & 0x00FFFFFFFFFFFF00
//全辺の番人
let allSideWatchBoard : UInt64 = board.opponentBoard & 0x007e7e7e7e7e7e00
//空きマスのみにビットが立っているボード
let blankBoard : UInt64 = ~(board.playerBoard | board.opponentBoard)
//隣に相手の色があるかを一時保存する
var tmp : UInt64
//返り値
var legalBoard : UInt64
//8方向チェック (・一度に返せる石は最大6つ ・高速化のためにforを展開)
//左
tmp = horizontalWatchBoard & (board.playerBoard << 1)
tmp |= horizontalWatchBoard & (tmp << 1)
tmp |= horizontalWatchBoard & (tmp << 1)
tmp |= horizontalWatchBoard & (tmp << 1)
tmp |= horizontalWatchBoard & (tmp << 1)
tmp |= horizontalWatchBoard & (tmp << 1)
legalBoard = blankBoard & (tmp << 1)
//右
tmp = horizontalWatchBoard & (board.playerBoard >> 1)
tmp |= horizontalWatchBoard & (tmp >> 1)
tmp |= horizontalWatchBoard & (tmp >> 1)
tmp |= horizontalWatchBoard & (tmp >> 1)
tmp |= horizontalWatchBoard & (tmp >> 1)
tmp |= horizontalWatchBoard & (tmp >> 1)
legalBoard |= blankBoard & (tmp >> 1)
//上
tmp = verticalWatchBoard & (board.playerBoard << 8)
tmp |= verticalWatchBoard & (tmp << 8)
tmp |= verticalWatchBoard & (tmp << 8)
tmp |= verticalWatchBoard & (tmp << 8)
tmp |= verticalWatchBoard & (tmp << 8)
tmp |= verticalWatchBoard & (tmp << 8)
legalBoard |= blankBoard & (tmp << 8)
//下
tmp = verticalWatchBoard & (board.playerBoard >> 8)
tmp |= verticalWatchBoard & (tmp >> 8)
tmp |= verticalWatchBoard & (tmp >> 8)
tmp |= verticalWatchBoard & (tmp >> 8)
tmp |= verticalWatchBoard & (tmp >> 8)
tmp |= verticalWatchBoard & (tmp >> 8)
legalBoard |= blankBoard & (tmp >> 8)
//右斜め上
tmp = allSideWatchBoard & (board.playerBoard << 7)
tmp |= allSideWatchBoard & (tmp << 7)
tmp |= allSideWatchBoard & (tmp << 7)
tmp |= allSideWatchBoard & (tmp << 7)
tmp |= allSideWatchBoard & (tmp << 7)
tmp |= allSideWatchBoard & (tmp << 7)
legalBoard |= blankBoard & (tmp << 7)
//左斜め上
tmp = allSideWatchBoard & (board.playerBoard << 9)
tmp |= allSideWatchBoard & (tmp << 9)
tmp |= allSideWatchBoard & (tmp << 9)
tmp |= allSideWatchBoard & (tmp << 9)
tmp |= allSideWatchBoard & (tmp << 9)
tmp |= allSideWatchBoard & (tmp << 9)
legalBoard |= blankBoard & (tmp << 9)
//右斜め下
tmp = allSideWatchBoard & (board.playerBoard >> 9)
tmp |= allSideWatchBoard & (tmp >> 9)
tmp |= allSideWatchBoard & (tmp >> 9)
tmp |= allSideWatchBoard & (tmp >> 9)
tmp |= allSideWatchBoard & (tmp >> 9)
tmp |= allSideWatchBoard & (tmp >> 9)
legalBoard |= blankBoard & (tmp >> 9)
//左斜め下
tmp = allSideWatchBoard & (board.playerBoard >> 7)
tmp |= allSideWatchBoard & (tmp >> 7)
tmp |= allSideWatchBoard & (tmp >> 7)
tmp |= allSideWatchBoard & (tmp >> 7)
tmp |= allSideWatchBoard & (tmp >> 7)
tmp |= allSideWatchBoard & (tmp >> 7)
legalBoard |= blankBoard & (tmp >> 7)
return legalBoard
}
/**
* @brief 座標をbitに変換する
* @param x 横座標(A~H)
* @param y 縦座標(1~8)
* @return 着手箇所のみにフラグが立っている64ビット
*/
public func coordinateToBit(x: String, y: String) -> UInt64 {
var mask: UInt64 = 0x8000000000000000
// X方向へのシフト
switch x {
case "A":
break
case "B":
mask = mask >> 1
case "C":
mask = mask >> 2
case "D":
mask = mask >> 3
case "E":
mask = mask >> 4
case "F":
mask = mask >> 5
case "G":
mask = mask >> 6
case "H":
mask = mask >> 7
default:
break
}
// Y方向へのシフト
let intY = Int(y)
mask = mask >> ( (intY! - 1) * 8)
return mask
}
/**
* @brief ビットカウント
* @param (num: UINT64)
* @return 立ってるフラグの数[Int]
*/
public func bitCount(_ num: UInt64) -> Int {
let BOARDSIZE = 64
var mask: UInt64 = 0x8000000000000000
var count: Int = 0
for _ in 0..<BOARDSIZE {
if mask & num != 0 {
count += 1
}
mask = mask >> 1
}
return count
}
実例
かなり雑な例だが、こんな感じで使う
もちろん実際にはこんな風には書かないです。
var board = Board()
// F5に着手
var put = coordinateToBit(x: "F", y: "5")
if board.canPut(put: put) {
board.reverse(put: put)
board.swapBoard()
}
if board.isPass(){
board.swapBoard()
}
if board.isGameFinished() {
let result = board.getResult()
print(result)
}
// D6に着手
put = coordinateToBit(x: "D", y: "6")
if board.canPut(put: put) {
board.reverse(put: put)
board.swapBoard()
}
if board.isPass(){
board.swapBoard()
}
if board.isGameFinished() {
let result = board.getResult()
print(result)
}
// C3に...