奎宁井字游戏


19

用您选择的语言编写一个程序,该程序可以在3 * 3板上与人类玩家玩井字游戏。但是,每一步都必须是从上一次迭代生成的不同程序

评估人工输入的方式和方式由您决定,但是必须从标准输入中读取。同样,您可以自由选择一种方法来确定哪个玩家开始游戏(例如,您先问一个问题,或者您允许人类输入一个无效举动来表明计算机已经开始运转,或者其他想法)。

不需要验证动作,您可以假设一个公平的人类对手。

基本上,您具有与电路板状态相对应的程序。状态以任何可识别的方式打印,但是至少需要以下详细级别:

X..
00X
x..

在人类玩家输入动作之后,您的程序必须以相同的语言(标准输出或文件)将自身的下一个迭代生成为源文件并终止。不允许将信息存储在该源文件之外的任何其他位置。(您的程序不必构建和运行所生成的程序,它可以由用户完成-但是,这不是禁止的)。生成并运行生成的程序时,它的行为类似,显示状态,等待用户输入等。

在游戏结束时,您必须以任何明确的方式打印结果(无论您赢了还是平局)。

完美发挥,我的意思是程序一定不能输,如果有可能迫使获胜,那就应该赢。

最短代码获胜,第一个有效条目至少10天后选出获胜者。

如果您的程序可以处理下一个迭代的构建和启动,您的得分将减少10%。(我知道,这很可能不值得)当然,程序本身必须在下一次迭代接受用户的移动时终止。

如果您使用一些奇怪的不常见技巧,请在代码中附上简短的说明。


2
挑战不错,但我想我会选择退出。
约翰·德沃夏克

“每一步都必须是不同的程序”。您是说“每个游戏都必须由原始程序的新的,不同的实例启动和管理”吗?
DavidC

1
@DavidCarraher:不,每一个动作,而不仅仅是每局比赛。检查下面的电路板示例说明。当计算机必须移动时(因此电路板的状态发生变化),您的程序必须生成一个源文件,该文件在构建和运行时将成为下一个状态。然后,原始程序退出。新生成的程序在移动时将具有类似的行为:它将创建一个源文件,该文件在构建和运行时将成为下一个状态,依此类推。由于除已生成的源文件中之外不允许任何信息存储,因此它就像是迭代之间有差异的quine。
vsz

Answers:


13

Perl,933个字符

$m=<<'';$_='         ';
sub h{/^(?:...)*(\d)\1\1/|/^.?.?(\d)..\1..\1/|/(\d)...\1...\1/|/^..(\d).\1.\1/&&$1}
sub r{substr($_,$p-1,1)=pop}sub p{my$w=pop;my@b=(0,h==$w||h&&-1);if(!$b[1]&&/ /){$b[1]=-9;
while(/ /g){local($_,$p)=($_,pos);r$w;$r=-(p($w^1))[1];@b=($p,$r)if$r>$b[1]}}@b}
if(($w=h||!/ /)||!@ARGV){$w--&&print+(nobody,X,O)[$w]," wins\n";s/(...)/$1\n/g;
tr/ 23/.XO/;print}else{$w=3;$w^=1for/\d/g;($p=pop)?r($w^1)&&!h&&(($p)=p$w)&&r$w:s/ /2/;
print"\$m=<<'';\$_='$_';\n$m\n$m"}

sub h{/^(?:...)*(\d)\1\1/|/^.?.?(\d)..\1..\1/|/(\d)...\1...\1/|/^..(\d).\1.\1/&&$1}
sub r{substr($_,$p-1,1)=pop}sub p{my$w=pop;my@b=(0,h==$w||h&&-1);if(!$b[1]&&/ /){$b[1]=-9;
while(/ /g){local($_,$p)=($_,pos);r$w;$r=-(p($w^1))[1];@b=($p,$r)if$r>$b[1]}}@b}
if(($w=h||!/ /)||!@ARGV){$w--&&print+(nobody,X,O)[$w]," wins\n";s/(...)/$1\n/g;
tr/ 23/.XO/;print}else{$w=3;$w^=1for/\d/g;($p=pop)?r($w^1)&&!h&&(($p)=p$w)&&r$w:s/ /2/;
print"\$m=<<'';\$_='$_';\n$m\n$m"}

请注意,实际上需要在脚本中间插入空白行。(除了为了清晰起见,不需要在长行末尾使用换行符,并且不包括在字符计数中。)

用法:在没有参数的情况下运行该程序时,它将显示当前游戏状态。由于开始时板是空的,因此输出为:

...
...
...

运行参数在1到9之间的程序,以声明该平方作为您的移动。该程序将自行移动,然后输出具有新状态的替换脚本。因此,例如:

$ perl ./qttt 5 > ./qttt-2
$ perl ./qttt-2
O..
.X.
...

仅在第一转时,您可以移动0来表示计算机应该先移动。请注意,第一个玩家将永远是X

游戏结束后,显示输出将包含有关该效果的注释:

$ perl ./qttt-4 6 > ./qttt-5
$ perl ./qttt-5
O wins
OXX
OOX
X.O

该程序通过对游戏树进行标准的minimax搜索来工作。(井字游戏足够小,每次运行都可以生成完整的游戏树。)这种情况的例外是计算机先移动时-在这种情况下,最初移动到左上角很困难-编码。

请注意,该程序以适当的形式工作-脚本在任何时候都不会访问其自己的源文件以产生其输出。


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.