十字架,无空


10

每个人都认识到井字游戏是一款已解决的游戏。但是,仅X的Misère版本提供了一个有趣的选择。

在此版本的游戏中,两名玩家都在板上玩X,并尝试避免连续三局。如果您想了解更多有关此的信息,Numberphile提供了有关此概念的精彩视频。

给定MisèreCrosses董事会,发挥最佳行动。

木板是三行,每行三个字符,分别是X。从而:

X X
X  
 XX

是有效的董事会。您可以采用任何方便的格式,只要您的输入和输出使用相同的格式即可。格式包括(但不限于):多行字符串(带有可选的尾随换行符);二维其是字符数组X; 一维扁平化的布尔值数组,表示是否已播放每个位置。

最佳举动是通过继续最佳发挥来保证您会获胜或尽可能长时间地延长亏损的举动,它由以下规则定义:

  • 避免连续三个。
  • 如果您先走,请在中间玩。
  • 如果唯一的占用空间是中间位置,请在任何剩余的空间中播放。
  • 如果中间的正方形没有被占用,而外部的正方形被占据,则与对手的最后一局相对。
  • 如果中间方格被占领,而外部方格被占领,则在不招致您失败的情况下,与前一步打“骑士步”(对面,翻过来)。
  • 如果没有剩余的方格,您就可以玩剩下的方格。

[注意:在一种情况下,这已被证明不是最佳选择,但无论如何都应使用此算法。]

您可能会认为之前的所有举动都是最佳的。因此,第一个示例板不是有效输入。对手的举动可能是最优的,也可能不是最优的。

如果游戏结束(即连续三场比赛),则行为不确定。

因为这是,所以最短答案(以字节为单位)将获胜!

仅使用最佳移动的一种可能路径是:

[   ]  [   ]  [X  ]  [X  ]  [X  ]  [X  ]  [XX ]
[   ]->[ X ]->[ X ]->[ XX]->[ XX]->[ XX]->[ XX]
[   ]  [   ]  [   ]  [   ]  [ X ]  [XX ]  [XX ]

以下是使用非最佳移动方法从对手处获得的可能输入:(
请注意,仅此列表上的左侧面板是有效输入。)

[X  ]  [X  ]
[   ]->[   ]
[   ]  [  X]

[XX ]  [XX ]
[   ]->[   ]
[  X]  [ XX]

[XX ]  [XX ]
[X  ]->[X X]
[ XX]  [ XX]


输入和输出格式是什么?我假设一个板子被当作数组或字符串?但是,这没有提供最后一步的信息,因此是我的下一个问题。
水平河圣

1
策略“与对手的最后一场比赛相对”是假设您了解了对手的移动历史,或者您以前已经遵循了该策略,即没有继承.XX\nX..\nX..例如棋盘。我们是否必须考虑继承这样的董事会?
水平河圣

@LevelRiverSt按照写法,“您可以假设以前的所有举动都是最佳的”,因此该板将是无效的输入。您可以采用任何喜欢的格式输入,但是多行字符串(例如您的示例)将是“默认”:我只是不想限制任何人在移动逻辑是关键时必须解析String。挑战。
CAD97

Answers:


3

Ruby,修订版B 121字节

提交是匿名函数,减去f=。在测试程序中显示以说明用法。

f=->n{["~mK)\7","}uYwQO"][l=n%2].bytes{|t|9.times{|i|(m=n|1<<i)==n||8.times{|j|m/2*257>>j&255==126-t&&t+j%2!=119&&l=m}}}
l}

puts g=f[gets.to_i]
puts
[7,6,5,
 8,0,4,
 1,2,3].each{|i|print g>>i&1; puts if i/3==1}

通过使中心正方形成为最低有效位而不是最高有效位,可以节省2个字节(用/2代替,而不是%256。)通过重组可接受的动作表来节省剩余空间。组织为自由/占用的中心正方形而不是按X的总数进行组织,可以简化测试。而且,现在数组中只有2个字符串,因此%w{string1 string2}语法被放弃,以支持["string1","string2"]语法。这样可以\7包含不可打印的字符,从而可以使用更简单的编码:126-t代替(36-t)%120

Ruby,修订版143字节

->n{l=r=("%b"%n).sum%8
%w{$ %5 - I+Wy Q S#}[r].bytes{|t|9.times{|i|(m=n|1<<i)==n||8.times{|j|m%256*257>>j&255==(t-36)%120&&t+j%2!=43&&l=m}}}
l}

这是一个匿名函数。输入/输出格式保持打开状态,因此我准备使用9位二进制数。512位代表中心,其余位围绕它呈螺旋形旋转(1位被认为是一个角。)

可能的输入比可接受的输出要多得多,因此该算法将尝试所有移动,并找到适合可接受输出模式的移动。每个X数量可接受的输出模式都经过硬编码。

删除有关中心正方形的信息,并将剩余的8位乘以257以复制它们。然后通过右移使该图案旋转超过可接受的图案。

找到样式后,循环不会退出,因此返回的样式将是找到的最后一个可接受的样式。因此,首选模式(有偏好的模式)会出现在列表的后面。

考虑到“骑士移动”策略,图案是否旋转45度并不重要。未打高尔夫球的版本遵循骑士移动策略,因此无需区分拐角正方形和边角正方形:无论如何都要避免连续三个。

但是,我发现这并不总是最好的策略,因为存在以下技巧。如果您的对手先走并取得中锋,他应该获胜。但是在他的第二步中,他犯了一个错误,那就是让您做出一个2x2的正方形,这是您应该采取的做法,因为这可以使您迫使他连续制造三个。这是在高尔夫球版中实现的。在这种情况下,需要一点额外的代码来区分拐角处的三个X(迫使对手丢失)和沿一个边缘的3个X(立即自杀)。

取消测试程序

非高尔夫版本遵循问题中表达的逻辑。

在高尔夫球版本中,桌子进行了略微的修改,[[0],[1,17],[9],[37,7,51,85],[45],[47,119]]以实现与表壳略有不同的行为r=3。然后将其压缩为可打印的ASCII(需要解码(t-36)%120)。在表条目7的情况下,需要额外的逻辑来区分拐角处的三个X和沿边的三个X:&&t+j%2!=43

f=->n{l=r=("%b"%n).sum%8                                      #convert input to text, take character checksum to count 1's(ASCII 49.) 
                                                              #0 is ASCII 48, so %8 removes unwanted checksum bloat of 48 per char.
                                                              #l must be initialised here for scoping reasons.
  [[0],[1,17],[9],[11,13,37,51,85],[45],[47,119]][r].each{|t| #according to r, find the list of acceptable perimeter bitmaps, and search for a solution.
    9.times{|i|(m=n|1<<i)==n||                                #OR 1<<i with input. if result == n, existing X overwritten, no good.
                                                              #ELSE new X is in vacant square, good. So.. 
      8.times{|j|m%256*257>>j&255==t&&l=m}}                   #%256 to strip off middle square. *257 to duplicate bitmap.
                                                              #rightshift, see if pattern matches t. If so, write to l
  }
l}                                                            #return l (the last acceptable solution found) as the answer.

#call function and pretty print output (not part of submission)
puts g=f[gets.to_i]
puts
[6,7,0,
 5,8,1,
4,3,2].each{|i|print g>>i&1; puts if i<3}

测试程序输出

电脑播放时会发生这种情况。

C:\ Users \ steve> ruby​​ tictac.rb
0
256

000
010
000

C:\ Users \ steve> ruby​​ tictac.rb
256
384

010
010
000

C:\ Users \ steve> ruby​​ tictac.rb
384
400

010
010
100

C:\ Users \ steve> ruby​​ tictac.rb
400
404

010
010
101

C:\ Users \ steve> ruby​​ tictac.rb
404
436

010
110
101

C:\ Users \ steve> ruby​​ tictac.rb
436
444

010
110
111

游戏分析第一

这实际上是非常简单且线性的。

在开始比赛时,中间的方块将始终是第一个方块。

r = 0

...  binary representation 0
.X.
...

r = 2

X..  binary representation 1001=9 
.XX
...

r = 4

X.. binary representation 101101=45
.XX
XX.

在不结束游戏的情况下,只有一种方法(可以对称)具有五个X(包括棋盘上的中间方块)。中间的正方形有一个X,每个对角线一个(彼此成90度),每个水平/垂直中心线一个(彼此成90度)。由于不能占据整个边缘,所以上面是唯一的可能的安排。其他玩家必须在下一步行动中输掉。

游戏分析第二

玩法完全不同,具体取决于其他玩家是否选择中间方块。

r = 1

中间广场占领

.X. X..  binary representation 1 
.X. .X.
... ...

中间广场免费

X.. .X. binary representation 10001=17
... ...
..X .X.

r = 3

中间方格,如果其他玩家在您的最后一个X附近玩

XX. .XX binary representation 1011=11 
.X. XX. or mirror image 1101=13
X.. ...

但是,上述方法并非最佳选择,高尔夫版本不支持上述方法。最好的举动如下,迫使下一轮获胜:

XX. binary representation 111=7.           XXX
XX. Only to be used where j is odd.        .X.
... Even j would look like image to right. ...

如果其他玩家以与您最后一个X呈90度或135度的角度进行游戏,则占据中间方格(扮演骑士的步伐)。

X.X .X. binary representation 100101=37 
.X. .XX
.X. X..

中间广场免费

X.X .X. XX. binary representations:
... X.X ...    1010101=85 (first two)
X.X .X. .XX and 110011=51 (last one)

r = 5

中间广场占领。由于上面在r = 4中所述的原因,有四个可能的动作,所有这些动作都失败了。仅支持一个:101111 = 47。

中间广场免费。如下所示,只有一个可能的板达到对称。其他玩家必须在下一步行动中输掉,因此无需支持r> 5。

XX. binary representation 1110111=119
X.X
.XX

这是一个了不起的答案!我以为我已经检查了所有情况下的最佳萌,但我想我错过了。不过,为简单起见,规范将保持不变。(真的,这真是太棒了,谢谢您这样做,并且对此做了很好的解释!我离开了I / O
通道,

1
谢谢,这是一个有趣的挑战。我现在已经设法打更多的高尔夫球了。
级圣河
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.