オセロ
Swift
ビットボード

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

対象読者

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

"ビットボード"を知らない人は、まず以下あたりを読むと良いかもしれません
ビットボードの凄さをざっくりと解説してみる

本記事は上記リンクからもう少し踏み込んで、初歩的な部分に関する実装例をまとめました
解説というよりも、"サンプルコード紹介"の意味合いが強い記事です
(ひっくり返す処理のサンプルであり、戻るや進むなどの処理は省略しています)

ちなみに

更なる高みを目指す場合は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進数で盤面を表現していく
とはいえ、中身は0と1が64個並んだものにすぎない
ので、分かりにくい場合は一度2進数に直すと理解しやすい

盤面の空きマス

ひとまず
手番側の盤面: 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)
    // 今回の着手が、その合法手ボードに含まれれば着手可能
    if (put & legalBoard) == put {
        return true
    }
    return false
}

合法手ボードの生成はビットボードの醍醐味の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を展開)
    //左
    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)

    // 手番側だけがパスの場合    
    if playerLegalBoard == 0x0000000000000000 && opponentLegalBoard != 0x0000000000000000 {
        return true
    }
    return false
}

終局の判定

終局とは、「両手番の合法手ボードに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)

    // 両手番とも置く場所がない場合    
    if playerLegalBoard == 0x0000000000000000 && opponentLegalBoard == 0x0000000000000000 {
        return true
    }
    return false
}

手番交代

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)
        // 今回の着手が、その合法手ボードに含まれれば着手可能
        if (put & legalBoard) == put {
            return true
        }
        return false
    }

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

        // 手番側だけがパスの場合    
        if playerLegalBoard == 0x0000000000000000 && opponentLegalBoard != 0x0000000000000000 {
            return true
        }
        return false
    }

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

        // 両手番とも置く場所がない場合    
        if playerLegalBoard == 0x0000000000000000 && opponentLegalBoard == 0x0000000000000000 {
            return true
        }
        return false
    }

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

実例

かなり雑な例だが、こんな感じで使う
もちろん実際にはこんな風には書かないです。touch座標やwhileと絡めてシンプルに書くはずです。

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