Three Men 's Morris에서 두 번 더 이길 수 있습니까?


16

바운티

1 위 ( 수상 )

첫 번째 유효한 답변에 50 명의 담당자를 던질 것입니다.

2 위 ( 수상 )

가장 짧은 유효한 답변에 대해 다른 100 명의 담당자를 처리합니다.

No. 3 ( 투고 가능 )

유효 답변이 훨씬 짧은 첫 번째 담당자는 200 명을 처리합니다. 현재 가장 짧은 답변의 최대 45 % ( 564 바이트 x 0.45 = 최대 254 바이트 ) 가 중요 합니다.


게임

당신은 고전 게임 " 나인 멘스 모리스 "또는 단순히 " "을 기억하십니까? 변형 가능한 틱택 토와 비슷한 Three Men 's Morris 라는 변형이 있습니다 .

규칙

이것은 게임의 빈 보드입니다.

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

[ ]필드이며 |–/\해당 필드 사이의 경로를 나타냅니다.

이 게임은 두 선수에 의해 연주 12보드에 각 장소를 누가 3 토큰을. 이것은 실제로 이미 일어 났고 우리는 게임에 있습니다. 한 플레이어가 mill플레이어의 3 개 토큰의 세로 또는 가로 행인 a 를 형성 할 수 있으면 게임에서 승리합니다 .

이 규칙에 따라 토큰을 연결선을 따라 보드에서 이동할 수 있습니다.

인접한 빈 위치 (즉, 모서리 위치에서 중심으로 또는 중심에서 모서리 위치로 또는 모서리 위치에서 인접 모서리 위치로)

인접한 빈 위치가 없으면 플레이어는 이동을 건너 뛰어야합니다.이 경우 이동을 건너 뜁니다.

도전

당신은 선수 1이고 당신의 움직임은 다음입니다. 다음을 결정하는 프로그램 또는 함수를 작성하십시오.

  • 당신은 2 이하의 움직임으로 승리를 강요 할 수 있습니다 ( 확실한 승리 )
  • 상대방이 실수를하면 2 번 이하로 이길 수 있습니다 (승리 가능 )
  • 당신은 당신이 더 이동해야하기 때문에, 2 이하 움직임에 이길 수 없다 또는 강제 이동이 이길 상대를 리드하기 때문에 ( 불가능 승리 )

요구 사항

  • 상대방을 죽일 때 확실히이기는 경우에도 프로그램은 유한 한 시간 안에 완료되어야합니다.
  • 프로그램이나 함수를 작성할 수 있습니다.

입력

선수들은으로 표시됩니다 12. 0자유 필드를 정의합니다. 입력을 행렬 또는 배열로 취할 수 있습니다.

명확한

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][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]

두 가지 움직임으로 가능한 승리 :

[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][ ][ ]

두 가지 움직임으로 이길 수 없습니다.

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

보너스

확실한 승리가 가능하고 프로그램이 a1:a2(1 이동) 또는 a1:a2,a3:b2(2 이동) 과 같이 성공의 한 가지 방법으로 이동을 출력하는 경우 바이트 수의 30 % 를 철회 할 수 있습니다 .


이것은 코드 골프입니다 – 바이트 단위의 최단 답변이 이깁니다. 표준 허점은 허용되지 않습니다.


샌드 박스의 결함을 수정하고 표현을 개선 한 Peter Taylor 에게 감사합니다 .



1
나는 그 ascii 테이블 / 그래픽을 좋아한다 =)
flawr

1
플레이어가 움직일 수 없으면 어떻게됩니까? 예를 들어 [1,0,0,2,1,0,2,2,1], 2 번 선수는 움직일 수 없습니다-1 번 선수의 승리입니까?
VisualMelon

1
@LeifWillerts 나는 당신이 의미하는 바를 이해하지 못할 수도 있지만,이 경우 어떤 선수도 승리 상태가 아닙니다.
VisualMelon

3
글쎄, 유효한 보드 위치는 1680 개뿐이므로 하드 코딩은 210 바이트를 약간 넘을 수 있습니다. (대칭이 고려되는 경우 더 적음)
lirtosiast December

답변:


1

하스켈, 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
맞습니다. 저녁에 재확인하고 제대로 골프를칩니다 (여기에서 유예 기간이 끝나기 전에)
Leif 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))]);}}

어제 골프를 할 수 없었기 때문에 (이 시간이 많이 걸리지 않았고 연습이 어려울 수 있기 때문에) 어제 게시를 거부했습니다. 그러나 아직 응답이 없었기 때문에 어쨌든 게시하겠습니다. 나는 현상금을 기대하지 않습니다. 오히려 게시하기 전에 조금 더 노력을 기울인 사람에게갔습니다!

편집 : 모든 부울을 정수로 대체하여 Linq를 더 잘 사용할 수 있었고 두 foreach 루프를 모두 축소하여 크게 절약했습니다. h카운터가 작동 한다는 것에 약간 놀랐습니다 ... ++는 미묘한 유틸리티입니다.

이 프로그램은 매우 간단합니다. 가능한 모든 이동 세트를 탐색합니다 (보드 상태를 문자열 []로 저장). 그것은 우리의 가능한 모든 움직임 (그 결과로 나온 보드)을 반복하고 상대가 우리가 성공적으로 이길 수있는 응답 수를 계산합니다 ( ). 우리가 이길 수 있다면 가능하고, 합계에 1을 더하고, 모두 이길 수 있다면 그것은 확실하며, 합계에 2를 더합니다. 따라서 최대 일부는 가능한 최상의 결과이며 문자열 "(|))"으로 색인하여 적절한면을 반환합니다. 합계가 2 또는 3 일 수 있으므로 추가 ")"가 필요합니다 (처음에 이미이긴 응답을 이길 수없는 것 같습니다). 약간 오해의 소지가 있음).G (즉, 우리가이기는 것과 그렇지 않은). 또한 가능한 응답 수를 계산합니다 (h

이 프로그램은 공백으로 구분 된 행과 열인 보드에서 문자열을 만들어 승리를 확인하고이 문자열에서 플레이어의 캐릭터 중 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

어떤 출력

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

좋은. 첫 번째 주셔서 감사합니다. :) 괜찮다면 주말 후에 현상금을 수여하여 추천 탭에서 며칠 더 유지할 것입니다.
insertusername 여기

@insertusernamehere 괜찮습니다. 실제 작업을 방해하지 않으면 내일 더 많은 작업을 수행 할 수 있습니다.
VisualMelon

1
" 나는 FORTY MINUTES에 대한 질문에 대답 할 수 없었습니다. 이것은 중요합니다! 데이터베이스 세부 정보를 보내면 SQL이 답변을 삽입 할 것입니다. 피해야 할 일이 많고 이유가 없습니다. 그것을 피하기 위해! "에 왜 스택 오버플로가 작동하지? . :)
insertusernamehere

1

PowerShell 576550 바이트

C #을 631 바이트 미만으로 얻을 수 없다면 다른 언어를 사용해야합니다! 나는 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

파이썬 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.