5ラウンド目の3ターン目、つまり最後に残り3枚から選択する場面で最善の一手を選ぶ方法を考えてみた。
・自分が3枚のうちから1枚を選ぶとする
→自分が得点するか、自分以外(RandomAI1 or RandomAI2)が得点する。すべてのパターンを洗い出す。
→すべてのパターンから、そのラウンドの結果を算出し、さらにゲームの結果まで算出できる。
→それぞれの結果が起こりうる確率も計算できる。結果の期待値として、ゲーム結果の評価×確率を算出できる
…というのをすべての選択肢に対して行うことで、自分の選択肢でどれが最善なのかを選ぶことができる。
ゲーム結果の評価として、実際に最終的に決定する勝ち点(2 とか -1 とか)を使ってもいいが、
自分なりに考えた関数を用意してみた。これを調整することである程度評価方法を変えられることになる。
# -*- encoding: utf-8 -*- from saichugen import Player from saichugenlib import * class MyAI(Player): name = "MyAI" def __init__(self, hand): hand.sort() self.hand = hand def play(self, info): handstr = map(to_str, self.hand) # 未知カードから自分の手持ちを取り除く import copy self.unknowns = copy.copy(info['unknowns']) for i in self.hand: self.unknowns.remove(i) # 最終ラウンド&最終ターン以外はランダムに出す if (info['iround'] == 4) & (info['iturn'] == 2): # 手持ちカードのそれぞれを出したときの評価を決める valuations = [] for i in self.hand: # print "case", to_num(i), ":" # 自分の出したカードよりも小さいもの lt = [] # 自分の出したカードよりも大きいもの gt = [] for j in self.unknowns: if j < i: lt.append(to_num(j)) else: gt.append(to_num(j)) patterns = [] # 自分が得点するパターン if (len(lt) > 0) & (len(gt) > 0): tmp = copy.copy(info['round_score']) tmp[0] += to_num(i) patterns.append((len(lt) * len(gt) * 2, tmp)) # 自分以外が得点するパターン a = 13 * [0] for j in range(len(lt)): a[lt[j] - 1] += j for j in range(len(gt)): a[gt[j] - 1] += len(gt) - j - 1 for j in range(len(a)): if a[j] > 0: tmp = copy.copy(info['round_score']) tmp[1] += j + 1 patterns.append((a[j], tmp)) tmp = copy.copy(info['round_score']) tmp[2] += j + 1 patterns.append((a[j], tmp)) # すべてのパターンの結果を計算 for j in patterns: # そのラウンドの結果 mid = get_mid(j[1]) for k in range(3): if j[1][k] != mid: j[1][k] = 0 # ラウンドの結果をプラスしたゲームスコア for k in range(3): j[1][k] += info['game_score'][k] # 最終結果を評価(get_myscoreによる) valuation = 0 for j in patterns: # print j, get_myscore(j[1]) valuation += j[0] * get_myscore(j[1]) valuations.append(valuation) # print valuations return self.hand.pop(valuations.index(max(valuations))) from random import choice return self.hand.pop(choice(range(len(self.hand)))) def get_myscore(xs): mid = get_mid(xs) if xs[0] == mid: return abs(xs[1] - xs[2]) else: return -abs(mid - xs[0])
変数名もメチャクチャで、自分にしか内容を把握できそうにないひどいプログラムだ…orz
とはいえ、これでどの程度結果が良くなるのか試してみる。
前回同様、ランダムAI×2と10000回対戦してトータルスコアを見てみる。
$ time python saichugen.py [2248, -1193, -1055] real 0m37.556s user 0m37.232s sys 0m0.105s
おぉっ!予想以上の効果!!
何回かやってみたけど、
[2238, -1053, -1185] [2144, -1135, -1009] [2199, -1011, -1188]
と、平均0.2得点は出せるようだ。
最後の一手を考えるだけでここまで変わるとは…