いものやま。

雑多な知識の寄せ集め

変種オセロをSwiftに移植してみた。(その8)

ボードの表示まで出来るようになった。

次は、人同士が対戦できるようにする。

Playerプロトコル

Rubyの場合、ダック・タイピングが出来るので、プレイヤーに共通のインタフェースをコード上に定義する必要はないのだけど、Swiftはそうではないので、プレイヤーに共通のインタフェースをちゃんと定義していく。

ということで、Playerプロトコルを以下のように定義。

/* Player.swift */

public protocol Player {
  func select(board: Board) -> Board.Action?
}

戻り値の型がオプショナル型となっているのは、途中でやめたい場合のアクションの指定が面倒だったから。
どういうことかというと、もしちゃんとやるなら、列挙型をBoard.Actionとは別に定義して、そこに.Exitという列挙子を追加し、さらにBoard.Actionとの変換を用意したりすることになるのだけど、それはとても面倒。
なので、nilが返ってきた場合にはゲームを終了するということにした。

ゲーム進行を管理するクラスの実装

プロトコルを定義したので、先にゲーム進行を管理するクラスの実装から。

/* Game.swift */

public class Game {
  public private(set) var blackPlayer: Player
  public private(set) var whitePlayer: Player

  public init(blackPlayer: Player, whitePlayer: Player) {
    self.blackPlayer = blackPlayer
    self.whitePlayer = whitePlayer
  }

  public func start() {
    var board = Board()

    var done = false
    while true {
      BoardViewer.view(board)

      if board.isGameEnd {
        done = true
        break
      }

      if board.mustPass {
        println("pass!")
        board = board.pass()
      } else {
        let player: Player
        if board.turn == .BLACK {
          player = self.blackPlayer
        } else {
          player = self.whitePlayer
        }

        let actionOpt = player.select(board)
        if let action = actionOpt {
          switch action {
          case let .Play(row, col):
            board = board.play(row, col)
          case let .Change(row, col):
            board = board.change(row, col)
          default:
            break
          }
        } else {
          break
        }
      }
    }

    println("----------")
    println("black: \(board.count(.BLACK)), white: \(board.count(.WHITE))")
    if done {
      if board.win(.BLACK) {
        println("\(BoardViewer.mark(.BLACK)) win.")
      } else if board.win(.WHITE) {
        println("\(BoardViewer.mark(.WHITE)) win.")
      } else {
        println("draw.")
      }
    } else {
      println("exit.")
    }
  }
}

Javaのinterfaceと同じく、Swiftのprotocolも型として使用することが出来るので、プロパティのblackPlayerwhitePlayerPlayerという型になっている。
そして、Playerというプロトコルに準拠したクラスはPlayer#select(_: Board)というメソッドを持っていることが約束されているので、それを呼び出して、ゲームを進めていく。

なお、ここで変種オセロをSwiftに移植してみた。(その2) - いものやま。で説明した、パラメータを持った列挙型のパターンマッチを行っている。

今日はここまで!