Haçlar, Noughts yok


10

Herkes Tic Tac Toe'nun çözülmüş bir oyun olduğunu fark eder . Bununla birlikte, sadece X'lerin Misère versiyonu ilginç bir alternatif sunuyor.

Oyunun bu versiyonunda, her iki oyuncu da tahtaya Xs oynar ve arka arkaya üç yapmaktan kaçınır. Bununla ilgili daha fazla şey görmek isterseniz, Numberphile'ın bu konsept hakkında güzel bir videosu var.

Bir Misère Crosses kurulu göz önüne alındığında, optimal bir hamle yapın.

Bir tahta, her biri üç karakterli üç satırdır, Xya da . Böylece:

X X
X  
 XX

geçerli bir kurul. Girdiniz ve çıktınız aynı biçimi kullandığı sürece bunu uygun bir biçimde alabilirsiniz. Biçimler şunları içerir (ancak bunlarla sınırlı değildir): Çok satırlı bir dize (isteğe bağlı son satırsonu ile); XVeya olan bir 2B karakter dizisi ; her bir pozisyonun oynatılıp oynatılmadığını temsil eden 1D düzleştirilmiş bir boole değerleri dizisi.

Optimum hareket, en iyi şekilde oynamaya devam ederek kazanacağınızı garanti eden veya kaybınızı mümkün olduğunca uzun süre uzatan ve aşağıdaki kurallarla tanımlanan bir harekettir:

  • Arka arkaya üç yapmaktan kaçının.
  • Önce gidersen, ortada oyna.
  • Tek işgal edilen alan ortasa, kalan alanlardan herhangi birinde oynayın.
  • Orta kare dolu değilse ve bir dış kare varsa, rakibinizin son oyununun karşısında oynayın.
  • Orta kare dolu ve dış kare ise, kaybetmenize neden olmayan bir önceki hamleden uzakta bir "şövalye hamlesi" (zıt, bir üstte) oynayın.
  • Kaybetmeyeceğiniz yerde kalan kareler kalmazsa, kalan karelerden herhangi birinde oynayın.

[NOT: bunun bir durumda optimal olmadığı kanıtlanmıştır, ancak yine de bu algoritmayı kullanmalısınız.]

Önceki tüm hareketlerinizin en uygun olduğunu varsayabilirsiniz. Dolayısıyla, ilk örnek panosu geçerli bir girdi değildir. Rakibinizin hamleleri optimum olabilir veya olmayabilir.

Oyun sona erdiyse (yani arka arkaya üç tane yapılmışsa), davranış tanımsızdır.

Bu olduğundan, bayttaki en kısa cevap kazanır!

Sadece optimal hareketleri kullanan olası bir yol şudur:

[   ]  [   ]  [X  ]  [X  ]  [X  ]  [X  ]  [XX ]
[   ]->[ X ]->[ X ]->[ XX]->[ XX]->[ XX]->[ XX]
[   ]  [   ]  [   ]  [   ]  [ X ]  [XX ]  [XX ]

En uygun olmayan hareketleri kullanarak rakipten gelen olası girişler şunlardır:
(Bu listedeki yalnızca sol taraftaki kartların geçerli girişler olduğunu unutmayın.)

[X  ]  [X  ]
[   ]->[   ]
[   ]  [  X]

[XX ]  [XX ]
[   ]->[   ]
[  X]  [ XX]

[XX ]  [XX ]
[X  ]->[X X]
[ XX]  [ XX]


Giriş ve çıkış formatları nelerdir? Bir dizi veya dize olarak alınan bir tahta varsayalım? Ancak bu son hamleyle ilgili bilgi vermiyor, dolayısıyla bir sonraki sorum.
Level River St

1
"Rakibinizin son oyununun karşısında oynayın" stratejisi, ya rakibinizin hareket geçmişi hakkında bilgi sahibi olduğunu ya da daha önce bu stratejiyi izlediğinizi, örneğin, örneğin bir tahta devralmadığını varsayar .XX\nX..\nX... Bunun gibi panoları devralmayı düşünmeli miyiz?
Level River St

@LevelRiverSt Yazıldığı gibi, "Önceki tüm hareketlerinizin en uygun olduğunu varsayabilirsiniz", böylece kart geçersiz giriş olur. İstediğiniz formatta girdi alabilirsiniz, ancak örneğiniz gibi çok satırlı bir dize "varsayılan" olurdu: Ben sadece hareket mantığı noktası Dize ayrıştırmak zorunda kimse kısıtlamak istemiyorum meydan okuma.
CAD97

Yanıtlar:


3

Ruby, Rev B 121 bayt

Gönderme, eksi f=. Kullanımı göstermek için test programında gösterilmiştir.

f=->n{["~mK)\7","}uYwQO"][l=n%2].bytes{|t|9.times{|i|(m=n|1<<i)==n||8.times{|j|m/2*257>>j&255==126-t&&t+j%2!=119&&l=m}}}
l}

puts g=f[gets.to_i]
puts
[7,6,5,
 8,0,4,
 1,2,3].each{|i|print g>>i&1; puts if i/3==1}

Merkez kareyi en önemli bit yerine en küçük anlamlı bit yaparak ( /2yerine kaldırmak %256) 2 bayt tasarruf etti. Toplam X sayısı yerine merkez kare serbest / dolu olarak organize etmek daha basit bir test yapılmasını sağlar. Ayrıca, dizide sadece 2 dize vardır, böylece %w{string1 string2}sözdizimi sözdizimi lehine terk edilir ["string1","string2"]. Bu, yazdırılamayan bir karakterin \7eklenmesini sağlar ve bu da daha basit bir kodlamanın kullanılmasını sağlar: 126-tyerine (36-t)%120.

Ruby, Rev A 143 bayt

->n{l=r=("%b"%n).sum%8
%w{$ %5 - I+Wy Q S#}[r].bytes{|t|9.times{|i|(m=n|1<<i)==n||8.times{|j|m%256*257>>j&255==(t-36)%120&&t+j%2!=43&&l=m}}}
l}

Bu anonim bir işlevdir. Giriş / çıkış formatı açık bırakıldı, bu yüzden 9-bit ikili sayı için gittim. 512 biti merkezi temsil eder, kalan bitler etrafına döner (1 biti bir köşe olarak kabul edilir).

Kabul edilebilir çıkışlardan çok daha fazla giriş vardır, bu nedenle algoritma tüm hareketleri denemek ve kabul edilebilir bir çıkış modeline uyan bir giriş bulmaktır. Her bir X sayısı için kabul edilebilir çıktı modelleri sabit kodlanmıştır.

Merkez kareyle ilgili bilgiler çıkarılır ve kalan 8 bit, kopyaları çoğaltmak için 257 ile çarpılır. Bu kalıp daha sonra hak değiştirerek kabul edilebilir kalıpların ötesine döndürülür.

Bir örüntü bulunduğunda döngüden çıkılmaz, bu nedenle döndürülen örüntü LAST kabul edilebilir örüntü olur. Bu nedenle, tercih edilen modeller (bir tercihin olduğu yerlerde) listenin ilerleyen kısımlarında gelir.

'Şövalyeler hareketi' stratejisi göz önüne alındığında, bir desenin 45 derece döndürülüp döndürülmemesi çok az önemlidir. Çözümsüz versiyon şövalyelerin hareket stratejisini takip eder ve bu nedenle köşe kareleri ve kenar kareleri arasında ayrım yapmak zorunda değildir: yine de arka arkaya üçten kaçınılmalıdır.

Ancak, aşağıdaki hile olduğu için bunun her zaman en iyi strateji olmadığını buldum. Rakibiniz önce giderse ve merkezi alırsa kazanmalıdır. Ancak ikinci hamlesinde, 2x2 kare yapmanıza izin verme hatasını yapar, çünkü onu arka arkaya üç yapmaya zorlamanıza izin verir. Bu, golf versiyonunda uygulanır. Bir köşedeki üç X'i (rakibi kaybetmeye zorlamak) ve bir kenar boyunca 3 X'i (hemen intihar) ayırt etmek için bu örnekte biraz ekstra kod gereklidir.

Test programında yönlendirilmemiş

Çözülmemiş versiyon, soruda ifade edilen mantığı takip eder.

Golf edilmiş versiyonda tablo, [[0],[1,17],[9],[37,7,51,85],[45],[47,119]]durum için biraz farklı davranışları uygulamak üzere biraz değiştirilmiştir r=3. Daha sonra yazdırılabilir ASCII'ye sıkıştırılır (kod çözme gerektirir (t-36)%120). Tablo girişi 7 durumunda bir köşedeki üç X ile bir kenar boyunca üç X arasında ayrım yapmak için ek bir mantık gerekir:&&t+j%2!=43

f=->n{l=r=("%b"%n).sum%8                                      #convert input to text, take character checksum to count 1's(ASCII 49.) 
                                                              #0 is ASCII 48, so %8 removes unwanted checksum bloat of 48 per char.
                                                              #l must be initialised here for scoping reasons.
  [[0],[1,17],[9],[11,13,37,51,85],[45],[47,119]][r].each{|t| #according to r, find the list of acceptable perimeter bitmaps, and search for a solution.
    9.times{|i|(m=n|1<<i)==n||                                #OR 1<<i with input. if result == n, existing X overwritten, no good.
                                                              #ELSE new X is in vacant square, good. So.. 
      8.times{|j|m%256*257>>j&255==t&&l=m}}                   #%256 to strip off middle square. *257 to duplicate bitmap.
                                                              #rightshift, see if pattern matches t. If so, write to l
  }
l}                                                            #return l (the last acceptable solution found) as the answer.

#call function and pretty print output (not part of submission)
puts g=f[gets.to_i]
puts
[6,7,0,
 5,8,1,
4,3,2].each{|i|print g>>i&1; puts if i<3}

Test programının çıktısı

Bilgisayar kendini oynattığında olan budur.

C: \ Kullanıcılar \ steve> ruby ​​tictac.rb
0
256

000
010
000

C: \ Kullanıcılar \ steve> ruby ​​tictac.rb
256
384

010
010
000

C: \ Kullanıcılar \ steve> ruby ​​tictac.rb
384
400

010
010
100

C: \ Kullanıcılar \ steve> ruby ​​tictac.rb
400
404

010
010
101

C: \ Kullanıcılar \ steve> ruby ​​tictac.rb
404
436

010
110
101

C: \ Kullanıcılar \ steve> ruby ​​tictac.rb
436
444

010
110
111

İLK OYUN ANALİZİ

Bu aslında çok basit ve doğrusal.

İlk oynarken, orta kare daima işgal edilen ilk kare olacaktır.

r = 0

...  binary representation 0
.X.
...

r = 2

X..  binary representation 1001=9 
.XX
...

r = 4

X.. binary representation 101101=45
.XX
XX.

Oyun bitmeden tahtadaki orta kareyi içeren beş X'e sahip olmanın tek bir yolu (simetriye kadar) vardır. Orta karede X, her biri çapraz (biri 90 derece) ve yatay / dikey her biri (90 derece birbirine). Bir kenarın tamamı işgal edilemediğinden, düzenleme mümkündür. Diğer oyuncu bir sonraki hamlede kaybetmelidir.

İKİNCİ OYNANAN OYUN ANALİZİ

Oyun diğer oyuncunun orta kareyi seçmesine bağlı olarak oldukça farklıdır.

r = 1

orta meydan işgal edildi

.X. X..  binary representation 1 
.X. .X.
... ...

orta kare ücretsiz

X.. .X. binary representation 10001=17
... ...
..X .X.

r = 3

Diğer oyuncu son X'inize bitişik oynarsa, ortadaki kare işgal edilir.

XX. .XX binary representation 1011=11 
.X. XX. or mirror image 1101=13
X.. ...

Ancak, yukarıdaki en iyi hareket değildir ve golf versiyonunda desteklenmez. En iyi hamle aşağıdaki gibi bir sonraki turda kazanmayı zorlar:

XX. binary representation 111=7.           XXX
XX. Only to be used where j is odd.        .X.
... Even j would look like image to right. ...

Diğer oyuncu son X'inize 90 veya 135 derece oynarsa orta şövalye işgal edilir (şövalyenin hamlesini oynayın.)

X.X .X. binary representation 100101=37 
.X. .XX
.X. X..

Orta kare serbest

X.X .X. XX. binary representations:
... X.X ...    1010101=85 (first two)
X.X .X. .XX and 110011=51 (last one)

r = 5

orta kare işgal etti. Yukarıda r = 4'te belirtilen nedenlerden dolayı, hepsi kaybedilen dört olası hareket vardır. sadece bir tanesi desteklenir: 101111 = 47.

orta kare ücretsiz. Aşağıdaki gibi simetriye kadar sadece bir olası kart vardır. Diğer oyuncu bir sonraki hamlede kaybetmelidir, bu yüzden r> 5'i desteklemeye gerek yoktur.

XX. binary representation 1110111=119
X.X
.XX

Bu harika bir cevap! Tüm vakaları en uygun moe için kontrol ettiğimi sanıyordum, ama sanırım birini özledim. Teknik özellikler basitlik için aynı kalacak. (Bu gerçekten bunu yaptığınız için teşekkür ederim ve bu çok iyi açıklandı! G / Ç kaybını bıraktım, böylece insanlar böyle inanılmaz bir şey yapabilirler.)
CAD97

1
Teşekkürler, ilginç bir meydan okumaydı. Şimdi biraz daha golf yapmayı başardım.
Level River St
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.