Bir Rubik Küpünü veri yapısında nasıl temsil edersiniz?


58

Bir Rubik Küpünü simüle etmeye çalışacak olursam , küpün durumunu hafızada saklamak için, her bir tarafta X karo sayısıyla nasıl bir veri yapısı oluşturabilirsiniz?

Düşünülmesi gereken şeyler:

  • küp herhangi bir boyutta olabilir
  • Bir Rubik küpüdür, böylece katmanlar döndürülebilir

2
Ev ödevi? Ya da gerçek dünya sorunu ...
sdg,

4
Rubik Küp Çözücü kaynak koduyla ilgileniyor olabilirsiniz .
mouviciel

22
Ben iki tarafın bir küpün 6 numaralı olmalıdır eminim
Simon Bergot

3
Tüm tarafları aynı anda görebilmem için Rubik Küp'ün düzleştirilmiş bir modelini görmek isterdim. Hmm, onu şimdi yazmaya cazip geliyorum. Bir T'nin şekli olabilir veya mümkünse sonsuz bir şekilde döşenebilir (ikincisini düşünmedim).
Lee Kowalkowski

6
Ben Eric Evans alıntı cazip hissedebilirsiniz (o bellekten çağırılır alıntı muhtemelen% 100 doğru olarak) "Modeller ya da yanlış, ne doğru Onlar sadece az ya da çok yararlıdır."
Pete

Yanıtlar:


37

Eski düz boyuttaki bir dizinin nesi var [6X][X]? Sen hakkında bilmek gerekmez Bunları görmüyorum, çünkü mini küpler; onlar küpün bir parçası değiller. Güzel görünümlü ve kullanımı kolay bir arayüzün arkasındaki iki çirkin yöntemi gizleyin, birimi ölüme test edin ve işte bitirin!


31
Gerçek bir Rubik küpünde bile mini küp yoktur
jk.

8
Bu işe yarayacak, ancak algoritmanız bu kadar basit bir veri yapısına uyum sağlamak için muhtemelen oldukça karmaşık olacaktır.
maple_shaft

6
As long as you know how the six surfaces are "threaded" together Hangi tam olarak daha sağlam bir veri yapısının size vereceği şeydir. Bence aynı şeyi tartışıyoruz. Bir dizi kenarları ve bir taraf bir blok dizisidir, ancak taraflar ve bloklar hakkında "iş parçacığı" nı anlamaya yardımcı olan pek çok ilginç özellik vardır . )
maple_shaft

7
@maple_shaft "Tam olarak daha güçlü bir veri yapısının size vereceği şey budur." Bunu bilmiyorum: onun için daha fazla "yapı" olan bir veri yapısı mutlaka o yapının tekil kısımlarının kurulması, sürdürülmesi ve erişilmesi ile ilgili ek tesadüfi bir karmaşıklığa neden olacaktır . Neyin daha karmaşık olacağını söylemek zor - bazı köşe kasalarıyla düz bir dizide çirkin kaymalar ve bireysel hücrelere erişimde "serbest sürüş" veya biraz daha az karmaşık kaymalar ve biraz daha karmaşık okumalara sahip bir yapı uygulamak.
dasblinkenlight

16
Bir Rubik Küpünü manipüle etmek için programlar yazmış biri olarak, yüze bir tane olmak üzere altı adet iki boyutlu diziyi kullanma basit bir yaklaşım kullandım. Küp üzerinde biraz can sıkıcı olan bazı temel işlemleri uygulamanız gerektiği doğru, ancak bundan sonra temsili unutmaktan özgürsünüz. Benim için hiçbir zaman sorun olmadı. Diğer temsillerin performans perspektifinden nasıl işleyeceğini sık sık merak ediyordum, ancak kodlama perspektifinden hiç bir zaman yüklenmediğini hissettim.
PeterAllenWebb

39

Çok hevesli bir sürat olduğumu belirtmeliyim, fakat bir Rubik küpünü bir algoritma veya veri yapısında programlı olarak göstermeyi hiç denemedim.

Muhtemelen bir küpteki her bir bloğun benzersiz yönlerini yakalamak için ayrı veri yapıları yaratacağım.

Bir küp üzerinde 3 farklı tip blok vardır:

  1. Köşe Bloğu - Herhangi bir zamanda bir tarafı paylaşacağı üç renkli yüze ve üç bitişik parçaya sahiptir.

  2. Kenar Bloğu - İki renkli yüze sahiptir ve herhangi bir zamanda bir tarafını paylaşacağı 4 bitişik parçaya sahiptir. 3x3 bloklarda her zaman 2 merkez parçası ve 2 köşe parçası bulunur.

  3. Merkez blok - 3x3'lük bir küpte bu parça hareketli değildir, ancak döndürülebilir. Her zaman 4 bitişik kenar bloğu olacaktır. Daha büyük küplerde, başka bir merkez bloğu veya bir uç parçası ile paylaşılabilecek çok sayıda merkez bloğu vardır. Orta bloklar asla bir köşe bloğuna bitişik değildir.

Bunu bilerek, bir Blok dokunduğu diğer bloklara bir referans listesine sahip olabilir. Tek bir küp yüzünü temsil eden blokların listesi ve her küp yüzüne referansları tutan bir liste olacak başka bir liste listesini tutardım.

Her küp yüzü benzersiz bir yüz olarak temsil edilir.

Bu veri yapılarıyla, her blokta dönme dönüşümü yapan bir algoritma yazmak, uygun blokları uygun listelerin içine ve dışına taşımak oldukça kolay olacaktır.

EDIT: Önemli not, bu listeler elbette sipariş edilmelidir, ancak bunu belirtmeyi unuttum. Örneğin, eğer sağ tarafı çevirirsem, o zaman sol köşe sağ taraf bloğu sağ tarafın sağ köşesine hareket eder ve saat yönünde döndürülür.


Her bloğun benzersiz özelliklere sahip olması gerektiğine katılıyorum. ancak dönüşüm sıkıcı olmaz çünkü referansları bitişik bloklara ve sizinkilere güncellemek zorundasınız list of lists. belki sadece sorgulayabileceğiniz sıralanmamış bir blok listesine sahip olmak daha iyidir. ve dönüşüm gerçekleştirirken bitişik blok referanslarını güncellemeniz yeterlidir. Bir yüzdeki tüm blokların bir listesini istiyorsanız, o zaman tüm bitişik bloklar için listenizi ortadaki bloklara sorgulayabilirsiniz, değil mi?
Mel

@Mel Her iki şekilde de yapmak mümkün, ancak dasblinkenlight ile konuştuktan sonra yaklaşımının daha az karmaşık olacağını düşünüyorum. Cevabının benimkinden daha fazla oy almasını diliyorum. Algoritmalar ve en verimli olanlarla o kadar iyi değilim, sadece rubik küplerini seviyorum ve onları topladım (dünyanın her yerinden 40'dan fazla çeşit).
maple_shaft

Her ne kadar dasblinknenlight cevabı ben cevap böyle bir veri yapısı için gerekli olacaktır mantık bazılarını içerir gerçeğini ve farklı blok özelliklerini sevdiğim için basit çözüm, sana ödül ödüllendirme ediyorum
Rachel

Bu veri modeli gerçeğe göre daha doğrudur, ancak olması gerekenden daha zor yapmak istediğiniz basit işlemlerden bazılarını yapar - Sadece küpün durumunu elde etmek, hantal olan hantal bir liste halinde dolaşmayı gerektirir.
Ziv

@ Ziv Doğru, ancak soru veri yapısını soruyordu ve algoritmalar hakkında mutlaka değil.
maple_shaft

13

Bu problemi düşündüğümde, bilinen desenlerde renkleri üzerinde hareket eden statik bir küp düşünüyorum. Yani....

Bir Cube nesnesi, 0-5 dizine sabitlenmiş kalan 6 Yan nesne içerir. Her iki taraf da, 0-8 arasında dizine alınmış sabit kalan 9 konum nesnesi içerir. Her pozisyonda bir renk bulunur.

Basit olması için her işlemi çeyrek tur artışlarla gerçekleştirin. Küp üzerinde toplam 6 olası hareket için her biri 2 yönde olmak üzere 3 dönüş ekseni vardır. Bu bilgilerle, küp üzerindeki 6 olası eylemi belirlemek oldukça basit bir görev haline gelir.

Bu nedenle, 6. pozisyondaki yeşil renk, 3. pozisyon, alınan eyleme bağlı olarak diğerlerinin yanı sıra 1. veya 3. konuma 2. veya 7. konuma hareket edebilir. Bunu herhangi bir matematiksel çeviri bulmak için yeterince araştırmadım, ancak muhtemelen kodda yararlanabileceğiniz kalıplar ortaya çıkacaktır.

Veri yapısını kullanarak, belirli bir durumda belirli bir küpün çözülebilir olup olmadığını nasıl bilebilirim? Bu soru ile kendim mücadele ediyorum ve henüz cevabı bulamadım.

Bunu yapmak için, asla rastgele bir küp durumu ile başlamayın. Bunun yerine, çözülmüş bir durumla başlayın ve küpü rastgele bir başlangıç ​​durumuna getirmek için programlı olarak n eylemleri gerçekleştirin . Mevcut duruma ulaşmak için yalnızca yasal işlemlerde bulunduğunuzdan, küpün çözülebilir olması gerekir.


1
Klasik "buradan başlamak istemiyorsunuz" tavsiyesi!
Ergwun

8

Bir xyz koordinat sistemini bir Rubik küpüne hitap etmenin basit bir yolu buldum ve rotasyon matrislerini rotasyonları uygulamanın basit, jenerik bir yolu olarak buldum.

Bir pozisyon vektörü içeren bir Parça sınıfı yarattım (x, y, z). Bir Parça, konumuna bir matris matrisi uygulanarak döndürülebilir (bir matris-vektör çarpımı). Parça ayrıca renklerini bir demet halinde tutar (cx, cy, cz)ve renkleri her bir eksen boyunca bakacak şekilde verir. Mantık bir miktar bu renkler bir rotasyon sırasında uygun güncellenmektedir sağlar: XY düzleminde 90 derece rotasyonu değerlerini takas anlamına geliyor cxve cy.

Tüm dönme mantığının Parça sınıfında kapsüllenmesi nedeniyle, Küp sırasız bir Adet listesi saklayabilir ve rotasyonlar genel bir şekilde yapılabilir. Sol yüzün bir dönüşünü yapmak için, -1'i x koordinatına sahip tüm parçaları seçin ve her bir Parçaya uygun dönüş matrisini uygulayın. Küpün tamamını döndürmek için her parçaya aynı döndürme matrisini uygulayın.

Bu uygulama basittir ve birkaç güzelliğe sahiptir:

  1. Bir Parça nesnesinin konumu değişecektir, ancak renkleri değişmez. Bu, kırmızı-yeşil parçayı sorabileceğiniz, nesneye asabileceğiniz, bazı döndürmeler yapabileceğiniz ve kırmızı-yeşil parçanın nerede bittiğini görmek için aynı nesneyi kontrol edebileceğiniz anlamına gelir.
  2. Her bir Parçanın türü (kenar, merkez, köşe) benzersiz bir koordinat düzenine sahiptir. 3x3 küp için, bir köşe parçasının konum vektöründe ( (-1, 1, 1)) sıfır yoktur , bir kenar tam olarak bir sıfıra ( (1, 0, -1)) sahiptir ve bir orta parça iki sıfıra ( (-1, 0, 0)) sahiptir.
  3. 3x3 küp için çalışan rotasyon matrisleri bir NxN küpü için çalışacaktır.

Downsides:

  1. Matris-vektör çarpımı, dizilerdeki takas değerlerinden daha yavaştır.
  2. Parçalı konuma göre doğrusal zaman aramaları Pieces'ı harici bir veri yapısında saklamanız ve sabit zamanlı aramalar için pozisyona göre rotasyonlar sırasında güncellemeniz gerekir. Bu, rotasyon matrislerini kullanma zerafetinin bir kısmını yitirir ve Rotasyon mantığını Cube sınıfınıza katar. Herhangi bir tür arama tabanlı çözme algosu uyguluyor olsaydım, başka bir uygulama kullanırdım.
  3. Örüntü analizi (çözme sırasında) olabileceği kadar hoş değildir. Bir Parça, bitişik Parçalar hakkında hiçbir bilgiye sahip değildir ve yukarıdaki performans sorunları nedeniyle analiz yavaş olacaktır.

3
Bu tür bir uygulamanın, küpü bir 3B grafik programında temsil etmek için en iyi sonucu bulduğunu gördüm. Matris çarpımı, katman dönüşlerini canlandırmayı mümkün kılar. Bu yaklaşımın örnek bir uygulaması için bu github deposuna bakınız . 3D küpüme bir çözücü eklemek için, diğer cevaplardan birinden bir algoritmaya ve veri yapısına ihtiyacım olacağını düşünüyorum.
Jonathan Wilson

5

Basit bir dizi (yüzdeki bir kareye 1 ila 1 eşlemesi olan her öğe) kullanabilir ve her dönüşü belirli bir permütasyonla simüle edebilirsiniz.

Sadece 3 temel permütasyondan kurtulabilirsiniz: ön yüzü olsa ekseni olan bir dilimi döndürün, küpü dikey eksen çevresinde döndürün ve küpü sol ve sağ yüzlerden yatay eksen üzerinde döndürün. diğer tüm hareketler bu üçünün bir araya getirilmesiyle ifade edilebilir.

Bir küpün çözülebilir olup olmadığını bilmenin en basit yolu, onu çözmek (küpü çözecek bir dizi permütasyon bulmak), eğer değiştirilen bir yere, tek bir döndürülmüş kenara, tek bir döndürülmüş köşeye veya 2 değiştirilebilen köşe, çözülemeyen bir küpünüz var


1
the most straightforward way of know whether a cube is solvable is to solve it. Evet, önerdiğin modeli kullanarak sanırım bu doğru. Ancak @ maple_shaft'ınkine daha yakın bir model kullanırsanız ve rota dönüşlerini izlerseniz, mod 2'nin kenar kliplerinin toplamının 0 ve köşe dönüşlerinin mod 3'ün 0 olduğunu doğrulayarak çözülebilir olup olmadığını hızlı bir şekilde test edebilirsiniz. Kenar değişim ve köşe değişim (geri çözülmesi için gerekli) sayma, toplam mod 2 0 (toplam eşitlik bile) olmalıdır. Bunlar, küpün çözülebilir olduğunu kanıtlamak için gerekli ve yeterli testlerdir.
jimhark

3

Çözülebilir olması gereken birinci koşul, her bir parçanın mevcut olması ve her bir parçadaki renklerin "kıvrılmış" bir küpü bir araya getirmek için kullanılması olabilir. Bu, gerçeği basit bir kontrol listesi ile belirlenebilecek göreceli bir durumdur. "Standart" bir küp üzerindeki renk şeması tanımlanır , ancak standart küple başa çıkmasanız bile sadece 6 tane olur! çözülmüş yüzlerin olası kombinasyonları.

Tüm parçaları ve renkleri doğru seçtikten sonra, herhangi bir fiziksel konfigürasyonun çözülebilir olup olmadığını belirlemek bir konudur. Hepsi değil. Bunu kontrol etmenin en saf yolu, bir küp çözme algoritması çalıştırmak ve çözülmüş bir küple sonlandırıp sonlandırmadığını görmek. Küpü çözmeye çalışmadan çözülebilirliği belirlemek için fantezi birleştirme teknikleri olup olmadığını bilmiyorum.

Hangi veri yapısına gelince, bu önemli değil. İşin zor kısmı dönüşümleri doğru yapmak ve küp durumunu literatürde uygun algoritmalar ile düzgünce çalışmanıza izin verecek şekilde gösterebilmek. Maple-şaftın belirttiği gibi, üç çeşit parça vardır. Rubik küpü çözme üzerine literatür her zaman türlerine göre parçaları ifade eder. Dönüşümler de ortak yollarla temsil edilir ( Singmaster notasyonuna bakınız ). Ayrıca, gördüğüm tüm çözümler her zaman bir parçaya referans noktası olarak atıfta bulunur (genellikle beyaz merkez parçayı aşağıya yerleştirir).


1
2. nokta için, rastgele bir küp ile başlamak ve çözülebilir olup olmadığını kontrol etmek yerine. Çözülmüş bir küp ile başlar ve rastgele bir duruma getirmek için küp üzerinde rasgele eylemler gerçekleştirirdim.
Matthew Vines,

Evet, kesinlikle, fiziksel olarak çözülmesi mümkün bir konfigürasyon oluşturmanın en basit yoludur. İsteğe bağlı bir konfigürasyon ile başlamak ve çözülebilir olup olmadığını belirlemek kesinlikle ayrı ama ilgili bir sorundur.
Angelo,

2
Bir küpün çözülebilen bir olup olmadığını belirlemek için “fantezi teknikler” olabileceğini varsayıyorsunuz; aslında var. Bir küpü söküp çıkartmaları tutarsanız ve sonra küpü tekrar monte ederseniz, mutlaka çözülebilen bir küp almazsınız; Aslında, çözülebilir bir küpün olması ihtimaline karşı yüzde on ikide bir oran var. Kenarların ve köşelerin eşlik analizi yoluyla çözülebilir bir durumda olup olmadığınızı belirleyebilirsiniz ; aslında küpü çözmeye çalışmak zorunda değilsin.
Eric Lippert

1
İşte küpün çözülebilir olması için korunması gereken üç tür küp eşleştirme özelliğine kısa bir genel bakış. ryanheise.com/cube/cube_laws.html .
Eric Lippert

1
Bu soruyu maç yığını
Mel

3

Harika cevaplar aldığına göre, sadece bir ayrıntı ekleyeyim.

Somut temsilinizden bağımsız olarak, lenslerin bir küpün çeşitli kısımlarını "yakınlaştırmak" için çok iyi bir araç olduğunu unutmayın . Örneğin, işlevi bakmak cycleLeftiçinde bu Haskell kodu . Herhangi bir uzunluk 4 listesine döngüsel olarak izin veren genel bir fonksiyondur. L hareketini gerçekleştirme kodu şöyle görünür:

moveL :: Aut (RubiksCube a)
moveL =
    cong cube $ cong leftCols cycleLeft
              . cong leftSide rotateSideCW

Böylece tarafından verilen görünümdecycleLeft çalışır . Benzer şekilde, döndürülmüş bir versiyonunun bir tarafını alan genel bir fonksiyon olan, tarafından verilen görünümde çalışır . Diğer hamleler benzer şekillerde uygulanabilir. leftColsrotateSideCWleftSide

Haskell kütüphanesinin amacı güzel resimler oluşturmak. Bence başardı: Diyagramlar-rubiks-küp kütüphanesi iş başında


2

İki ayrı soru soruyor gibisin.

  1. X sayısı ile bir küp nasıl gösterilir?

Gerçek dünya Rubic küpünü taklit edecekseniz, tüm Rubik küplerinin 6 tarafı vardır. Bence demek istediğin "her taraftaki boyut başına X kiremit sayısı". Orijinal Rubic'in küpünün her iki tarafı 3x3'tür. Diğer boyutlar arasında 4x4 (Profesörün Küpü), 5x5 ve 6x6 sayılabilir.

"Standart" küp çözme notasyonunu kullanarak verileri 6 tarafla temsil ederdim:

  • ÖN: çözücüye bakan yüz
  • GERİ
  • SAĞ
  • AYRILDI
  • YUKARI
  • AŞAĞI

Her bir taraf, X'e göre 2 boyutlu bir X dizisidir.


17x17 küp satın alabilirsiniz ! Bazı mekanik uzlaşmaları var, ama gerçek olana izomorfik.
RBerteig

1

@Maple_shaft fikrini farklı parçaları (mini küpler) farklı şekilde temsil etme fikrini seviyorum: merkezi, kenar ve köşe parçaları sırasıyla 1, 2 veya 3 renk taşır.

Aralarındaki ilişkileri, bitişik parçaları birleştiren kenarları olan (iki yönlü) bir grafik olarak temsil ederdim. Her parçada kenarlar için bir dizi yuva (bağlantılar) bulunur: merkezi parçalarda 4 yuva, kenar parçalarda 4 yuva, köşe parçalarında 3 yuva. Alternatif olarak, merkez parçaların kenar parçalarına 4 bağlantı ve ayrı ayrı köşe parçaları için 4 bağlantıya sahip olabilir ve / veya kenar parçalarının merkez parçalara 2 bağlantı ve 2 ayrı ayrı köşe parçalarına sahip olabilir.

Bu diziler, grafik kenarları yineleyen her zaman 'aynı' dönüşü temsil eden, küpün dönüşünü modulo edecek şekilde sıralanır. Yani, örneğin bir merkez parçası için, küpü yüzü üstte olacak şekilde döndürürseniz, bağlantıların sırası her zaman saat yönündedir. Benzer şekilde kenar ve köşe parçaları için. Bu özellik yüz rotasyonlarından sonra (ya da şimdi bana öyle geliyor gibi) tutuyor.

  • Bir kenara ait parçaları bulmak önemsizdir.
  • Bir yüze ait parçaları bulmak önemsizdir.
  • Verilen yüze veya karşı bir yüze verilen yüzleri bulmak, 2 veya 3 adet iyi tanımlanmış bağlantıdan geçer.
  • Bir yüzü döndürmek için yüzün orta parçasına bağlı tüm parçaların bağlantılarını güncelleyin.

Açıkça çözülemeyen koşulların (değiştirilmiş / çevrilmiş kenarlar, değiştirilmiş köşe) tespiti, umarım da kolaydır, çünkü belirli tipte parçaları bulmak ve oryantasyonu basittir.


1

Düğümler ve işaretçiler nasıl?

Her zaman 6 yüz olduğunu varsayalım ve 1 düğüm 1 yüzde 1 kareyi temsil eder:

r , g , b
r , g , b
r , g , b
|   |   |
r , g , b - r , g , b
r , g , b - r , g , b
r , g , b - r , g , b

Bir düğümün yanındaki her düğüme bir işaretçi vardır. Bir daire dönüşü yalnızca işaretçiyi (düğüm sayısı / yüz sayısı) -1 düğümün üzerinden geçirir, bu durumda 2. Tüm dönüşler daire dönüşü olduğundan, yalnızca bir rotateişlev oluşturun. Her bir düğümü bir boşluk hareket ettirmek ve onları yeterince hareket edip etmediğini kontrol etmek yinelemelidir, çünkü düğüm sayısı toplanacaktır ve her zaman dört yüz vardır. Değilse, taşınan değerin sayısını artırın ve tekrar arama döndürün.

İki kat bağlantılı olduğunu unutmayın, bu nedenle yeni sivri uçlu düğümleri de güncelleyin. Her zaman her düğümde bir işaretçi bulunan Yükseklik * Genişlik düğüm sayısı taşınacak, bu yüzden Yükseklik * Genişlik * 2 işaretçi sayısı güncellendi.

Tüm düğümler birbirlerine işaret ettiğinden, siz geldikçe her düğümü güncelleyerek dairenin etrafında dolaşın.

Bu, kenar kutusu veya karmaşık mantık olmadan, herhangi bir boyutta küp için çalışmalıdır. Bu sadece bir işaretçi yürüyüş / güncelleme.


-1

Kişisel deneyimden küpün her bir dönme parçasını takip etmek için bir set kullanmak iyi sonuç verir. Her bir alt küp üç sette olup rubik küpün büyüklüğünü göstermez. Yani bir alt küp bulmak için bir kısmı rubik küpünde üç kümenin kesişme noktasını alırsınız (sonuç bir alt küptür). Bir hareket yapmak için etkilenen alt yavruları harekete dahil olan kümelerden çıkarın ve sonra onları hareketin bir sonucu olarak alan kümelere geri koyun.

4 x 4 küp 12 set olacaktır. 6 yüz için 6 set ve küpün etrafındaki altı grup için 6 set. Yüzlerin her birinin 16 alt küpü vardır ve bantların her birinin 12 alt küpü vardır. Toplam 56 alt küp bulunmaktadır. Her alt küp, renk ve renklerin yönü hakkında bilgi tutar. Rubik küpünün kendisi, her bir elemanın, bu konumdaki alt küpü tanımlayan 3 kümeden oluşan bilgilere sahip olan bir 4'e 4 dizisidir.

Diğer 11 cevaptan farklı olarak, bu veri yapısı küpteki her bir alt blok konumunu tanımlamak için setlerin kesişimini kullanıyor. Bu, bir değişiklik yapıldığında yakındaki alt blokları güncellemek zorunda kalmanızı sağlar.


Bu, önceki 11
cevapta
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.