ゲームに最適なAIを構築する15


8

ゲーム15では、2人のプレイヤーが順番に1から9までの数字を選択します(どちらかのプレイヤーがすでに選択している数字を選択することはありません)。合計が15になる3つの数字を持っている場合、プレイヤーが勝利します。すべての数字が選択されており、いずれかのプレイヤーの合計が最大で15でない場合、ゲームは引き分けです。

あなたの仕事は、15のゲームの状態(好きな形で表されます)を取り、次に移動する番号を返す関数を構築することです。これは、AIとして機能し、別のプレイヤーとゲームをプレイします。あなたはポジションが正当であると仮定するかもしれません(どのプレイヤーも他のプレイヤーよりも多くの数を持っておらず、どのプレイヤーも合計で15になる3つの数をすでに持っていません)。

AIは完璧である必要があります。つまり、勝利のポジションが与えられた場合、AIは強制的に勝利を収める必要があり、負けのないポジション(対戦相手に勝利戦略がないポジション)が与えられた場合、そのAIは対戦相手に敗北ポジションを与える(15は解決済みゲームであるため可能です)。

最短のコードが優先されます。

(注:現在最も短い回答を受け入れ、より短い回答が表示された場合は変更します。)


私たちがAIが得ることができなかった勝てるポジションに入ると、私たちが失うことが許されていることを正しく理解していますか?
John Dvorak

はい、そうです。AIが勝利または引き分けできないゲーム状態(たとえば、ダブルトラップ)を提示された場合、敗北することが許可されます。ただし、AIはゲームが空のボードから上記の敗北状態になることを許可してはなりません。
Joe Z.

AIが常に最初にプレイすることを正しく想定しますか?
John Dvorak

1
うーん…強制的に勝てても引いてもいいようです。本当?
John Dvorak

2
ああ。私はこのゲームについてちょうど学んだ、そして私が家に帰ったとき最初にそれをここに投稿することだった。悲しいかな、私はそれに打ちのめされています。
ブース

回答:


6

GolfScript(129 86 81 85 75文字)

{:C[{.`{1$-\{+15\-}+%}:T+/}/10,1>C~+-:^{.{^T&}+C/,2<*T}/5^{1&}$][]*^&0=}:N;

予期される入力形式:[[int int ...][int int ...]]最初のリストは私の番号で、2番目のリストは対戦相手の番号です。インタラクティブテストの場合~Nは、スクリプトの最後に追加して、その形式の文字列を指定します。例:

$ golfscript.rb 15.gs <<<"[[5][2 8]]"
9
$ golfscript.rb 15.gs <<<"[[2][5 8]]"
6

経験則:

  1. このターンに勝てるなら、やる
  2. 対戦相手が次のターンに勝つ場合、ブロックします
  3. 相手をフォークにできないように正方形に強制できたら、それを行います
  4. 5 4つの方法で勝利に貢献できる唯一の数なので、可能であればそれをつかみます。
  5. オッズよりも偶数を優先

テストフレームワーク:

{:Set;[1 5 9 1 6 8 2 4 9 2 5 8 2 6 7 3 4 8 3 5 7 4 5 6]3/{.Set&=},!!}:isWin;
{
    # Mine His
    .isWin{
        "Lost "@`@`++puts
    }{
        # If there are available moves, it's my move.
        # If I won before my move, I've still won after it.
        1$1$+,9<!!{
            # my move
            1$1$[\\]N 2$\+
            # Mine His Mine'
            .isWin!{
                # his move
                10,1>2$2$+-{
                    2$\+1$\
                    # Mine His Mine' Mine' His'
                    fullTest
                    # Mine His Mine'
                }/
            }*;
        }*;;
    }if
}:fullTest;
# I move first
'[][]fullTest'puts [][]fullTest
# He moves first
'[][1]fullTest'puts [][1]fullTest
'[][2]fullTest'puts [][2]fullTest
'[][5]fullTest'puts [][5]fullTest

この入力を実行できます[5][3]か(4または8を返す必要があります)。
Joe Z.

9-しかし、あなたはルールを変更したようです。
Peter Taylor

また、なぜだけ48
Peter Taylor

ちょっと待って、気にしないで、私は間違っていました。以外はすべて機能する7はず9なので、許容範囲です。
Joe Z.

また、ルールを変更するつもりはありませんでした。初めて私が彼らに間違っていると言っただけです。
Joe Z.

4

Ruby、330 315 341文字

def m i
$_=i.join
l='159258357456168249267348'.scan /(.)(.)(.)/
return 1 if /^5(28|46|64|82)$/
return 4 if /^[258]{3}$/
return 2 if /^[456]{3}$/
i.each{|i|l.map{|l|return l if(l-=i).size==1&&!/[#{l=l[0]}]/}}
.map{|i|l.map{|m|l.map{|l|return (l&m)[0] if(z=l-i|m-i).size==3&&l!=m&&!/[#{z.join}]/}}}
"524681379".chars{|z|return z if !/#{z}/}
end

今のところ詳細は差し控えておきますが、これは同様に解決された同様の問題に対する最適なアルゴリズムに基づいており、その最適なアルゴリズムがたまたまここでも同じようにうまく機能するとします。 仮定が行われました-これは、このアルゴリズムが他のプレイヤーと対戦することによって生成できない状況で、2人のプレイヤーが互いに対戦するだけで、悪い動きを選択します。

入力:1桁の文字列の2つの配列の配列。各配列は、1人のプレーヤーが取った値を表します。最初の配列はAI、2番目の配列は対戦相手です。

出力:数値または1桁の文字列。それらは意味的に同等です。文字列への正規化には8文字かかります。

発信者から与えられた数字の順序を仮定すると、さらに3つのキャラクターを保存できます。L5の正規表現を、ゲームから生成された順序に、/^285$/または/^258$/ゲームに応じて変更し(opponent)5-(ai)2-(opponent)8ます。


5優先注文の先頭に移動するだけで、最後の3行を簡単に節約できるようです。
Peter Taylor

@ah、はい、ありがとう。その間に別のステップがあり、削除しました(特殊なケースの場合)と、周囲のステップをマージするのを忘れていました。家に帰ったら編集します(以前にボランティアをしていない限り)。
John Dvorak

1

GolfScript(90 85 84文字)

{.~.,3/*..2%.@^++3*3/{~++15=},,*10,1>2$~+-@`{([2$+]+v[0=~)\]}+%[1,]or$0=+}:v{1=}+:N;

これは完全に異なるアプローチを取りますが、ヒューリスティックなアプローチを打ち負かすための最適化の影響を受ける可能性があります。ここでは、完全にゲームツリーの分析を非常にゆっくりと実行します。(いいえ、つまり、主に現在の状態を次の移動ループに追加するため、完全なテストの実行には数時間かかり`{...}+ます)。難しいのは、勝った状態(現在のコードの3分の1)を識別することです。

非再帰セクションには、いくつかの醜いハックがあります。特に、ポジションが負けポジションとして識別された場合、そのポジションを[value move]配列とみなし、移動は無関係で値はゼロ以外であることを前提としています。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.