Perl, 147 bayt (rakip olmayan, hareket başına 10 saniyeden fazla sürer)
İçin +4 içerir -0p
Program çalıyor X. Mükemmel bir oyun oynayacak.
Kartı STDIN'e girin, örneğin:
tictaclatin.pl
-X-O
-X--
X-X-
O--O
^D
Çıkış, tümüyle Xdeğiştirilen tahta ile aynı olacaktır Ove tersi de geçerlidir. Boş noktalar, X'in orada oynayacağı sonucu gösteren bir sayı ile doldurulacaktır, 1yani sonuç bir galibiyet, 2beraberlik ve 3kayıp olacaktır. Bitmiş bir oyun, renkleri tersine çevirerek aynı pozisyonu döndürür.
Bu örnekte çıktı:
1O1X
1O33
O3O3
X33X
Bu yüzden pozisyon, Xüst ve sol boyunca 3 noktada oynarsa kazanır . Diğer tüm hamleler kaybeder.
Oyunun bir hamleden sonra nasıl devam ettiğini bilmek istiyorsanız, bu kafa karıştırıcı çıktı aslında kullanışlıdır. Program her zaman oynadığı Xiçin takas Xve Ohamle görmek gerekir O. Burada, örneğin Xsol üstte oynayarak kazandığı oldukça açıktır , ancak üstte Xüçüncü pozisyonda oynarsa ne olur ? Çıktıyı kopyalayın, Oseçtiğiniz hareketin yerine koyun ve diğer tüm sayıları -tekrar değiştirin , böylece burada:
-OOX
-O--
O-O-
X--X
Sonuçlanan:
3XXO
3X33
X3X3
O33O
Açıkçası her hamle Okaybetmeli, öyleyse sol üstte oynarsa nasıl kaybeder? Bunu tekrar Osol üst köşeye koyarak ve rakamları aşağıdaki gibi değiştirerek yapın -:
OXXO
-X--
X-X-
O--O
Giving:
XOOX
1O33
O3O3
X33X
X'in kazanması için tek bir yolu var:
XOOX
OO--
O-O-
X--X
verilmesi
OXXO
XX33
X3X3
O33O
Durum Oümitsiz kalıyor. Her hamlenin Xhemen kazanmasına izin verdiğini görmek artık çok kolay . En azından arka arkaya 3 O almaya çalışalım:
OXXO
XX--
X-X-
O-OO
Giving:
XOOX
OO13
O3O3
X3XX
Xtek kazanan hamleyi oynar ( XXXObunun üçüncü sütun boyunca yapıldığına dikkat edin :
XOOX
OOO-
O-O-
X-XX
İşte çıktı:
OXXO
XXX-
X-X-
O-OO
çünkü oyun çoktan bitmişti. Kazanımı üçüncü sütunda görebilirsiniz.
Gerçek program 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)
Boş panoya uygulandığında bu, bilgisayarımda 30Gb ve 41 dakika süren 9506699 pozisyonlarını değerlendirir. Sonuç:
2222
2222
2222
2222
Böylece her başlangıç hareketi çekilir. Yani oyun berabere bitiyor.
Aşırı bellek kullanımı çoğunlukla yinelenen kullanımdan kaynaklanır do$0. Bu 154 baytlık sürümü düz bir işlev kullanarak kullanmak için 3Gb ve 11 dakika gerekir:
#!/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
ki bu daha katlanılabilir (ama yine de çok fazla, bir şey hala bellek sızdırıyor olmalı).
Bir dizi hızlandırmayı birleştirmek, bu 160 baytlık sürüme yol açar (boş tahta için 5028168 konum, 4 dakika ve 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
Sonuncusu 0bir galibiyet (karıştırmayın O), 1beraberlik ve 2kayıp için kullanır. Bunun çıktısı da daha kafa karıştırıcı. Renk değişimi olmayan bir galibiyet durumunda X için kazanan hamleyi doldurur, ancak giriş oyunu zaten kazanılmışsa, renk değişimi hala devam eder ve herhangi bir hamleyi doldurmaz.
Tabii ki tüm versiyonlar hızlanır ve kart dolarken daha az bellek kullanır. Daha hızlı sürümler, 2 veya 3 hamle yapılır yapılmaz 10 saniyenin altında bir hamle üretmelidir.
Prensip olarak, bu 146 baytlık sürüm de çalışmalıdır:
#!/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)
ama benim makinede bir perl hata tetikler ve çekirdek dökümü.
İlke olarak yapılan 6 baytlık konum önbelleği $$_||=kaldırılırsa, ancak yalnızca neredeyse doldurulmuş kartlar için çalışacak kadar çok zaman ve bellek kullanırsa, tüm sürümler prensip olarak çalışmaya devam edecektir . Ama teoride en azından 140 baytlık bir çözümüm var.
Eğer koyarsanız $\=hemen önce: (3 bayt maliyet) $@<=>0: Daha sonra her çıkış kartı bütün kurulu durumuna göre takip edilecektir 1için Xgalibiyet, 0beraberlik için ve -1kayıp.
Yukarıda belirtilen en hızlı sürüme dayanan etkileşimli bir sürücü. Sürücünün oyun bittiğinde mantığı yoktur, bu yüzden kendinizi durdurmanız gerekir. Golfçü kodu olsa biliyor. Önerilen hamle, hiçbir -şeyle değiştirilmeden geri dönerse oyun biter.
#!/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;
}