Bạn có thể giành chiến thắng với hai lần di chuyển nữa tại Three Men Morris không?


16

Tiền thưởng

Số 1 ( trao giải )

Tôi sẽ ném vào 50 rep cho câu trả lời hợp lệ đầu tiên

Số 2 ( trao giải )

Tôi sẽ gửi thêm 100 đại diện cho câu trả lời hợp lệ ngắn nhất.

Số 3 ( mở để gửi )

Tôi sẽ gửi 200 rep cho người đầu tiên với câu trả lời hợp lệ ngắn hơn đáng kể. Đáng kể nhất là 45% câu trả lời ngắn nhất hiện tại ( 564 byte x 0,45 = tối đa 254 byte ).


Tro choi

Bạn có nhớ trò chơi kinh điển " Nine Men Morris " hay đơn giản là " Mill "? Có một biến thể gọi là Three Men Morris , hơi giống một tic-tac-toe có thể thay đổi.

Quy tắc

Đây là bảng trống của trò chơi:

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

[ ]là một trường và |–/\đại diện cho các tuyến giữa các trường đó.

Trò chơi được chơi bởi hai người chơi 12mỗi người đặt 3 token trên bảng. Điều này thực sự đã xảy ra và chúng tôi đang ở trong trò chơi. Trò chơi được chiến thắng nếu một người chơi có thể tạo thành một millhàng dọc hoặc ngang trong 3 mã thông báo của người chơi.

Mã thông báo có thể được di chuyển trên bảng dọc theo các đường kết nối, theo quy tắc này:

Đến bất kỳ vị trí trống liền kề nào (nghĩa là từ vị trí cạnh đến trung tâm hoặc từ vị trí trung tâm đến vị trí cạnh hoặc từ vị trí cạnh đến vị trí cạnh liền kề

Người chơi phải thực hiện di chuyển trừ khi không có vị trí trống liền kề, trong trường hợp đó di chuyển bị bỏ qua.

Các thách thức

Bạn là người chơi 1và di chuyển của bạn là tiếp theo. Viết chương trình hoặc hàm, xác định xem:

  • bạn có thể buộc một chiến thắng với 2 hoặc ít hơn di chuyển ( thắng chắc chắn )
  • bạn có thể giành chiến thắng với 2 hoặc ít hơn các động tác, nếu đối thủ của bạn mắc lỗi ( có thể thắng )
  • bạn không thể giành chiến thắng với 2 hoặc ít hơn các lần di chuyển, bởi vì bạn sẽ cần nhiều nước đi hơn hoặc bởi vì các động tác bắt buộc sẽ khiến đối thủ của bạn giành chiến thắng ( không thể thắng )

Yêu cầu

  • Mặc dù bạn chắc chắn giành chiến thắng khi bạn chán đối thủ đến chết, chương trình của bạn phải kết thúc trong thời gian hữu hạn.
  • Bạn có thể viết một chương trình hoặc một chức năng.

Đầu vào

Các cầu thủ được đại diện bởi 12. 0định nghĩa một trường tự do. Bạn có thể lấy đầu vào dưới dạng ma trận hoặc một mảng.

Xác định

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]

Khả thi

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]

Không thể nào

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]

Đầu ra

Chương trình của bạn sẽ xuất / trả lại một mặt cười:

  • Chiến thắng chắc chắn: :)
  • Chiến thắng có thể: :|
  • Không thể thắng: :(

Ví dụ

Chiến thắng chắc chắn trong hai nước đi:

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

Chiến thắng có thể có trong hai nước đi:

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

Không thể thắng trong hai nước đi:

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

Tặng kem

Trong trường hợp có thể giành chiến thắng nhất định và chương trình của bạn đưa ra các bước di chuyển theo một cách để thành công cũng như a1:a2(1 di chuyển) hoặc a1:a2,a3:b2(2 di chuyển), bạn có thể rút 30% số byte của mình.


Đây là mã golf - vì vậy câu trả lời ngắn nhất trong byte thắng. Sơ hở tiêu chuẩn là không được phép.


Cảm ơn Peter Taylor , người đã sửa một số lỗi và cải thiện từ ngữ trong Sandbox .



1
Tôi thích những bảng ascii / đồ họa =)
flawr

1
Điều gì xảy ra nếu một người chơi không thể di chuyển? ví dụ: [1,0,0,2,1,0,2,2,1]người chơi 2 không thể di chuyển - đây có phải là chiến thắng cho người chơi 1 không?
VisualMelon

1
@LeifWillerts Tôi có thể hiểu nhầm ý của bạn, nhưng trong trường hợp đó, không có người chơi nào ở trạng thái chiến thắng - họ chỉ thắng bằng cách có một đường ngang hoặc dọc (không phải đường chéo).
VisualMelon

3
Chà, chỉ có 1680 vị trí bảng hợp lệ, vì vậy mã hóa cứng có thể cung cấp hơn 210 byte một chút. (ít hơn nếu tính đối xứng được xem xét)
lirtosiast

Câu trả lời:


1

Haskell, 580 564 441 byte

Đây là cách tôi có thể chơi golf bây giờ. Không chắc chắn nếu các ngôn ngữ khác có thể đánh bại nó.

Gọi mvào danh sách các danh sách như [[2,1,0],[2,1,2],[0,0,1]](Xác định A).

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

Mã kiểm tra:

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 trả về:

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

1
Sửa chữa, tôi nghĩ. Sẽ đánh đôi và chơi golf đúng cách vào buổi tối (ở đây là trước khi thời gian ân hạn kết thúc)
Leif Willerts 9/12/2015

5

C # - 739 663 byte

Hoàn thành chương trình, đọc đầu vào từ argv và xuất hiện để hoạt động. Chạy nó như

ThreeMill 1 2 1 1 2 0 0 0 2

Nếu phương thức nhập liệu này không được chấp nhận, tôi sẽ vui lòng thay đổi nó (không bao giờ thích sử dụng 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))]);}}

Tôi đã không thích đăng bài này vào ngày hôm qua, vì tôi đã không thể đánh nó xuống nhiều (không có nhiều thời gian và tôi có thể không tập luyện), nhưng vì chưa có phản hồi, tôi Dù sao thì tôi cũng sẽ đăng nó, tôi chắc chắn không mong đợi tiền thưởng, tôi muốn gửi cho ai đó đã nỗ lực hơn một chút trước khi đăng!

Chỉnh sửa: thay thế tất cả các bool bằng ints, điều đó có nghĩa là tôi có thể sử dụng Linq tốt hơn và quản lý để thu gọn cả hai vòng lặp foreach, mang lại khoản tiết kiệm lớn. Tôi hơi ngạc nhiên khi bộ hđếm hoạt động ... ++ là một tiện ích tinh tế như vậy.

Chương trình này rất đơn giản, nó chỉ khám phá mọi bộ di chuyển có thể (lưu trữ trạng thái bảng trong một chuỗi []). Nó lặp đi lặp lại trên tất cả các động tác có thể có của chúng tôi (các bảng kết quả của nó) và đếm số phản hồi của đối thủ mà chúng tôi có thể đánh bại thành công ( G) (tức là những ván mà chúng tôi thắng, và anh ta không thắng). Nó cũng đếm số lượng phản ứng có thể (h). Nếu chúng tôi có thể giành được bất kỳ, thì điều đó là có thể, và chúng tôi thêm 1 vào tổng, nếu chúng tôi có thể giành được tất cả, đó là một xác định và chúng tôi thêm 2 vào tổng. Do đó, tối đa một số là kết quả tốt nhất có thể của chúng tôi và chúng tôi lập chỉ mục vào chuỗi "(|))" để trả về khuôn mặt phù hợp. Lưu ý rằng chúng tôi cần thêm ")" vì tổng có thể là 2 hoặc 3 nếu nó là xác định (có thể là chúng tôi dường như không thể đánh bại bất kỳ phản hồi nào đã giành được trong lần đầu tiên, vì vậy kiểm tra có thể là một chút sai lệch).

Chương trình kiểm tra chiến thắng bằng cách tạo ra một chuỗi từ bảng, đó là các hàng và cột được phân tách bằng dấu cách và chỉ tìm chuỗi 3 ký tự của người chơi trong chuỗi này (ví dụ: "201 201 021 220 002 111" là một chiến thắng cho chúng tôi)

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 
            ]);

    }
}

Đây là kịch bản thử nghiệm của tôi:

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

Đầu ra nào

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

Đẹp. Cảm ơn vì đã là người đầu tiên. :) Nếu nó ổn, tôi sẽ thưởng tiền thưởng sau cuối tuần, để giữ nó thêm vài ngày nữa trong tab đặc trưng.
insertusernamehere

@insertusernamehere Điều đó tốt đối với tôi, nếu tôi không thể làm phiền bất kỳ công việc thực tế nào, tôi có thể làm thêm một số công việc vào ngày mai.
VisualMelon

1
Điều này nhắc nhở tôi về nhận xét này: " Tôi đã không thể trả lời một câu hỏi cho PHÚT LỚN. Điều này rất quan trọng! Chỉ cần gửi qua chi tiết cơ sở dữ liệu và tôi sẽ chèn SQL câu trả lời của mình. Tôi có rất nhiều việc phải tránh và không có lý do để tránh điều đó !! "trên Tại sao Stack Overflow không hoạt động? . :)
insertusernamehere

1

PowerShell 576 550 byte

Tôi sẽ không dễ bị răn đe - nếu tôi không thể có C # dưới 631 byte, tôi sẽ phải sử dụng một ngôn ngữ khác thay thế! Tôi hy vọng rằng Leif Willerts sẽ loại bỏ 5 byte câu trả lời của anh ấy, bởi vì tôi đã quyết định rằng tôi không quá thích PowerShell, có lẽ tôi chỉ cần nhìn vào nó một cách khách quan về mặt số lượng byte ...

Đây là một kịch bản, bạn chạy nó bằng . .\mill.ps1 "201102021". Đây là bản sao câu trả lời C # của tôi khá tốt, chỉ bằng ngôn ngữ mà tôi ít kinh nghiệm. Tôi đã không nỗ lực quá nhiều để chơi golf này, bởi vì phải mất quá nhiều thời gian để làm việc trong trường hợp đầu tiên, và đã nhỏ gọn một cách hợp lý.

Chỉnh sửa: không thể để những người đó [Math]::Floor cuộc gọi trong đó

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]

Nếu bạn mô tả về cách thức hoạt động của nó ... câu trả lời C # là dành cho bạn, nhưng hy vọng các ý kiến ​​làm cho nó đủ rõ ràng. Dấu chấm phẩy có thể không khớp hoàn hảo với lệnh một dòng, tôi không chắc là chúng cần ở đâu và không sao chép và không sao chép chúng lại khi tôi đặt toàn bộ trên một dòng.

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

Tập lệnh thử nghiệm (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"

Đầu ra của chúng:

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

1

Python 3, 566 557 byte

Tôi sẽ phải xem liệu tôi có thể đánh gôn thêm không, hoặc tôi có thể nhận được 30% tiền thưởng không, nhưng sau nhiều sự chần chừ, đây là câu trả lời của tôi.

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":|"

Ung dung:

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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.