Edited at

オセロをビットボードで実装する


対象読者

ビットボード初心者がオセロをさくっと実装してみること」に重点を置いてます

"ビットボード"を知らない人は、まず以下あたりを読むと良いかもしれません

ビットボードの凄さをざっくりと解説してみる

本記事は上記リンクからもう少し踏み込んで、初歩的な部分に関する実装例をまとめました

解説というよりも、"サンプルコード紹介"の意味合いが強い記事です

(ひっくり返す処理のサンプルであり、戻るや進むなどの処理は省略しています)


ちなみに

更なる高みを目指す場合は「edax (世界最高峰のオセロソフト)」などを眺めると幸せになれます。

ビットボードのロジックもはるかに綺麗な実装になっています。

Null Window Search等の探索アルゴリズム、空きマス別メソッド、book構築などなど色々参考になります


2進数で表す

0と1しかないので、黒・白・空の3種類は表現できない

そこで、黒番と白番とで手番ごとに盤面を表現するのが上手い

例えばこんな盤面(黒番)だとする

Simulator Screen Shot - iPhone 5 - 2017-12-18 at 13.55.28.png

画像の出典: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を反転させている

こんな感じで全てを細かく説明しているとキリがないので、もうコード紹介に入ります


石をひっくり返す

今回のメイン

ビットボードであれば、再帰処理を書かずに石をひっくり返せる

盤面(黒番)

Simulator Screen Shot - iPhone 5 - 2017-12-18 at 13.55.28.png

例えばA4に置きたい場合、以下の流れをたどる

1) "A4"をビットに変換 →「0x0000008000000000」

2) 「0x0000008000000000」が着手可能な場所かを調べる

3) 可能なら着手し、石をひっくり返す

4) パスの判定

5) 終局の判定

6) 手番を交代

Swift4で実装していく

ファイルは以下の2つを作る


  • Board.swift : Boardクラス定義ファイル

  • bit.swift : ビット関連の関数定義ファイル


Boardクラスを作る

以下のようなBoardクラスを前提とする


Board.swift

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」という座標文字列をビットに変換


Board.swift

/**

* @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
}



着手できるかを判定


Board.swift

/**

* @brief 着手可否の判定
* @param put 置いた位置のみにフラグが立っている64ビット
* @return 着手可能ならtrue
*/

func canPut (put: UInt64) -> Bool {
// 着手可能なマスにフラグが立っている合法手ボードを生成
let legalBoard : UInt64 = makeLegalBoard(board: self)
// 今回の着手が、その合法手ボードに含まれれば着手可能
return (put & legalBoard) == put
}

合法手ボードの生成はビットボードの醍醐味の1つ。

手番側のボードを8方向それぞれにずらし、置ける場所にフラグを立てる。

番人として、最初に相手側ボードと特定のビットで積を取っている。これは、盤外に置ける可能性を排除するため。


Board.swift

/**

* @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
}



着手し、石を反転する


Board.swift

/**

* @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
}


Board.swift

/**

* @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つも立っていない状態」である

相手側もパスの場合は、終局になってしまうため


Board.swift

/**

* @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
}



終局の判定

終局とは、「両手番の合法手ボードに1つもフラグが立っていない状態」である


Board.swift

/**

* @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
}



手番交代


Board.swift

/**

* @brief 手番の入れ替え
*/

func swapBoard() {
//ボードの入れ替え
let tmp = playerBoard
playerBoard = opponentBoard
opponentBoard = tmp

//色の入れ替え
nowTurn = nowTurn * -1
}



終局結果の取得

勝者手番(色)と石数の取得メソッドを実装しておく


Board.swift

/**

* @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)
}


bit.swift

/**

* @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
}



まとめ


Board.swift

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
}



bit.swift

/**

* @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
}



実例

かなり雑な例だが、こんな感じで使う

もちろん実際にはこんな風には書かないです。


main.swift

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に...