Three Men's Morrisでさらに2つの動きで勝つことができますか?


16

報奨金

No. 1(授与

最初の有効な回答には50人の担当者を投入します

No. 2(授与

最短の有効な回答を得るために、さらに100人の担当者を投入します。

No. 3(提出用にオープン

有効な回答が大幅に短くなった最初の回答には200人の担当者を投入します。重要なのは、現在の最短回答の最大45%(564バイトx 0.45 = 最大254バイト)です。


ゲーム

古典的なゲーム「Nine Men's Morris」または単に「Mill」を覚えていますか?Three Men's Morrisと呼ばれるバリエーションがあり、これは変更可能な三目並べのようなものです。

ルール

これはゲームのブランクボードです。

   a   b   c
1 [ ]–[ ]–[ ]
   | \ | / |
2 [ ]–[ ]–[ ]
   | / | \ |
3 [ ]–[ ]–[ ]

[ ]はフィールドであり|–/\、それらのフィールド間のルートを表します。

ゲームは2人のプレーヤーで再生される1と、2誰が各場所3は、ボード上のトークン。これは実際にすでに起こり、私たちはゲームに参加しています。1人のプレイヤーがmill、プレイヤーの3つのトークンの縦または横の列を形成できる場合、ゲームに勝ちます。

このルールに従って、トークンは接続線に沿ってボード上で移動できます。

隣接する空の位置へ(つまり、エッジ位置から中心へ、または中心からエッジ位置へ、またはエッジ位置から隣接エッジ位置へ)

プレーヤーは、隣接する空の位置がない限り移動する必要があります。空の位置がない場合、移動はスキップされます。

チャレンジ

あなたはプレイヤーで1あり、あなたの動きは次です。次のことを決定するプログラムまたは関数を作成します。

  • あなたは2回以下の動きで勝利を強制することができます(明確な勝利
  • 対戦相手がミスを犯した場合は、2手以内で勝つことができます(勝てる可能性があります)
  • あなたはより多くの移動が必要になりますので、2回の以下の移動で勝つことができないか、強制移動が勝つために相手を導くため(不可能勝つために

必要条件

  • 対戦相手を死に至らしめたとき、あなたは間違いなく勝ちますが、プログラムは有限の時間で終了しなければなりません。
  • プログラムまたは関数を作成できます。

入力

プレイヤーはで表され1、および20自由フィールドを定義します。入力を行列または配列として受け取ることができます。

明確

A         B         C         D
2 1 0  |  2 1 0  |  1 0 1  |  1 2 2
2 1 2  |  0 1 0  |  1 0 2  |  2 1 O
0 0 1  |  2 2 1  |  0 2 2  |  O O 1

A: [2,1,0,2,1,2,0,0,1]
B: [2,1,0,0,1,0,2,2,1]
C: [1,0,1,1,0,2,0,2,2]
D: [1,2,2,2,1,0,0,0,1]

可能

A         B         C
1 0 1  |  1 0 1  |  1 2 2
1 2 2  |  1 2 0  |  0 0 1
2 0 0  |  2 0 2  |  2 1 0

A: [1,0,1,1,2,2,2,0,0]
B: [1,0,1,1,2,0,2,0,2]
C: [1,2,2,0,0,1,2,1,0]

不可能な

A         B    
1 0 0  |  1 2 0
1 2 2  |  2 1 0
2 0 1  |  1 2 0

A: [1,0,0,1,2,2,2,0,1]
B: [1,2,0,2,1,0,1,2,0]

出力

あなたのプログラムはスマイリーを出力/返すはずです:

  • 明確な勝利: :)
  • 可能な勝利: :|
  • 勝てない: :(

2つの動きで明確な勝利:

[2][1][ ] 1. [2][1][ ]
[2][1][2] -> [2][1][2]
[ ][ ][1]    [ ][1][ ]

[2][1][ ] 1. [2][1][ ]    [ ][1][ ] 2. [ ][ ][1]
[ ][1][ ] -> [ ][ ][1] -> [2][ ][1] -> [2][ ][1]
[2][2][1]    [2][2][1]    [2][2][1]    [2][2][1]

[1][ ][1] 1. [ ][1][1]    [ ][1][1] 2. [1][1][1]
[1][ ][2] -> [1][ ][2] -> [1][ ][2] -> [ ][ ][2]
[ ][2][2]    [ ][2][2]    [2][ ][2]    [2][ ][2]

2つの動きで勝つ可能性:

[1][ ][1] 1. [ ][1][1]    [ ][1][1] 2. [1][1][1]
[1][2][ ] -> [1][2][ ] -> [1][2][2] -> [ ][2][2]
[2][ ][2]    [2][ ][2]    [2][ ][ ]    [2][ ][ ]

[1][ ][1] 1. [ ][1][1]    [ ][1][1] 2. [1][1][1]
[1][2][ ] -> [1][2][ ] -> [1][2][2] -> [ ][2][2]
[2][ ][2]    [2][ ][2]    [2][ ][ ]    [2][ ][ ]

[1][2][2] 1. [ ][2][2]    [2][ ][2] 2. [1][2][2]
[ ][ ][1] -> [1][ ][1] -> [1][ ][1] -> [1][1][1]
[2][1][ ]    [2][1][ ]    [2][1][ ]    [2][ ][ ]

2つの動きで勝つことは不可能です。

[1][ ][ ]
[1][2][2]
[2][ ][1]

ボーナス

明確な勝ちが可能で、プログラムがa1:a2(1移動)またはa1:a2,a3:b2(2移動)のように成功への一方通行の動きを出力する場合、バイトカウントの30%を引き出すことができます。


これはコードゴルフです。バイト単位の最短回答が勝ちです。標準の抜け穴は許可されていません。


Sandboxのいくつかの欠陥を修正し、文言を改善してくれたPeter Taylorに感謝します。



1
私はそれらのアスキーテーブル/グラフィックが好き=)
flawr

1
プレーヤーが移動できない場合はどうなりますか?たとえば、[1,0,0,2,1,0,2,2,1]では、プレーヤー2は移動できません-これはプレーヤー1の勝利ですか?
VisualMelon

1
@LeifWillerts私はあなたの言うことを誤解しているかもしれませんが、その場合、勝者の状態にあるプレーヤーはいません-彼らは水平線または垂直線(対角線ではない)を持つことによってのみ勝ちます。
VisualMelon

3
まあ、有効なボード位置は1680だけなので、ハードコーディングで210バイトを少し超えることがあります。(対称性が考慮されている場合は少ない)
リトシアスト

回答:


1

Haskell、580 564 441バイト

これは今のところゴルフできる範囲です。他の言語がそれを打ち負かすことができるかどうか不明。

(Definite A)のmようなリストのリストを呼び出します[[2,1,0],[2,1,2],[0,0,1]]

import Data.Array
r=[0..2]
p?f=[(x,y)|x<-r,y<-r,f!y!x==p]
p%f=all(==x)xs||all(==y)ys where(x:xs,y:ys)=unzip$p?f
s p x y f=f//[(y,f!y//[(x,p)])]
p#f=[s 0 x y$s p u v f|a@(x,y)<-p?f,b@(u,v)<-0?f,((x-u)*(y-v)==0&&abs(x+y-u-v)==1)||elem(1,1)[a,b]]
p&f|p#f>[]=p#f|0<1=[f]
e=any
i a p f=e(a$e(p%))(map(map(p&))(map((3-p)&)$p&f))||e(p%)(p&f)
l=listArray(0,2)
f(True,_)=":)"
f(False,True)=":|"
f _=":("
m=putStrLn.f.(\f->(i all 1 f,i e 1 f)).l.map l

テストコード:

da = [[2,1,0],[2,1,2],[0,0,1]]
db = [[2,1,0],[0,1,0],[2,2,1]]
dc = [[1,0,1],[1,0,2],[0,2,2]]
dd = [[1,2,2],[2,1,0],[0,0,1]]
pa = [[1,0,1],[1,2,2],[2,0,0]]
pb = [[1,0,1],[1,2,0],[2,0,2]]
pc = [[1,2,2],[0,0,1],[2,1,0]]
ia = [[1,0,0],[1,2,2],[2,0,1]]
ib = [[1,2,0],[2,1,0],[1,2,0]]
al = [da,db,dc,dd,pa,pb,pc,ia,ib]

mapM_ m al 戻り値:

:)
:)
:)
:)
:|
:|
:|
:(
:(

1
修正したと思う。(ここでは、猶予期間が終了する前にある)夕方にdoublecheckかつ適切ゴルフう
レイフ・Willerts

5

C#-739 663バイト

完全なプログラムで、argvから入力を読み取り、動作しているように見えます。のように実行します

ThreeMill 1 2 1 1 2 0 0 0 2

この入力方法が受け入れられない場合は、喜んで変更します(argvの使用とは異なります)。

using System;using System.Linq;class P{static void Main(string[]A){var I=new[]{0,3,6,1,4,7,2,5,8};Func<string[],string>J=S=>S[0]+S[1]+S[2]+" "+S[3]+S[4]+S[5]+" "+S[6]+S[7]+S[8]+" ";Func<string[],string,int>W=(B,p)=>(J(B)+J(I.Select(i=>B[i]).ToArray())).Contains(p+p+p)?1:0;Func<string[],string,string[][]>V=(B,p)=>I.SelectMany(a=>I.Where(b=>a!=b&B[a]==p&B[b]=="0"&(a==4|b==4|a-b==3|b-a==3|((a-b==1|b-a==1)&a/3==b/3))).Select(b=>{var N=(string[])B.Clone();N[b]=p;N[a]="0";return N;})).DefaultIfEmpty(B).ToArray();int h,G;Console.WriteLine(":"+"(|))"[V(A,"1").Max(z=>((h=0)<(G=V(z,"2").Sum(j=>V(j,"1").Max(q=>W(q,"1")-W(q,"2"))+h++*0))?1:0)+(h>G?W(z,"1")*2:2))]);}}

私は昨日、これをあまり投稿できなかったので、あまりゴルフをすることができなかったので(あまり時間がなかったので、練習ができなかったかもしれません)、まだ返答がなかったので、とにかくそれを投稿します、私は確かに賞金を期待していません、私はむしろ投稿する前に彼らのことにもう少し努力をした誰かに行きたいです!

編集:すべてのブール値をintに置き換えました。これは、Linqをより有効に活用できることを意味し、両方のforeachループを折りたたんで、大幅に節約できました。hカウンターが機能することに少し驚いています... ++はそのような微妙なユーティリティです。

このプログラムは非常にシンプルで、考えられるすべての動きを探索するだけです(string []にボードの状態を保存します)。可能なすべての動き(その結果のボード)を反復処理し、ビート(G)を成功させることができる対戦相手の応答数(つまり、勝ったが彼がしない)をカウントします。また、考えられる応答の数もカウントします(h)。私たちが勝つことができれば、それは可能です。合計に1を加えます。すべて勝つことができれば、それは明確であり、合計に2を加えます。したがって、最大のsomeは可能な限り最良の結果であり、文字列「(|))」にインデックスを付けて適切な顔を返します。明確な場合は合計が2または3になる可能性があるため、追加の ")"が必要であることに注意してください(すでに最初に勝ち取った応答に勝つことができないように見える可能性があるため、可能なチェックは少し誤解を招く)。

プログラムは、ボードから文字列、つまりスペースで区切られた行と列を生成することによって勝利をチェックし、この文字列でプレイヤーのキャラクターの3つの文字列を探します(例:「201 201 021 220 002 111」は私たちのために勝ちます)

using System;
using System.Linq; // all important

class P
{
    static void Main(string[]A) // transform to int?
    {
        var I=new[]{0,3,6,1,4,7,2,5,8}; // vertical indexes
        Func<string[],string>J=S=>S[0]+S[1]+S[2]+" "+S[3]+S[4]+S[5]+" "+S[6]+S[7]+S[8]+" "; // joins the strings up, so that there is a space separating each group of three (including at end)
        Func<string[],string,int>W=(B,p)=>(J(B)+J(I.Select(i=>B[i]).ToArray())).Contains(p+p+p)?1:0; // checks if a particular player wins
        Func<string[],string,string[][]>V=(B,p)=>I.SelectMany(a=>I // for each imagineable move
            .Where(b=>a!=b&B[a]==p&B[b]=="0"&(a==4|b==4|a-b==3|b-a==3|((a-b==1|b-a==1)&a/3==b/3))) // where it's legal
            .Select(b=>{var N=(string[])B.Clone();N[b]=p;N[a]="0";return N;}) // select the resulting board
        ).DefaultIfEmpty(B) // allow not-moving
        .ToArray();

        int h, // h stores the number of responses the opponent has to each move
        G; // G stores the number of responses by the opponent we can beat

        Console.WriteLine(":"+"(|))"[ // we index into this to decide which smiley
            V(A,"1").Max(z=>
                    ((h=0)<(G=V(z,"2").Sum(j=>V(j,"1").Max(q=>W(q,"1")-W(q,"2"))+h++*0))?1:0) // if there is atleast 1 reponse by the opponent we can beat, we can possibly win
                    +(h>G?W(z,"1")*2:2) // if there are moves which we can't win, then if we have already won (one-move), else, we can definitely win
                   ) // sum is therefore 0 if impossible, 1 if possible, >2 (no more than 3) if definite 
            ]);

    }
}

これが私のテストスクリプトです。

ThreeMill 2 1 0 2 1 2 0 0 1
ThreeMill 2 1 0 0 1 0 2 2 1
ThreeMill 1 0 1 1 0 2 0 2 2
ThreeMill 1 2 2 2 1 0 0 0 1

ThreeMill 1 0 1 1 2 2 2 0 0
ThreeMill 1 0 1 1 2 0 2 0 2
ThreeMill 1 2 2 0 0 1 2 1 0

ThreeMill 1 0 0 1 2 2 2 0 1
ThreeMill 1 2 1 1 2 0 0 0 2
ThreeMill 1 0 1 2 0 2 1 0 2

どの出力

:)
:)
:)
:)
:|
:|
:|
:(
:|
:)

いいね 最初になってくれてありがとう。:)大丈夫なら、私は週末の後に賞金を授与し、機能タブでさらに数日間それを維持します。
insertusernamehere

@insertusernamehereそれでいいのです。本当の仕事をするのが面倒なら、明日はもっと仕事をするかもしれません。
VisualMelon

1
これは、このコメントを思い出させます。「40分間の質問に答えることができませんでした。これは非常に重要です。データベースの詳細を送信するだけで、回答をSQLに挿入します。回避するために!!スタックオーバーフローが機能しないのはなぜですか?。:)
ここにユーザー名を挿入します

1

PowerShell 576 550バイト

631バイト未満のC#を取得できない場合、代わりに別の言語を使用する必要があります。PowerShellをあまり好きではないと判断したので、Leif Willertsが答えから5バイトをノックすることを望んでいます。

これはスクリプトです. .\mill.ps1 "201102021"。あなたはそれを実行します。これは、C#の回答のコピーであり、経験の少ない言語でのみ使用できます。私はこれをゴルフするためにあまり努力しませんでした。なぜなら、それは最初のインスタンスで仕事をするのに非常に長い時間がかかり、すでにかなりコンパクトだからです。

編集:[Math]::Floorそこにそれらの呼び出しを残すことができませんでした

param($U);$I=0,3,6,1,4,7,2,5,8;function J($S){($S[0..2]+" "+$S[3..5]+" "+$S[6..8]-join"").Contains($p*3)}function W($D,$p){(J $D)-or(J $D[$I])}function V($Q,$C){$I|%{$a=$_;$I|?{$a-ne$_-and$Q[$a]-eq$c-and$Q[$_]-eq"0"-and($a-eq4-or$_-eq4-or$a-$_-eq3-or$_-$a-eq3-or(($a-$_-eq1-or$_-$a-eq1)-and$a/3-$a%3/3-eq$_/3-$_%3/3))}|%{$b=$Q[0..8];$b[$_]=$c;$b[$a]=0;$b-join''}}|%{$n=1}{$n=0;$_}{if($n){$Q}}}$e=$f=0;V $U "1"|%{$h=0;$x=$_;V $x "2"|%{$k=0;(V $_ "1"|%{if((W $_ "1")-and!(W $_ "2")){$k=$e=1}});$h+=1-$k};if($h-eq0-or(W $x "1")){$f=2}};":"+"(|))"[$e+$f]

どのように機能するかの説明があれば... C#の答えはあなたのためですが、うまくいけばコメントがそれを十分に明確にすることを願っています。セミコロンは単一行のコマンドと完全に一致しない場合があります。それらが必要な場所とそうでない場所はまだわかりません。

param($U); # take input as argument

$I=0,3,6,1,4,7,2,5,8; # cols

function J($S){ # checks if this is a winning string
($S[0..2]+" "+$S[3..5]+" "+$S[6..8]-join"").Contains($p*3)}

function W($D,$p){ # checks if this is a winning board
(J $D)-or(J $D[$I])} # $D[$I] reorganises into columns

function V($Q,$C){ # yields all valid moves from position $Q for player $C
$I|%{$a=$_;$I| # for each possible move
?{$a-ne$_-and$Q[$a]-eq$c-and$Q[$_]-eq"0"-and($a-eq4-or$_-eq4-or$a-$_-eq3-or$_-$a-eq3-or(($a-$_-eq1-or$_-$a-eq1)-and$a/3-$a%3/3-eq$_/3-$_%3/3))}| # where legal
%{$b=$Q[0..8];$b[$_]=$c;$b[$a]=0;$b-join''}}| # make the move (copy $Q to an array, modify, join into a string)
%{$n=1}{$n=0;$_}{if($n){$Q}}} # if empty, return $Q - I am confident this can be achieved with commas, and [0], and maybe a +, but I don't want to think about it

$e=$f=0; # possible, definite

V $U "1"|%{ # for all our possible moves
$h=0;$x=$_; # $k is whether we win all of these
  V $x "2"| # for all opponent's responses
  %{$k=0;(V $_ "1"| # for all our responses
  %{if((W $_ "1")-and!(W $_ "2")){$k=$e=1}});$h+=1-$k}; # if we can win and he can't, then things are looking good, set $e to 1 (possible win)

  if($h-eq0-or(W $x "1")){$f=2} # if we win every move, or we have already won, it's a definite
};

":"+"(|))"[$e+$f] # smile, it's all over

テストスクリプト(PowerShell):

. .\mill.ps1 "210212001"
. .\mill.ps1 "210010221"
. .\mill.ps1 "101102022"
. .\mill.ps1 "122210001"

. .\mill.ps1 "101122200"
. .\mill.ps1 "101120202"
. .\mill.ps1 "122001210"

. .\mill.ps1 "100122201"
. .\mill.ps1 "121120002"
. .\mill.ps1 "101202102"

. .\mill.ps1 "100122201"
. .\mill.ps1 "120210120"

その出力:

:)
:)
:)
:)
:|
:|
:|
:(
:|
:)
:(
:(

1

Python 3、566 557バイト

さらにゴルフができるかどうか、または30%のボーナスを得ることができるかどうかを確認する必要がありますが、多くの先延ばしの後、ここに私の答えがあります。

def t(g,x=1,r=0,z=0):
 m=[[1,3,4],[0,2,4],[2,4,5],[0,4,6],[0,1,2,3,5,6,7,8],[2,4,8],[3,4,7],[4,6,8],[4,5,7]];a=[[0,1,2],[3,4,5],[6,7,8],[0,3,6],[1,4,7],[2,5,8],[0,4,8],[2,4,6]];z=z or[[],[],[],[]];s=0
 if r>3:return z
 for i in a:
  if g[i[0]]==g[i[1]]==g[i[2]]>0:s=g[i[0]];break
 z[r]+=s,
 for q in range(9):
  i=g[q]
  if i==x:
   for p in m[q]:
    if g[p]<1:n=g[:];n[q],n[p]=n[p],n[q];z=t(n,3-x,r+1,z)
 if r:return z
 else:
  w=l=0
  for j in range(4):w=w or 1in z[j];l=l or 2in z[j]
  if l<1and w:return":)"
  elif w<1and l:return":("
  else:return":|"

ゴルフをしていない:

def three_mens_morris(grid, player=1, rec=0, w_l=0, p=0):
    moves = [[1,3,4],[0,2,4],[2,4,5],[0,4,6],[0,1,2,3,5,6,7,8],[2,4,8],[3,4,7],[4,6,8],[4,5,7]]
    w_l = w_l or [[],[],[],[]]
    if rec == 4: return w_l
    result = check_grid(grid)
    w_l[rec].append(result)
    for sq_1 in range(len(grid)):
        piece = grid[sq_1]
        if piece == player:
            for sq_2 in moves[sq_1]:
                if grid[sq_2] == 0:
                    new_grid = grid.copy()
                    new_grid[sq_1],new_grid[sq_2]=new_grid[sq_2],new_grid[sq_1]
                    w_l = three_mens_morris(new_grid,3-player,rec+1,w_l)
    if p: print(w_l)
    if rec:
        return w_l
    else:
        win = loss = 0
        for i in range(4):
            if 1 in w_l[i]:
                win = 1
            elif 2 in w_l[i]:
                loss = 1
        if p:print(win,loss)
        if loss==0 and win:
            return ":)"
        elif loss and win==0:
            return ":("
        else:
            return ":|"

def check_grid(grid):
    rows = [[0,1,2],[3,4,5],[6,7,8],[0,3,6],[1,4,7],[2,5,8],[0,4,8],[2,4,6]]
    for i in rows:
        if grid[i[0]]==grid[i[1]]==grid[i[2]] and grid[i[0]]:
            return grid[i[0]]
    return 0
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.