你下一步要做什么?


18

面临的挑战是用您选择的语言编写一个minimax函数,在给定当前棋盘状态的情况下,在井字游戏的NxN游戏中输出下一个最佳动作。板输入可以接受为矩阵,2D集合对您有意义但符合规则的任何其他内容。输出是下一个最好的举动谁轮到它是目前,其中X被认为已经开始

Minimax算法的快速背景

minimax算法的基本思想是将所有可能的结果作为DAG枚举,然后通过一系列动作对玩家的好处(通过第一个动作为关键)对它们进行加权。然后,所有可能的结果都会在第一步中“丢包”,并根据所有结果的总和进行评分(-1为损失,0为平局,1为胜利)。在需要多个玩家参与的实现中,您需要枚举玩家的所有可能举动以及对手的所有可能的响应。例如,在井字游戏中(第一个举动之后),您可以进行8个可能的第一个举动,而在仅分析下一弯时,它们似乎都相等。但是,通过对每组可能产生最终结果的动作进行遍历所有可能的结果并将它们加总,

有关tic-tac-toe的mini-max算法的更好,更深入和上下文的摘要,请在此处阅读更多信息:http : //neverstopbuilding.com/minimax

XKCD(仅3x3解决方案)

井字游戏3x3游戏的所有可能动作。

规则

  • 可以使用任何语言,但不允许使用外部minimax库。
  • 输出可以是表示最佳下一移动的坐标(0-n,0-n)或数字(1-n * n)。
    • 除此之外,您必须能够确定最佳情况是什么时候是失败或平局而不是获胜。
    • 您表示损失或平局的方式再次取决于您。
  • 输入必须使用传统的X和O,并且您必须假设X首先移动;空格可以用任何东西表示。
  • 您可以假设进入程序的任何输入都具有n个O和n + 1个X,换句话说,您可以假设您得到的是格式良好的板。
  • 开发板的当前状态必须是程序的唯一输入,如果使用递归,则必须使用辅助方法来满足输入要求。有关说明,请参见/codegolf//a/92851/59376
  • 必须支持10> = n> = 1的任何值。如果您的程序在n> 10时“超时”,我也认为这是可以接受的,因为某些语言的处理能力明显降低(尤其是使用面向Web的控制台)。

评判

  • 这是代码高尔夫球,因此程序的最低字节数获胜,并且普遍禁止标准漏洞。
  • 如果是平局,则支持最大n的程序将获胜。

输入示例

2x2

[[X,O]
 [-,-]]

输出: 2或[0,1](也可以说是3或[1,1]正确)(以某种形式表示位置,只要可以方便地解释所使用的格式即可)


3x3

[[X,O,X]
 [O,X,-]
 [-,-,-]]

输出: -1(损失)


再次允许使用您想要的任何输入格式,但必须使用X和O,所提供的示例并非旨在限制该格式,仅是为了启发。


抱歉,DJMCMayhem,我实际上试图标记这些东西,但由于我是新来的人,所以无法。
魔术章鱼缸

奖金也被删除,只增加了乏味。
魔术章鱼缸

是否允许使用以下输出格式:棋盘位置图,每个原始空白处都有一个唯一的字符,指示在此游戏是否导致赢/输/平局(例如W,L和D)
Ton Hospel

1
在3x3的示例中,无论他玩什么,O都应该输掉,但是您说输出应该是[2,1],为什么呢?
达达

编辑,不错。不知道我在想什么,那是负面的例子。
魔术章鱼缸

Answers:


8

Perl,101 98字节

包括+4用于-0p

使用STDIN上的输入运行

tictactoe.pl
OXO
---
--X
^D

输出是相同的图,但是每个动作的状态都会更新,1代表胜利,2代表平局,3代表损失。对于这种情况,

OXO
223
21X

因此3次平局,1赢1输(如果这种输出格式不可接受,我将更新解决方案,但基本代码将保持不变)

tictactoe.pl

#!/usr/bin/perl -0p
m%@{[map"O.{$_}"x"@-"."O|",1-/.(
)(.)/,@-]}Z%sx||s%-%$_="$`X$'";y/XO/OX/;do$0%eg?/1/?3:1+/2/:2

这已经很慢了,并且为空的3 * 3开发板使用了很多内存(为什么实际上,递归没有那么深。一定是内存泄漏)。添加备忘录需要6个字节,但要聪明得多:

#!/usr/bin/perl -0p
$$_||=m%@{[map"O.{$_}"x"@-"."O|",1-/.(\n)(.)/,@-]}Z%sx||s%-%$_="$`X$'";y/XO/OX/;do$0%eg?/1/?3:1+/2/:2

哇,忽略了它的作用,可能很可能不会在n = 10的情况下运行很多空容器...您做了我希望看到有人做的两件事。一个字符串输入并映射所有动作的结果,而不仅仅是最好的。太棒了
魔术章鱼缸

如果一个递归函数“泄漏”怎么办呢???语言太高级,无法在CPU中看到32位寄存器(或类似简单指令的内容)
RosLuP

在这种情况下,@ RosLup泄漏并不一定意味着无法访问的丢失内存。Perl在释放内存时非常特殊,它经常比您预期的要晚,因此使用的内存比您预期的要多。它也倾向于分配比直接需要更多的资源,以期您将增长数据结构。在这种情况下,将“正常”递归与功能配合使用(而不是滥用)do$0将减少10倍的内存。请注意,这种情况是如此极端,实际上可能是真正的内存泄漏。
Ton Hospel '16

不仅一个人没有看到寄存器或基本指令(从hlls指令中获得),而且失去了对内存使用的控制...对我来说,它们不能扩展...
RosLuP

已经足够长的时间了,您赢了我的男人,可惜我们没有再尝试。
魔术

2

使用Javascript(ES6),320个 294字节

(b,p,d,M,S=-2)=>(T=(p,q,r,s)=>b[p][q]==(n=b[r][s|0])&&n!='-',w=0,b.map((r,y)=>(l=r.length-1,m=15,r.map((c,x)=>(m&=8*T(l-x,x,l)+4*T(x,x,0)+2*T(x,y,0,y)+T(y,x,y))),w|=m)),w?-1:(b.map((r,y)=>r.map((c,x)=>S<1&&c=='-'&&(r[x]='O.X'[p+1],(s=-f(b,-p,1))>S&&(S=s,M=[x,y]),r[x]=c))),S=S+2?S:0,d?S:[M,S]))

输入值

1)描述当前板的字符数组,例如:

[['X', '-'], ['-', 'O']]

2)描述当前转弯的整数:1 = X,-1 =O

输出量

由以下组成的数组:

  • [x, y]格式描述最佳移动的数组
  • 游戏结果为整数:1 =赢,-1 =输,0 =平局

在以下示例中,X通过玩保证赢[1, 2]

let f =
(b,p,d,M,S=-2)=>(T=(p,q,r,s)=>b[p][q]==(n=b[r][s|0])&&n!='-',w=0,b.map((r,y)=>(l=r.length-1,m=15,r.map((c,x)=>(m&=8*T(l-x,x,l)+4*T(x,x,0)+2*T(x,y,0,y)+T(y,x,y))),w|=m)),w?-1:(b.map((r,y)=>r.map((c,x)=>S<1&&c=='-'&&(r[x]='O.X'[p+1],(s=-f(b,-p,1))>S&&(S=s,M=[x,y]),r[x]=c))),S=S+2?S:0,d?S:[M,S]))

console.log(JSON.stringify(f(
  [['O','X','O'],
   ['-','-','-'],
   ['-','-','X']],
  1
)));

一个奇怪的游戏。唯一的制胜法宝没有发挥。
怎么样的国际象棋游戏?


做得好,很好的第一个入口。仅保留我的备注可能会保存带有给定信息“ X始终优先”的字节。并且您是否尝试过使用非3x3板;)?
Magic Octopus Urn

@carusocomputing-不知道您对“ X始终优先”的想法。它可以用来推论哪一块板是单板的,但是计算实际上会花费更多的字节。所以我想你在说别的东西。回答:是的,我用稍大一些的板子做了一些测试。只要... err ...没有太多的空缺职位,那应该可以正常工作。:-)
Arnauld

挑战说The current state of the board must be the only input to your program。您的代码需要两个输入,这违反了该规则。
达达

1
@Dada-我对此很疑惑,但我认为活动颜色 董事会状态的一部分(就像国际象棋的位置总是伴随着活动颜色+被动正方形+小圆滑的可用性)。因此,我想OP应该澄清这一点。(恕我直言,这听起来像是不必要的额外困难,恕我直言。)
Arnauld

1
嗯..我真的很喜欢他的回应中关于董事会状态的解释。考虑到这一点,有些挂绳可能只使用字符串作为输入,如果没有诸如板子尺寸之类的其他信息,拥有像XXOOXO-OO这样的板子就很难以低字节数进行解码。尽管我仍然认为“假设X先走”信息与“给谁转动”的信息不同,但不允许任何其他有助于董事会状态的输入。有些语言会以此为前提;)。
魔术章鱼缸
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.