昨日は「BirdHead」に対するランダムAIを実装した。
今日はもうちょっとマシなAIを実装してみる。
グリーディAI
「22」や「5本のキュウリ」のルールを聞いたときに誰もが思うのが、「それなら一番強いカードを出し続ければいいんじゃないの?」というもの。
実際には、リードが取れないならしゃがんでディスカードしたり、後で邪魔になりそうなカードをプレイしたりするというのが必要になってくるのだけど、「常に一番強いカードを出し続ける」というのも一つの戦略。
そこで、これをグリーディAIとして実装してみる。
(グリーディは「貪欲」という意味で、一番効果の高い選択(今回の場合、一番強いカードを出す)を常に選び続けるアルゴリズムを一般に「グリーディ法」と呼ぶ)
//============================== // BirdHead //------------------------------ // GreedyCom.swift //============================== import Foundation class GreedyCom: Player { private(set) var name: String private(set) var isCom: Bool init(name: String) { self.name = name self.isCom = true } func select(view: GameInfo.PlayerView) throws -> Action { var action: Action! = nil var legalActions = view.legalActions if view.actionsInTrick.count == 0 { var cardCount: Int = 0 for legalAction in legalActions { if case .Play(let cards) = legalAction { if cards.count >= cardCount { cardCount = cards.count action = legalAction } } } } else { action = legalActions.removeLast() } return action } }
リードのときには、出来るだけ枚数が多く、その中でも一番数が大きいカードをプレイし、そうでない場合、合法手の一番最後の手(手札は強さ順にソートされているので、生成された合法手の一番最後が一番強いカードになっている)を選ぶようにしている。
実行例
グリーディAI同士で対戦させるコードは、以下。
import Foundation let deck = Deck() let game = GameInfo(deck: deck, playerCount: 4) let players: [Player] = [ GreedyCom(name: "Greedy Com 1"), GreedyCom(name: "Greedy Com 2"), GreedyCom(name: "Greedy Com 3"), GreedyCom(name: "Greedy Com 4"), ] let controller = GameController(gameInfo: game, players: players) controller.output = true try! controller.start()
これをビルドして実行すると、次のような感じ。
-------------------- deal... ---------- [Greedy Com 1] selected action: Play([10, 10]) [Greedy Com 2] selected action: Play([10, 10]) [Greedy Com 3] selected action: Play([11, 11]) [Greedy Com 4] selected action: Discard([2, 3]) ---------- trick 0 is done. Greedy Com 3 takes trick. ---------- [Greedy Com 3] selected action: Play([9, 9]) [Greedy Com 4] selected action: Play([9, 11]) [Greedy Com 1] selected action: Discard([2, 2]) [Greedy Com 2] selected action: Discard([2, 2]) ---------- trick 1 is done. Greedy Com 4 takes trick. ---------- [Greedy Com 4] selected action: Play([4, 4]) [Greedy Com 1] selected action: Play([7, 7]) [Greedy Com 2] selected action: Discard([3, 5]) [Greedy Com 3] selected action: Play([8, 11]) ---------- trick 2 is done. Greedy Com 3 takes trick. ---------- [Greedy Com 3] selected action: Play([8]) [Greedy Com 4] selected action: Play([9]) [Greedy Com 1] selected action: Discard([3]) [Greedy Com 2] selected action: Discard([6]) ---------- trick 3 is done. Greedy Com 4 takes trick. ---------- [Greedy Com 4] selected action: Play([8]) [Greedy Com 1] selected action: Discard([3]) [Greedy Com 2] selected action: Discard([6]) [Greedy Com 3] selected action: Discard([4]) ---------- trick 4 is done. Greedy Com 4 takes trick. ---------- [Greedy Com 4] selected action: Play([6]) [Greedy Com 1] selected action: Discard([4]) [Greedy Com 2] selected action: Play([7]) [Greedy Com 3] selected action: Play([7]) ---------- trick 5 is done. Greedy Com 3 takes trick. ---------- deal is done. last cards: Greedy Com 1: 5 Greedy Com 2: 6 Greedy Com 3: 5 Greedy Com 4: 5 ["Greedy Com 2"] lose in deal. minus points: Greedy Com 1: [] Greedy Com 2: [6] Greedy Com 3: [] Greedy Com 4: [] -------------------- deal... ---------- 〜省略〜 -------------------- deal... ---------- [Greedy Com 1] selected action: Play([10, 10]) [Greedy Com 2] selected action: Play([11, 11]) [Greedy Com 3] selected action: Discard([2, 2]) [Greedy Com 4] selected action: Discard([2, 3]) ---------- trick 0 is done. Greedy Com 2 takes trick. ---------- [Greedy Com 2] selected action: Play([8, 8, 8]) [Greedy Com 3] selected action: Play([9, 9, 11]) [Greedy Com 4] selected action: Discard([4, 4, 4]) [Greedy Com 1] selected action: Discard([2, 3, 4]) ---------- trick 1 is done. Greedy Com 3 takes trick. ---------- [Greedy Com 3] selected action: Play([5, 5, 5]) [Greedy Com 4] selected action: Play([7, 10, 11]) [Greedy Com 1] selected action: Discard([7, 7, 8]) [Greedy Com 2] selected action: Discard([2, 3, 5]) ---------- trick 2 is done. Greedy Com 4 takes trick. ---------- [Greedy Com 4] selected action: Play([6]) [Greedy Com 1] selected action: Play([9]) [Greedy Com 2] selected action: Play([10]) [Greedy Com 3] selected action: Discard([3]) ---------- trick 3 is done. Greedy Com 2 takes trick. ---------- deal is done. last cards: Greedy Com 1: 9 Greedy Com 2: 10 Greedy Com 3: 3 Greedy Com 4: 4 ["Greedy Com 2"] lose in deal. minus points: Greedy Com 1: [6] Greedy Com 2: [6, 6, 10] Greedy Com 3: [7, 9] Greedy Com 4: [6, 8, 7] -------------------- game ended. total minus points: Greedy Com 1: 6 Greedy Com 2: 22 Greedy Com 3: 16 Greedy Com 4: 21 ["Greedy Com 2"] lose.
積極的に複数枚リードや強いカードでのリードを行っていることが分かる。
ただ、最後のディールのGreedy Com 2の動きを追ってみると、手札が最初2, 3, 5, 8, 8, 8, 10, 10, 11, 11で、序盤に8, 8, 8, 11, 11を使ったことで10が2枚残ってしまっていて、これが最後まで響いてしまった感じ。
この辺りは難しいところだけれど、先に2枚の10を使ってしまって、どこかで11を使ってトリックをとり、3枚の8や残った11でリードしたいところかも。
もちろん、それで2枚の11が取り残されてしまう可能性もあるけど。
あと、全体的にプレイが単調。
まぁ、シンプルな戦略なので、仕方ないのだけど・・・
そこで、明日からは強化学習の方法を使って思考ルーチンを作ることを考えてみる。
今日はここまで!