次の動きは?


18

この課題は、書くことですミニマックス関数の出力に、お好みの言語での次の最善手のNxNのゲーム三目並べ与えられた現在のボードの状態を。ボード入力は、Matrix、2D Collection、またはユーザーにとって理にかなっているものの、ルールを順守するものとして受け入れることができます。出力はされて次善の動きのためのは、それが現在で回す誰でもXが起動していると考えられています

Minimaxアルゴリズムの簡単な背景

ミニマックスアルゴリズムの基本的な考え方は、考えられるすべての結果をDAGとして列挙し、最初の動きによってキー付けされた一連の動きがプレーヤーに与える利益によってそれらを重み付けすることです。可能なすべての結果は、最初の動きによって「バケット化」され、すべての結果の合計に基づいてスコアリングされます(損失の場合は-1、同点の場合は0、勝利の場合は1)。複数のプレイヤーがプレイする必要がある実装では、プレイヤーによるすべての可能な動きと、対戦者によるすべての可能な反応も列挙します。たとえば、三目並べのゲーム(最初の動きの後)では、8つの可能な最初の動きがあり、次のターンだけを分析するときはすべて同じように見えるかもしれません。しかし、最終的な結果をもたらす可能性のある一連の動きごとに考えられるすべての結果を反復処理し、それらをすべて合計することにより、

tic-tac-toeの観点から見たmini-maxアルゴリズムのより詳細で詳細なコンテキストの概要については、http//neverstopbuilding.com/minimaxを参照してください。

XKCD(3x3ソリューションのみ)

三目並べの3x3ゲームで可能なすべての動き。

ルール

  • 任意の言語を使用できますが、外部ミニマックスライブラリは許可されていません。
  • 出力は、次の最適な動きを示す座標(0-n、0-n)または数値(1-n * n)にすることができます。
    • これに加えて、ベストケースシナリオが勝利ではなく損失または同点である場合を特定できる必要があります。
    • あなたが損失や同点を示す方法は、あなた次第です。
  • 入力は従来のXとOを使用する必要があり、Xが最初に移動すると想定する必要があります。空白は何でも表すことができます。
  • プログラムに入力される入力には、n個のOとn + 1個のXがあると仮定できます。言い換えると、整形式のボードを取得していると仮定できます。
  • ボードの現在の状態がプログラムへの唯一の入力である必要があります。再帰を使用している場合、入力要件を容易にするためにヘルパーメソッドを作成する必要があります。詳細については、https://codegolf.stackexchange.com/a/92851/59376を参照してください
  • 10> = n> = 1の値をサポートする必要があります。プログラムがn> 10で「タイムアウト」になった場合、一部の言語の処理能力が大幅に低いため(特にWebに面したコンソールを使用しているため)、これも受け入れられます。

審査

  • これはコードゴルフであるため、プログラムの最小バイト数が優先され、標準的な抜け穴は一般的に許可されません。
  • 同点の場合、最大の「n」をサポートするプログラムが勝ちます。

入力例

2x2

[[X,O]
 [-,-]]

出力: 2または[0,1](3または[1,1]も間違いなく正しいでしょう)(使用した形式を簡単に説明できる限り、場所の表示の任意の形式)


3x3

[[X,O,X]
 [O,X,-]
 [-,-,-]]

出力: -1(損失)


繰り返しますが、必要な入力形式はすべて許可されますが、XとOを使用する必要があります。提供される例は、単にその形式に制約することを意図したものではなく、単に刺激を与えるためのものです。


DJMCMayhemさん、ごめんなさい。実際にそれらのタグを付けようとしましたが、ここにいるので、できませんでした。
魔法のタコUr

ボーナスも削除され、退屈だけが追加されました。
魔法のタコUr

次の出力形式が許可されていますか。ボードの位置の図に、元々空いているスペースにユニークなキャラクターがあり、そこでプレイすると勝ち負け/引き分けになるかどうかを示します(例:W、L、D)
Ton Hospel

1
3x3の例では、Oが何をプレイしても負けるはずですが、出力は[2,1]であると言いますが、それはなぜですか?
ダダ

編集済み、良いキャッチ。私が何を考えていたかわからない、それは否定的な例でした。
魔法のタコUr

回答:


8

Perl、101 98バイト

含み+4のために-0p

STDINの入力で実行する

tictactoe.pl
OXO
---
--X
^D

出力は同じ図ですが、各動きがステータスで更新され1、勝ち、2引き分け3、負けを表します。この場合、それは

OXO
223
21X

したがって、3移動ドロー、1勝、1負(この出力形式が受け入れられない場合はソリューションを更新しますが、基本的なコードは同じままです)

tictactoe.pl

#!/usr/bin/perl -0p
m%@{[map"O.{$_}"x"@-"."O|",1-/.(
)(.)/,@-]}Z%sx||s%-%$_="$`X$'";y/XO/OX/;do$0%eg?/1/?3:1+/2/:2

これはすでに非常に遅く、空の3 * 3ボード用に大量のメモリを使用します(実際には、再帰がそれほど深くならないので、メモリリークが必要です)。メモ化の追加には6バイトかかりますが、非常に便利です。

#!/usr/bin/perl -0p
$$_||=m%@{[map"O.{$_}"x"@-"."O|",1-/.(\n)(.)/,@-]}Z%sx||s%-%$_="$`X$'";y/XO/OX/;do$0%eg?/1/?3:1+/2/:2

うわー、それはplであり、n = 10で多くの空の場合は絶対に実行されない可能性が高いことを見落としています... 文字列の入力と、最高の動きだけでなく、すべての動きの結果のマッピング。ブラボー。
魔法のタコUr

1つの再帰関数が「リーク」する場合はどうすればいいですか?言語が高すぎると、CPUに32ビットレジスタが表示されません(または単純な命令のようなもの)
-RosLuP

このコンテキストでの@RosLup Leakは、必ずしも到達不能なメモリ損失を意味するわけではありません。Perlはメモリを解放する際にかなり独特であり、非常に多くの場合、これは予想よりも遅く実行されるため、予想よりもはるかに多くのメモリを使用します。また、データ構造を成長させることを期待して、直接必要以上に割り当てる傾向があります。この場合、乱用する代わりに関数で「通常の」再帰をdo$0使用すると、使用するメモリが10倍少なくなります。気を付けてください、このケースは非常に極端であるため、実際のメモリリークの可能性があります。
トンホスペル16

レジスタまたは基本命令(hlls命令から)が表示されないだけでなく、メモリ使用の制御が失われます...私にとってはスケーリングできません
...-RosLuP

それは十分な長さです、あなたは私の男を獲得します、しかし悲しいことに我々はそれ以上の試みを得なかった。
魔法のタコUr

2

Javascript(ES6)、320 294バイト

(b,p,d,M,S=-2)=>(T=(p,q,r,s)=>b[p][q]==(n=b[r][s|0])&&n!='-',w=0,b.map((r,y)=>(l=r.length-1,m=15,r.map((c,x)=>(m&=8*T(l-x,x,l)+4*T(x,x,0)+2*T(x,y,0,y)+T(y,x,y))),w|=m)),w?-1:(b.map((r,y)=>r.map((c,x)=>S<1&&c=='-'&&(r[x]='O.X'[p+1],(s=-f(b,-p,1))>S&&(S=s,M=[x,y]),r[x]=c))),S=S+2?S:0,d?S:[M,S]))

入力

1)次のような、現在のボードを説明する文字の配列の配列

[['X', '-'], ['-', 'O']]

2)現在のターンを表す整数:1 = X、-1 =O

出力

以下で構成される配列:

  • [x, y]形式での最適な移動を記述する配列
  • 整数としてのゲームの結果:1 =勝ち、-1 =負け、0 =引き分け

次の例でXは、をプレイすることで勝つことが保証されてい[1, 2]ます。

let f =
(b,p,d,M,S=-2)=>(T=(p,q,r,s)=>b[p][q]==(n=b[r][s|0])&&n!='-',w=0,b.map((r,y)=>(l=r.length-1,m=15,r.map((c,x)=>(m&=8*T(l-x,x,l)+4*T(x,x,0)+2*T(x,y,0,y)+T(y,x,y))),w|=m)),w?-1:(b.map((r,y)=>r.map((c,x)=>S<1&&c=='-'&&(r[x]='O.X'[p+1],(s=-f(b,-p,1))>S&&(S=s,M=[x,y]),r[x]=c))),S=S+2?S:0,d?S:[M,S]))

console.log(JSON.stringify(f(
  [['O','X','O'],
   ['-','-','-'],
   ['-','-','X']],
  1
)));

素晴らしいゲーム。勝つ唯一のムーブはプレイではありません。
ナイスゲームオブチェスについて


よくやった、良い最初のエントリー。「Xが常に最初に移動する」という指定された情報でバイトを節約できる可能性があるのは、私だけです。そして、あなたは非3x3ボードで試してみました;)?
魔法のタコUr

@carusocomputing-「Xは常に最初に移動する」ということを念頭に置いて理解していることは確かではありません。ボードだけを考えると、どちら側が動いているかを推測するために使用できますが、実際に計算するとより多くのバイトが必要になります。あなたは何か他のことを話していると思います。はい、少し大きめのボードでテストを行いました。... err ...空の位置が多すぎない限り、期待どおりに動作するはずです。:
アーナルド

挑戦は言いThe current state of the board must be the only input to your programます。コードには2つの入力が必要であり、この規則に違反します。
ダダ

1
@Dada-私はそれについて疑問に思っていましたが、アクティブな色ボードの状態の一部であると仮定しました (チェスの位置には常にアクティブな色+パッサンスクエア+キャスティングの可用性が付属するように)。だから私はOPがその点を明確にする必要があると思います。(そして、あなたが正しいなら、それは不必要な追加の難しさのように聞こえます、私見。)
アーナルド

1
うーん、私は彼の応答でボードの状態の説明が本当に好きです。それを考えると、一部のラネーグは入力として文字列のみを使用する場合があり、XXOOXO-OOのようなボードを持つと、ボードの寸法などの追加情報なしで低バイト数で解読するのが困難になります。ボードの状態に寄与する追加の入力は許可しますが、「Xが最初に移動すると仮定する」という情報は「誰がターンするかを与える」とは異なると今でも考えています。一部の言語では、これを前提として利用します;)。
魔法のタコUr
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.