Perl, 147 byte (không cạnh tranh, mất hơn 10 giây mỗi lần di chuyển)
Bao gồm +4 cho -0p
Chương trình chơi X
. Nó sẽ chơi một trò chơi hoàn hảo.
Nhập bảng trên STDIN, ví dụ:
tictaclatin.pl
-X-O
-X--
X-X-
O--O
^D
Ouptut sẽ là cùng một bảng với tất cả được X
thay thế bởi O
và ngược lại. Các điểm trống sẽ được lấp đầy bằng một con số cho biết kết quả nếu X chơi ở đó, với 1
nghĩa là kết quả sẽ là thắng, 2
hòa và 3
thua. Một trò chơi đã hoàn thành chỉ trả về cùng một vị trí với màu sắc đảo ngược.
Trong ví dụ này, đầu ra sẽ là:
1O1X
1O33
O3O3
X33X
Vì vậy, vị trí này là một chiến thắng cho X
nếu anh ta chơi ở 3 vị trí dọc theo đỉnh và bên trái. Tất cả các động thái khác bị mất.
Đầu ra khó hiểu này thực sự tiện lợi nếu bạn muốn biết trò chơi tiếp tục như thế nào sau khi di chuyển. Vì chương trình luôn phát X
nên bạn phải trao đổi X
và O
để xem các động thái cho O
. Ví dụ ở đây khá rõ ràng là X
chiến thắng bằng cách chơi ở phía trên bên trái, nhưng nếu X
chơi ở vị trí thứ ba dọc theo đỉnh thì sao? Chỉ cần sao chép đầu ra, đặt một O
vị trí di chuyển bạn chọn và thay thế tất cả các số khác -
một lần nữa, vì vậy ở đây:
-OOX
-O--
O-O-
X--X
Kết quả là:
3XXO
3X33
X3X3
O33O
Rõ ràng mỗi lần di chuyển đều O
phải thua, vậy làm thế nào để anh ta thua nếu chơi ở phía trên bên trái? Một lần nữa làm điều này bằng cách đặt O
ở trên cùng bên trái và thay thế các chữ số bằng cách -
:
OXXO
-X--
X-X-
O--O
Tặng:
XOOX
1O33
O3O3
X33X
Vì vậy, X chỉ có một cách để giành chiến thắng:
XOOX
OO--
O-O-
X--X
Bố thí
OXXO
XX33
X3X3
O33O
Tình hình O
vẫn vô vọng. Bây giờ thật dễ dàng để thấy rằng mọi di chuyển đều cho phép X
giành chiến thắng ngay lập tức. Ít nhất hãy cố gắng đi trong 3 giờ liên tiếp:
OXXO
XX--
X-X-
O-OO
Tặng:
XOOX
OO13
O3O3
X3XX
X
đóng vai trò chiến thắng duy nhất (lưu ý rằng điều này thực hiện XXXO
dọc theo cột thứ ba:
XOOX
OOO-
O-O-
X-XX
Ở đây đầu ra là:
OXXO
XXX-
X-X-
O-OO
bởi vì trò chơi đã kết thúc Bạn có thể thấy chiến thắng trên cột thứ ba.
Chương trình thực tế 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)
Áp dụng cho bảng trống, điều này đánh giá các vị trí 9506699, mất 30Gb và 41 phút trên máy tính của tôi. Kết quả là:
2222
2222
2222
2222
Vì vậy, mọi di chuyển bắt đầu rút ra. Vì vậy, trò chơi là một trận hòa.
Việc sử dụng bộ nhớ cực đoan chủ yếu là do đệ quy sử dụng do$0
. Sử dụng phiên bản 154 byte này bằng chức năng đơn giản cần 3Gb và 11 phút:
#!/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
cái nào dễ chịu hơn (nhưng vẫn còn quá nhiều, thứ gì đó vẫn phải bị rò rỉ bộ nhớ).
Kết hợp một số tốc độ tăng tốc dẫn đến phiên bản 160 byte này (5028168 vị trí, 4 phút và 800M cho bảng trống):
#!/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
Cái cuối cùng đó sử dụng 0
cho một chiến thắng (đừng nhầm lẫn với O
), 1
cho một trận hòa và 2
thua. Đầu ra của cái này cũng khó hiểu hơn. Nó lấp đầy trong nước cờ chiến thắng cho X trong trường hợp thắng mà không đổi màu, nhưng nếu trò chơi đầu vào đã thắng thì vẫn là đổi màu và không điền vào bất kỳ động thái nào.
Tất cả các phiên bản tất nhiên sẽ nhanh hơn và sử dụng ít bộ nhớ hơn khi bảng đầy lên. Các phiên bản nhanh hơn sẽ tạo ra một động thái trong vòng dưới 10 giây ngay sau khi 2 hoặc 3 động tác được thực hiện.
Về nguyên tắc phiên bản 146 byte này cũng sẽ hoạt động:
#!/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)
nhưng trên máy của tôi, nó kích hoạt lỗi perl và bỏ lõi.
Về nguyên tắc, tất cả các phiên bản sẽ vẫn hoạt động nếu bộ nhớ đệm vị trí 6 byte được thực hiện bằng cách $$_||=
loại bỏ nhưng điều đó sử dụng rất nhiều thời gian và bộ nhớ mà nó chỉ hoạt động cho các bảng gần như đầy. Nhưng trên lý thuyết ít nhất tôi có một giải pháp 140 byte.
Nếu bạn đặt $\=
(chi phí: 3 byte) ngay trước $@<=>0
thì mỗi bảng đầu ra sẽ được theo sau bởi trạng thái của toàn bộ bảng: 1
cho X
thắng, 0
cho hòa và -1
thua.
Dưới đây là trình điều khiển tương tác dựa trên phiên bản nhanh nhất được đề cập ở trên. Trình điều khiển không có logic khi trò chơi kết thúc nên bạn phải tự dừng lại. Các mã golf biết mặc dù. Nếu di chuyển được đề xuất trở lại mà không bị -
thay thế bởi bất cứ điều gì, trò chơi kết thúc.
#!/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;
}