Perl,147个字节(非竞争性,每次移动耗时超过10秒)
包括+4 -0p
程序播放X
。它将扮演一个完美的游戏。
在STDIN上输入板,例如:
tictaclatin.pl
-X-O
-X--
X-X-
O--O
^D
输出将是同一块板,所有X
替换为O
,反之亦然。空点将被一个数字填充,该数字指示如果X将在那里比赛的结果,则1
意味着结果将是胜利,2
平局和3
失败。完成的游戏只是返回相同的位置,而颜色却相反。
在此示例中,输出为:
1O1X
1O33
O3O3
X33X
因此,X
如果他在顶部和左侧的3个位置上都发挥作用,则该职位是赢家。其他所有动作都会失败。
如果您想知道移动后游戏如何继续,这种令人困惑的输出实际上很方便。由于该程序始终在播放,因此X
您必须进行交换X
并O
查看的移动O
。例如,在这里很明显,X
靠左上方的比赛获胜,但是如果X
沿顶部的第三位比赛怎么办?只需复制输出,O
替换您选择的举动,-
然后再次替换所有其他数字,所以在这里:
-OOX
-O--
O-O-
X--X
导致:
3XXO
3X33
X3X3
O33O
显然,每一个举动O
都应该输掉,那么如果他在左上角打球怎么输?再次这样做,方法是将O
左上角的数字替换为-
:
OXXO
-X--
X-X-
O--O
给予:
XOOX
1O33
O3O3
X33X
因此,X只有一种赢得胜利的方法:
XOOX
OO--
O-O-
X--X
给予
OXXO
XX33
X3X3
O33O
情况O
仍然没有希望。现在很容易看出,每一步都可以X
立即获胜。让我们至少尝试连续3个O:
OXXO
XX--
X-X-
O-OO
给予:
XOOX
OO13
O3O3
X3XX
X
参与唯一获胜的举动(注意,此举XXXO
沿第三栏:
XOOX
OOO-
O-O-
X-XX
这里的输出是:
OXXO
XXX-
X-X-
O-OO
因为游戏已经结束了。您可以在第三栏看到获胜。
实际程序tictaclatin.pl
:
#!/usr/bin/perl -0p
y/XO/OX/,$@=-$@while$|-=/(@{[map{(O.".{$_}O"x3)=~s%O%Z|$`X$'|Z%gr}0,3..5]})(?{$@++})^|$/sx;$@<=>0||s%-%$_="$`O$'";$$_||=2+do$0%eg&&(/1/||/2/-1)
将其应用于空板上,可以评估9506699的位置,这在我的计算机上需要30 Gb和41分钟。结果是:
2222
2222
2222
2222
因此,每一个开始的举动都会吸引。因此游戏是平局。
极端的内存使用情况主要是由使用递归引起的do$0
。使用普通功能使用此154字节版本需要3Gb和11分钟:
#!/usr/bin/perl -0p
sub f{y/XO/OX/,$@=-$@while$|-=/(@{[map{(O.".{$_}O"x3)=~s%O%Z|$`X$'|Z%gr}0,3..5]})(?{$@++})^|$/sx;$@<=>0||s%-%$_="$`O$'";$$_||=2+&f%eeg&&(/1/||/2/-1)}f
这是可以忍受的(但仍然太多了,某些东西仍然必须泄漏内存)。
结合多个加速因素,就可以得到以下160字节的版本(5028168个位置,空板4分钟和800M):
#!/usr/bin/perl -0p
sub f{y/XO/OX/,$@=-$@while$|-=/(@{[map{(O.".{$_}O"x3)=~s%O%Z|$`X$'|Z%gr}0,3..5]})(?{$@++})^|$/osx;$@<=>0||s%-%$_="$`O$'";$a{$_}//=&f+1or return 1%eeg&&/1/-1}f
最后一个0
用于获胜(请勿与混淆O
),1
平局和2
亏损。这一项的输出也更加令人困惑。在没有颜色交换的情况下,它为X填充了获胜的举动,但是如果输入游戏已经获胜,则仍然进行颜色交换并且不填充任何举动。
当然,随着电路板的装满,所有版本都会变得更快,并使用更少的内存。进行2或3次移动后,速度更快的版本将在10秒内产生一次移动。
原则上,此146字节版本也应起作用:
#!/usr/bin/perl -0p
y/XO/OX/,$@=-$@while/(@{[map{(O.".{$_}O"x3)=~s%O%Z|$`X$'|Z%gr}0,3..5]})(?{$@++})^/sx,--$|;$@<=>0||s%-%$_="$`O$'";$$_||=2+do$0%eg&&(/1/||/2/-1)
但是在我的机器上,它会触发perl错误并转储核心。
如果$$_||=
删除by进行的6字节位置缓存,则所有版本原则上仍然可以使用,但是这会占用大量时间和内存,因此仅适用于几乎装满的电路板。但是从理论上讲,至少我有一个140字节的解决方案。
如果你把$\=
(费用:3个字节)的前刚刚$@<=>0
然后每个输出板之后,将整个板的状态:1
为X
胜,0
对于平局和-1
损失。
这是基于上述最快版本的交互式驱动程序。驾驶员对游戏何时完成没有逻辑,因此您必须停下来。高尔夫规则知道。如果建议的举动返回且没有任何-
替换,则游戏结束。
#!/usr/bin/perl
sub f{
if ($p++ % 100000 == 0) {
local $| = 1;
print ".";
}
y/XO/OX/,$@=-$@while$|-=/(@{[map{(O.".{$_}O"x3)=~s%O%Z|$`X$'|Z%gr}0,3..5]})(?{$@++})^|$/osx;$@<=>0||s%-%$_="$`O$'";$a{$_}//=&f+1or return 1%eeg&&/1/-1}
# Driver
my $tomove = "X";
my $move = 0;
@board = ("----\n") x 4;
while (1) {
print "Current board after move $move ($tomove to move):\n ABCD\n";
for my $i (1..4) {
print "$i $board[$i-1]";
}
print "Enter a move like B4, PASS (not a valid move, just for setup) or just press enter to let the program make suggestions\n";
my $input = <> // exit;
if ($input eq "\n") {
$_ = join "", @board;
tr/OX/XO/ if $tomove eq "O";
$p = 0;
$@="";
%a = ();
my $start = time();
my $result = f;
if ($result == 1) {
tr/OX/XO/ if $tomove eq "O";
tr/012/-/;
} else {
tr/OX/XO/ if $tomove eq "X";
tr/012/123/;
}
$result = -$result if $tomove eq "O";
my $period = time() - $start;
print "\nSuggested moves (evaluated $p positions in $period seconds, predicted result for X: $result):\n$_";
redo;
} elsif ($input =~ /^pass$/i) {
# Do nothing
} elsif (my ($x, $y) = $input =~ /^([A-D])([1-4])$/) {
$x = ord($x) - ord("A");
--$y;
my $ch = substr($board[$y],$x, 1);
if ($ch ne "-") {
print "Position already has $ch. Try again\n";
redo;
}
substr($board[$y],$x, 1) = $tomove;
} else {
print "Cannot parse move. Try again\n";
redo;
}
$tomove =~ tr/OX/XO/;
++$move;
}