您可以在《三人莫里斯》中再赢两步吗?


16

赏金

第一名(获奖

我将为第一个有效答案投入50个报告

2号(获奖

我将再提供100个最短有效答案。

第3名(开放提交

我将为第一个报告贡献200个报告,并给出一个有效的简短答案。有效值最多为当前最短答案的45%(564字节x 0.45 = 最大254字节)。


游戏

您还记得经典游戏“ 九个人的莫里斯 ”还是简单的“ 磨坊 ”?有一个变种,叫做“ 三人莫里斯”,有点像易变的井字游戏。

规则

这是游戏的空白板:

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

[ ]是一个字段,|–/\代表这些字段之间的路由。

该游戏由两个玩家扮演12谁每个地方的板3个令牌。这实际上已经发生了,我们已经参与其中。如果一个玩家可以形成一个游戏,则该游戏获胜。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][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表格/图形=)
瑕疵的

1
如果玩家无法移动会怎样?例如,在中[1,0,0,2,1,0,2,2,1],玩家2无法移动-这是玩家1的胜利吗?
VisualMelon 2015年

1
@LeifWillerts我可能会误解您的意思,但是在那种情况下,没有球员处于获胜状态-他们只能通过水平或垂直线(而不是对角线)获胜。
VisualMelon 2015年

3
好吧,只有1680个有效的电路板位置,因此硬编码可以提供210个字节多一点。(如果考虑对称,则更少)
lirtosiast 2015年

Answers:


1

哈斯克尔,580个 564 441字节

这就是我现在能打多远。不知道其他语言是否能胜过它。

调用m列表列表,如[[2,1,0],[2,1,2],[0,0,1]](Definite 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

测试代码:

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 2015年

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计数器的工作感到有些惊讶... ++是如此微妙的实用程序。

该程序非常简单,它仅探索每组可能的动作(将电路板状态存储在string []中)。它遍历我们所有可能的举动(由此产生的棋盘),并计算对手能够成功击败(G)(即我们获胜而他没有获胜)的回应数量。它还会计算可能的响应数(h)。如果我们赢了,那是有可能的,我们将1加到总和上,如果我们能赢全部,那就是确定的,再加上2。因此,最大数量是我们最好的结果,我们索引到字符串“(|))”以返回适当的面孔。请注意,我们需要额外的“)”,因为如果确定的总和为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

哪个输出

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

真好 感谢您成为第一个。:)如果可以的话,我会在周末之后颁发赏金,以便在精选标签中再保留几天。
2015年

@insertusernamehere我很好,如果我不愿意做任何实际的工作,明天我可能会做更多的工作。
VisualMelon

1
这使我想起了这样的评论:“ 我无法回答FORTY MINUTES的问题。这很关键!只是发送数据库详细信息,然后我将通过SQL插入我的答案。我有很多工作需要避免,没有理由为了避免它! “关于为什么堆栈溢出不起作用?” 。:)
insertusername此处为2015年

1

PowerShell 576550字节

我不会那么容易受阻-如果我无法使C#低于631字节,我将不得不使用其他语言!我希望Leif Willerts将他的答案弄掉5个字节,因为我已经决定我不太喜欢PowerShell,也许我只需要客观地看一下字节数即可。

这是一个脚本,您可以通过运行 . .\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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.