ということで、大富豪をAI(DLR利用)に対応

以下、簡単な説明。ufcpp.netの方にちゃんとした説明書かなきゃなぁ。こんな実装でいいんでしょうか。LL派な人からご意見もらえるとうれしい。

大富豪のルール的な話

基本的にニコッとタウンの大富豪ルールに準拠。

ローカルルール

  • 同ランク複数枚あり
  • 同色連番あり
  • スイート縛り(2人目が初手と同じスイートを出したら、以後そのスイートしか出せない)あり
  • 連番縛り(階段: 初手が同スイート連番で、2人目がさらに初手と連番になるようにカードを出したら、以後、ぴったり連番でないと出せない)あり
  • 革命はJoker含めて4枚以上場に出たら起こる

実のところ未完成。以下の欠陥あり。

  • 2やJokerで普通に上がれる
  • 大富豪⇔大貧民、富豪⇔貧民間のカード交換実装してない
  • 勝負が終わっても順位表とか表示されない

WPFアプリ

  • 手動でカードを選んでプレイも可能
    • でも、全員分のカードが見えている状態なので、手動でプレイしても面白くない
  • 「auto」ボタンを押すと、AIが自動でカードを選ぶ
AI登録の仕方
  • 右クリックメニューから「AI設定」でAI用のスクリプトを登録できます。
  • 今のところ、PythonRubyに対応
  • ただし、自分で動作確認をしたのはPythonのみ

ちなみに、エラー処理を全然やってないんで、エラーのあるスクリプトを登録すると例外で止まります。

スクリプトの仕様

ちなみに、実装上、DLRを呼び出してるのはソースファイル中の DaifugouWpf\ScripAi.cs

スクリプトへの入力

スクリプトが実行される直前に、C#側で以下の変数を設定します

  • hand: 今現在の手札一覧(Card型の配列)
  • table: 今、場に出ているカード一覧(Card型の配列)
  • rank: 今、場に出ているカードのランク(int、複数枚出ている場合はそのうち最大のランク)
  • suit: (スイート縛り状態の場合のみ)どのスイートで縛られているか(enum Suit)
  • mode: 今現在のモード(enum Mode: ビットフラグ。詳細は後述)
  • revolution: 革命状態かどうか(bool)
  • history: 過去1ターンの履歴(History型。詳細は口述)

あと、System.Randomクラスのインスタンスが rand という名前の変数に格納してあります。

mode は以下のような enum

[Flags]
public enum Mode
{
    // 初手。なんでも出せる状態。
    First = 0,
    // 通常。
    Normal = 1,
    // 同ランク複数枚。
    Multiple = 2,
    // 同スイート連番。
    Sequence = 4,
    // スイート縛り。
    // 初手の人と2番目の人が同じスイートのカードを出したら次からそのスイートしか出せなくなるやつ。
    SuitBound = 8,
    // いわゆる「階段」状態。
    // 初手 { 3, 4 } の直後に { 5, 6 } が出たら次は { 7, 8 } しか出せないってやつ。
    SequenceBound = 16,
}

Histroy型は、他のプレイヤーからも見える情報(VisibleInfo型)のリスト。
VisibleInfo は以下のような感じ。

/// <summary>
/// プレイヤーの状態のうち、他のプレイヤーからも見える情報。
/// </summary>
public class VisibleInfo
{
    /// <summary>
    /// プレイヤーの手札の残り枚数。
    /// </summary>
    public int Count { set; get; }

    /// <summary>
    /// プレイヤーが前回出したカード。
    /// </summary>
    public IEnumerable<Card> Previous { set; get; }
}
スクリプトからの出力

出したいカードの一覧を result 変数に格納してください。
IEnumerable にキャストできる型ならなんでもOK(Python の場合、リストとかを使えば OK)。

ライブラリ

とりあえず、今のところ、スクリプトからはSystem.dllとDaifugou.dllだけ参照できる状態。

Daifugou.dll内には、Daifugou.Gameクラスがあって、このクラスの静的メソッドで以下のようなことが可能。

  • IsSameRank: カードが同ランクだけになっているかを判定
  • IsSameSuit: カードが同色だけになっているかを判定
  • IsSequence: カードが同色連番になっているかどうか判定
  • CanPlay: カードを場に出せるかどうかを判定
  • Rank: カードから大富豪的な意味でのランク(3が最弱で2が最強、革命時はその逆)を求める

デフォルトAI

AIスクリプトを登録しなかった場合、以下のような挙動をするデフォルトAIが使われます。

  • 出せる範囲で一番ランクが低いカードを出す
    • 同ランク複数枚、連番にも対応
    • ただ、未実装なので、連番縛り(階段)状態にされると対処できない
  • Jokerも惜しみなく使う
    • Jokerを含めた同ランク複数枚、連番も出してくる
  • 出せるのにあえてパスしたりしない
  • 初手は一番ランクの低いカードを全部出す(3が3枚あるなら、それを3枚とも出す)
    • 連番は出さない

ちなみに、実装はソースファイル中の Daifugou\SampleAI.cs