Nim tahtasını uzman gibi görselleştirin


10

Arka fon

In Nim oyununun her turda, bir oyuncu, bir gelen bir ve bütün taşlar arasında kaldırmak gerekir: oyuncular "kazıkların" dan "taş" çıkarmadan dönüşümlü tek kazık. Nim'in amacı son taşı almak veya yanlış varyantta rakibinizi bunu yapmaya zorlamaktır - ancak stratejilerin neredeyse aynı olduğu ortaya çıkıyor.

Nim eğlenceli bir bar oyunu yapar. "Taşlar" için kibrit çubukları veya madeni paralar kullanabilirsiniz ve "kazıklar" genellikle bir çizgi halinde düzenlenmiştir. Aşağıda 1, 3, 5 ve 7 yığınlarıyla klasik bir kurulum var:

kibrit çöpü ile nim

Daha önce hiç Nim oynamadıysanız, bu mücadeleyi denemeden önce elinizi deneyebilirsiniz. İşte "Domuzdan Önce İnciler" adlı bir versiyon .

strateji

Nim'deki en uygun strateji, sıradan insanların çoğunun bir uzmana sürekli olarak kaybetmesi, ancak ikili aritmetik ile tanımlanması basittir .

Bununla birlikte, zihinsel ikili XOR operasyonları yapmak zordur, bu yüzden neyse ki, sarhoş olsa bile, gerçek zamanlı olarak uygulanması daha kolay olan doğru stratejiyi görselleştirmenin eşdeğer bir yolu vardır.

Sadece üç adım vardır:

  1. Zihinsel olarak, her bir satırdaki "taşları", boyutları mümkün olan en büyük boyuttan başlayarak 2 gücü olan alt gruplara ayırın: 8, 4, 2 ve 1 çoğu oyun için yeterlidir.
  2. Her grubu başka bir satırdaki bir ikizle eşleştirmeye çalışın, böylece her grubun bir çifti olur.
  3. Bu mümkün değilse, eşleştirilmemiş "taşları" tek bir satırdan kaldırın (bu her zaman mümkün olacaktır - neden için Wikipedia bağlantısına bakın), böylece 2. adım mümkün olur.

Ya da başka bir yol: "Kazıkları 2'lik güçlere gruplandırırsanız, tüm gruplar başka bir yığındaki bir grupla eşleştirilebilecek şekilde, tek bir kazıktan bazı taşları çıkarın." 2'den büyük güçleri daha küçük güçlere ayıramayacağınız uyarı ile - örneğin, 8 taşlı bir çizgiyi 4'lü iki gruba ayıramazsınız.

Örneğin, yukarıdaki tabloyu nasıl görselleştireceğiniz aşağıda açıklanmıştır:

dengeli kibrit çöpleri

Bu tahta mükemmel dengelidir, bu yüzden önce rakibinizin hareket etmesini istersiniz.

Meydan okuma

Nim "yığınlarının" boyutunu temsil eden pozitif tamsayıların bir listesi göz önüne alındığında, bir uzman tarafından görüldüğü gibi Nim panosunun düz metin görselleştirmesini döndürün.

Geçerli bir görselleştirmeyi neyin oluşturduğu en iyi örnekle açıklanmaktadır, ancak şunları yapmanız gerekir:

  1. Her "2'nin gücü alt grubuna" ve çiftine (eşleştirilmemiş alt gruplar uygun değildir) ayrı bir karakter atayın ve bu karakteri hem alt grupta hem de çiftte "taşları" temsil etmek için kullanın.
  2. Herhangi eşleşmemiş "taş" Temsil (yani normal oynarken bir uzman ortadan kaldıracaktır olanlar - değil misere - Nim) tire kullanarak: -.

Geçerli bir görselleştirme elde etmenin birden çok yolu olacaktır ve hepsi geçerlidir. Bazı test senaryoları üzerinde çalışalım:

Test Durumları

Giriş: 1, 3, 5, 7

Olası Çıktı 1:

A
BBA
CCCCD
CCCCBBD

İsteğe bağlı olarak karakterler arasında boşlukların yanı sıra satırlar arasında boş satırlar ekleyebilirsiniz:

Olası Çıktı 2:

A

B B A

C C C C D

C C C C B B D

Giriş: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10

Karakterlerin sırası ve seçimi istediğiniz gibi olabilir:

Olası Çıktı 1:

G
E E
E E G
C C C C
C C C C F
B B B B D D
B B B B D D F
H H I - - - - -
A A A A A A A A I
A A A A A A A A H H

Unicode sembolleri de uygundur:

Olası Çıktı 2:

◎
◈  ◈
◈  ◈  ◎
△  △  △  △
△  △  △  △  ◉
◐  ◐  ◐  ◐  ◀  ◀
◐  ◐  ◐  ◐  ◀  ◀  ◉
▽  ▽  ◒  -  -  -  -  -
▥  ▥  ▥  ▥  ▥  ▥  ▥  ▥  ◒ 
▥  ▥  ▥  ▥  ▥  ▥  ▥  ▥  ▽  ▽  

Giriş: 7

Kurallardan, herhangi bir "tek yığın" ın tamamen kaldırılması gerektiği izlenir.

Olası Çıktı 1:

-------

Olası Çıktı 2:

- - - - - - -

Giriş: 5, 5

Olası Çıktı:

A A A A B
A A A A B

Ek Kurallar

  • Bu standart kurallar ile kod golf. En kısa kod kazanır.
  • Girdi esnektir ve sizin için uygun olan liste biçiminde alınabilir.
  • Yukarıdaki örneklerde gösterildiği gibi çıktı da esnektir. En makul değişikliklere izin verilecektir. Bir şeyden emin olup olmadığınızı sorun.

1
Her yığının kaç taş içerebileceği veya görselleştirme için kaç farklı karakterin gerekli olacağı konusunda bir sınır var mı? (Aşırı durumda, örneğin, yazdırılabilir ASCII karakter sayısından daha fazlasına veya 255'ten fazla farklı karaktere ihtiyaç duyulursa ne olur?)
Kapı tokmağı

@Doorknob Bunun olmayacağını varsayabilirsiniz. Alfabedeki harflerin herhangi bir giriş için yeterli olacağını varsayabilirsiniz.
Jonah

@Jonah bu ikinci test senaryosu için geçerli bir çıktı olur mu? ["H","EE","EEH","CCCC","CCCCI","DDDDFF","DDDDFFI","AAAAAAAA","AAAAAAAA-","----------"]
ngn

1
@ Οurous Bence basit cevap evet. Teknik AAAABBBBolarak aslında geçersiz ve ABBdeğil - ama daha az okunabilir hale getirir, bu yüzden sadece bir çizgi içinde azaltma açık bir kural en iyisi olduğunu düşünüyorum.
Jonah

1
@JonathanAllan Evet, her 3 adımın da aynı anda gerçekleşmesi mantığına güveniyorum. Dolayısıyla, 1. ve 2. adımları gerçekleştirir, ancak 3. adımı gerçekleştiremezseniz, çözümünüzü 1. ve 2. adımlara ayarlamanız gerekir. Bu da kafa karıştırıcı olduğunu görebilirim. Açıklamanızı aşağıya ekledim.
Jonah

Yanıtlar:


2

Yakut, 169 164 148 bayt

->a{s=eval a*?^
c=?@
m={}
a.map{|x|z=x-(x^s);[$><<?-*z,x-=z,s=0]if z>0
n=1
eval'x&1>0?[$><<(m[n]||c.next!)*n,m[n]=!m[n]&&c*1]:0;n*=2;x/=2;'*x
puts}}

Çevrimiçi deneyin!

İlk olarak,

  • nim-sum s=eval a*?^(ile daha kısadır a.reduce:^)
  • ckullanılmayan ilk benzersiz karakteri saklayan değişken
  • miki uzunluğun gücünü, onları temsil etmek için kullanılan karakterlerle eşleyen bir harita

Sonra, her kazık üzerinde döngü, biz aşağıdaki çalıştırın:

z=x-(x^s);[$><<?-*z,x-=z,s=0]if z>0

Başına Wikipedia'nın stratejisi ise, nim-sum XOR kazık az olduğu kazık , biz uzunluğu olur, öyle ki o kazık taşların atılıp gerektiğini nim-sum XOR kazık . Değişkendeki farkı saklayarak, zbu farkın pozitif olup olmadığını test edebiliriz ve eğer öyleyse 1.) birçok tireyi yazdırın, 2.) yığından çıkarın ve 3.) nim-sum değişkenini daha fazla taş çıkarılmasını önlemek için sıfır.

n=1
eval'[...];n*=2;x/=2;'*x

Şimdi üzerindeki her bir bit "döngü" ve tekrar tekrar bölerek değerlerini takip xile 2ve akümülatörü çarparak ntarafından 2. Döngü aslında x, gerekli olduğu zamanlardan çok daha büyük bir dize olarak değerlendirilen sürelerdir log2(x), ancak hiçbir zarar verilmez (verimsizliğin yanı sıra). Her bit için, bit 1 ( x&1>0) ise aşağıdakileri çalıştırırız :

$><<(m[n]||c.next!)*n

Bir karakter nkez yazdırın . Bu taşların eşleşmemiş bir grubunu zaten yazdırdıysak, o karakteri kullanın; aksi takdirde, kullanılmayan bir sonraki karakteri kullanın ( cnedeniyle yerinde ilerleme !).

m[n]=!m[n]&&c*1

Varsa m[n](yani bir çifti tamamladık), m[n]sıfırlanır. Aksi takdirde, yeni bir çift başlattık, bu yüzden m[n]kullandığımız karaktere ayarlandı ( *1bir kopyasını oluşturmanın kısa bir yoludur c).


4

Piton 2 , 150 196 206 bayt

def f(p):
 c=48;s=[l*'.'for l in p];m=2**len(bin(l))
 while m:
  if sum(m*'.'in l for l in s)>1:
   for i,l in enumerate(s):s[i]=l.replace('.'*m,chr(c)*m,`s`.count(chr(c)*m)<2)
   c+=1
  else:m/=2
 return s

Çevrimiçi deneyin!


Bunun işe yaradığını sanmıyorum 4, 9, 10.
Neil

@Neil Nice catch, şimdi düzeltilmelidir
TFeld

1
Üzgünüm, bu sefer tekrar kandırmayı başardım 14, 21, 35.
Neil

Ayrıca, ikinci yığının tamamını kaldırması gereken [1, 3, 4, 5] için başarısız olur.
Kapı tokmağı

@Doorknob, Bu gerekli mi? Kurallar söylüyorThere will be multiple ways to achieve a valid visualization, and all are valid
TFeld

1

JavaScript (ES6), 215 bayt

f=
(a,c=0,x=eval(a.join`^`),i=a.findIndex(e=>(e^x)<e),b=a.map(_=>``),g=e=>(d=e&-e)&&a.map((e,i)=>e&d&&(a[i]-=d,b[i]=(c++>>1).toString(36).repeat(d)+b[i]))&&g(e-d))=>g(eval(a.join`|`),b[i]='-'.repeat(a[i]-(a[i]^=x)))||b
<textarea oninput=o.textContent=/\d/.test(this.value)?f(this.value.match(/\d+/g)).join`\n`:``></textarea><pre id=o>

En fazla 36 farklı karakteri görüntüler. Bunun için rahatladım 1, 3, 4, 5.


Gerçekten hoş. Gerçek zamanlı olarak oynamak eğlenceli.
Jonah

1

Temiz , 454 bayt

hala golf oynuyor

import StdEnv,Text,Data.List
$p=join"\n"[{#toChar c+'-'\\c<-e}\\e<-[take i(e++[0,0..])\\e<-r[[~c\\c<-reverse e,_<-[1..c]]\\e<-hd[q\\q<-foldr(\h t=[[a:b]\\a<-h,b<-t])[[]][[c\\c<-subsequences(takeWhile((>=)k)(iterate((*)2)1))|sum c<=k]\\k<-p]|sum[1\\a<-q&b<-p|sum a<>b]<2&&foldr(bitxor)0(flatten q)==0]]1&i<-p]]
r[]_=[]
r[h:t]n|all((<)0)h=[h:r t n]
#[m:_]=removeDup[e\\e<-h|e<0]
#(a,[x:b])=span(all((<>)m))t
=r([[if(e==m)n e\\e<-k]\\k<-[h:a]++[x]]++b)(n+1)

Çevrimiçi deneyin!

$ :: [Int] -> StringKazık boyutlarını alarak ve -kaldırılacak taşların belirtildiği bir dize döndürerek işlevi tanımlar ve gruplar, yükselen ASCII karakterleriyle temsil edilir -. Yeterli gruba ihtiyaç duyulursa, karakterler sonunda geri döner ve bu foldrnedenle ikinci test senaryosunu çalıştırmak için bir gigabayttan fazla bellek gerektirir.

Dev kavrayışın girintili versiyonu:

$p=join"\n"[
    {#
        toChar c+'-'
        \\c<-j
    }
    \\j<-[
        take i(e++[0,0..])
        \\e<-r[
            [
                ~c
                \\c<-reverse e
                ,_<-[1..c]
            ]
            \\e<-hd[
                q
                \\q<-foldr(\h t=[
                    [a:b]
                    \\a<-h
                    ,b<-t
                ])[[]][
                    [
                        c
                        \\c<-subsequences(takeWhile((>=)k)(iterate((*)2)1))
                        |sum c<=k
                    ]
                    \\k<-p
                ]
                |sum[
                    1
                    \\a<-q
                    &b<-p
                    |sum a<>b
                ]<2&&foldr(bitxor)0(flatten q)==0
            ]
        ]1
        &i<-p
    ]
]

Sadece merak ediyorum, Clean haskell'e benziyor ... Haskell'e göre avantajları neler?
Jonah

1
@Jonah Oldukça benzer, evet. Başımın üst kısmında, daha düşük seviyeli tip manipülasyonu, satır içi IL / Assembly ve C ile birlikte çalışma Haskell'den daha kolay elde edildi. Bununla birlikte, gerçek kullanım için, Clean'in belirsizliği ve deneysel / akademik doğası nedeniyle, Haskell'i (kütüphaneler ve referans bilgileri açısından daha fazla desteği olan) tavsiye ederim. Clean'in hepsini sevmesini istiyorum.
0:17
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.