いものやま。

雑多な知識の寄せ集め

「BirdHead」を遊べるようにしてみた。(その6)

昨日までで、モデルの大部分は実装できた。

今日は、これらを繋ぎ合わせて動作させるコントローラを実装していく。

GameControllerクラス

コントローラはビューとモデルを結びつける「糊」の役割を果たすので、UIごとに作っていくことになる。
ここで作るのは、CUI用のコントローラ。

//==============================
// BirdHead
//------------------------------
// GameController.swift
//==============================

import Foundation

class GameController: GameInfoObserver {

  // 続く

GameInfoObserverプロトコルに準拠して、オブザーバになるようにしている。

プロパティとイニシャライザ

まずはプロパティとイニシャライザ。

  // 続き

  private var gameInfo: GameInfo
  private var players: [Player]

  var output: Bool
  var learn: Bool

  init(gameInfo: GameInfo, players: [Player]) {
    self.gameInfo = gameInfo
    self.players = players
    self.output = false
    self.learn = false

    self.gameInfo.addObserver(self)
  }

  // 続く

プロパティとして、出力を行うのかと、プレイヤーに学習を行わせるのかのフラグを持たせている。

あと、初期化のときに自身をオブザーバとして登録するようにしている。

ゲームの進行

次に、ゲームの進行

  // 続き

  func start() throws {
    while !self.gameInfo.isEnd {
      if !self.gameInfo.inDeal {
        if self.output {
          print("--------------------")
          print("deal...")
          print("----------")
        }
        try! self.gameInfo.deal()
      }

      let playerIndex = self.gameInfo.turnPlayerIndex
      let player = self.players[playerIndex]
      if self.output {
        print("[\(player.name)]")
      }
      let view = try! self.gameInfo.playerViewFor(playerIndex)
      let action = try player.select(view)
      if self.output {
        print("selected action: \(action)")
      }

      try! self.gameInfo.doAction(action)
    }
  }

  // 続く

やっていることはシンプルで、ディールの最初ならカードの分配を行って、あとは、手番プレイヤーを知り、そのプレイヤーにアクションの選択をさせ、選択されたアクションをゲーム情報に対して実行する、というのを繰り返しているだけ。
ここで、プレイヤーがアクションの選択をキャンセルする可能性があるので、その場合は例外をただ呼び出し元に投げるようにしている。
(例外が使えるって素晴らしいね!)

オブザーバとしての各メソッドの実装

最後に、オブザーバとしての各メソッドの実装。

  // 続き

  func gameInfoResolvedTrick(trickCount: Int, winner playerIndex: Int) {
    if self.output {
      print("----------")
      print("trick \(trickCount) is done.")
      print("\(self.players[playerIndex].name) takes trick.")
      print("----------")
    }

    if self.learn {
      for player in self.players {
        player.learn(0)
      }
    }
  }

  func gameInfoResolvedDeal(loserIndices: [Int], lastCards: [Int]) {
    if self.output {
      print("deal is done.")
      print("last cards:")
      for i in 0..<self.players.count {
        print("\(self.players[i].name): \(lastCards[i])")
      }
      print(loserIndices.map {(i: Int) -> String in self.players[i].name},
            terminator: "")
      print(" lose in deal.")
      print("minus points:")
      for i in 0..<players.count {
        print("\(players[i].name): \(self.gameInfo.minusPointCards[i])")
      }
    }

    if self.learn {
      for i in 0..<self.players.count {
        if loserIndices.indexOf(i) != nil {
          self.players[i].learn(lastCards[i])
        } else {
          self.players[i].learn(0)
        }
      }
    }
  }

  func gameInfoEnded() {
    if self.output {
      print("--------------------")
      print("game ended.")
      var losePlayerIndices: [Int] = [Int]()
      print("total minus points:")
      for i in 0..<self.players.count {
        var minusSum: Int = 0
        for minusPoint in self.gameInfo.minusPointCards[i] {
          minusSum += minusPoint
        }
        print("\(self.players[i].name): \(minusSum)")
        if minusSum >= GameInfo.LosePoint {
          losePlayerIndices.append(i)
        }
      }
      print(losePlayerIndices.map {(i: Int) -> String in self.players[i].name},
            terminator: "")
      print(" lose.")
    }
  }
}

通知がきたタイミングで、必要なら情報の出力、それとプレイヤーへ学習を行わせるということを行っている。

これでコントローラの実装も完了。
残すは実際のプレイヤーの実装のみ。

今日はここまで!