Geçerli kelimeleri bir karakter ızgarasında nasıl bulabilirim?


12

Tetris'e benzer bir oyun yaratıyorum, iki ana fark var: ekran zaten fayanslarla dolu (Nintendo DS ve PC için Puzzle Quest gibi) ve her bir karonun içinde bir harf var. Oyuncunun amacı, onlarla geçerli kelimeler oluşturarak karoları ortadan kaldırmaktır. Kelimeler, diyagonal olarak herhangi bir yönde, yan yana harfler yerleştirilerek oluşturulur.

Oyuncu, bir karo sırasının tamamını sola veya sağa veya tüm karo sütununu yukarı veya aşağı, istediği kadar boşluk taşıyabilir (bir sıranın / sütunun hareketi tahtanın sınırlarını aşarsa, sınırı geçen harf satır / sütunun diğer ucunda görünen "döngü" yapar). Oyuncunun eyleminden sonra, oyun geçerli kelimeleri aramak için tüm tahtayı kontrol etmeli ve bu kelimeleri oluşturan harfleri tahtadan kaldırmalıdır. Kaldırılan harflerin üzerindeki harfler, kaldırılan harflerin yerine düşer ve kart tekrar dolana kadar ekranın üstünden yeni harfler düşer.

Zaten karakter dizisi verildiğinde, geçerli bir İngilizce kelime olup olmadığını belirleyen doğrusal bir algoritma yazdım. Yaşadığım sorun: tahtadaki geçerli kelimeleri nasıl kontrol edebilirim? Kaba kuvvet tek yol mu? Küçük (5x5) bir tahta için bile geçerli olup olmadığını görmek için tüm olası kombinasyonları tahtadan test etmek çok yavaştır. Herhangi bir yardım çok takdir edilecektir, teşekkürler!


Maalesef haklısın. Sayılar nedeniyle çok yavaştır (tüm 3, 4, 5, ... 25 harf kombinasyonları). Belki performansı artırmak için "kelimeler yatay veya dikey olarak sıralanmalıdır" ile sınırlandırın (ve oyuncunun görmediği rastgele kelimeler alamayın)?
ashes999

Bence tekrar tekrar karakter dizisini kelimelere uyan algoritmanıza bakmanız gerekiyor. Sayımla, 5x5'lik bir ızgarada, algoritmanızın patlaması gereken 2700 potansiyel kelime bulunur, bkz. Josh'un cevabı.
Taemyr

2700 kelimeye şu şekilde ulaşıyorum; ilk satırda soldan sağa sözcüklerle başlayın. 5 harfli kelime, 2 4 harfli kelime, 3 3 harfli kelime, 4 2 harfli kelime ve 5 1 harfli kelime olmak üzere 1 pozisyon bulunmaktadır. Kelimedeki harflerden birini başka bir sütundan bir harfle değiştirebiliriz. Genelliği kaybetmeden, 1 harfli kelime için hiçbir harfin değiştirilmediğini ve ilk harfin 2 harfli kelime ile değiştirilmediğini varsayabiliriz. Bu; 5 x 5 x 1 + 4 * 5 * 2 + 3 * 5 * 3 + 1 x 5 x 4 + 1 = 135. Satır ve yön sayısı ile çarpın; 135 * 5 * 4 = 2700
Taemyr

Sanırım bunu netleştirmedim, ancak kelimeler çapraz olarak hariç herhangi bir yönde oluşturulabilir ve hatta köşeler bile (örneğin, ilk satırdan ilk karo, ardından ilk satırda sağa ikinci karo, ardından kiremit ikinci satırda aşağıdan).
Tavio

@Tavio Bazı düşünceler: kontrol ilk önce daha uzun kelimeler gitmelidir (eğer "istemiyorum" olarak "bir kenara" yaparsam) Ayrıca, tek harfli kelimeler göz ardı edilebilir daha iyi, aksi takdirde asla a's kullanmak mümkün olmayacaktır. İşiniz bittiğinde, bu oyunu verdiğiniz adı bilmek istiyorum, böylece kontrol edebilirim
David Starkey

Yanıtlar:


22

Kaba kuvvet tek yol değildir.

Oyun tahtanızı çözmek , daha basit dışında bir Boggle tahtasını çözmeye benzer . Tahtadaki her döşemeyi kontrol etmek, uygun yönlerde yapılabilecek herhangi bir kelime olup olmadığını görmek istiyorsunuz.

Arama alanınızı daha da hassaslaştırmak istersiniz, böylece bir kelime yapamayacağınızı biliyorsanız bir yön boyunca arama yapmaktan rahatsız olmazsınız. Örneğin, qarka arkaya iki s bulursanız , iptal etmeniz gerekir. Bu amaçla, belirli bir karakter kümesinin geçerli bir sözcüğün öneki olup olmadığını söylemenizi sağlayan bir tür veri yapısı isteyeceksiniz. Bunun için bir trie veya önek ağacı kullanabilirsiniz; böyle problemleri çözerken faydalı bir veri yapısı.

Bir önek ağacı, her düğümün çocuklarının bazı öneklerini temsil ettiği ve yaprak düğümlerinin (genellikle) son değerleri temsil ettiği hiyerarşik düğüm tabanlı bir yapıdır. Örneğin, geçerli kelimeler sözlüğünüz "kedi", "araba" ve "hücre" içeriyorsa, bir üçlü şu şekilde görünebilir:

    0        The root of the trie is the empty string here, although you 
    |        can implement the structure differently if you want.
    c
   / \ 
  a   e
 / \   \
t  r    l
         \
          l

Bu nedenle, oyununuzdaki her geçerli kelimeyle bir önek ağacı doldurarak başlayın.

Herhangi bir zamanda tahtada geçerli kelimeleri bulma işlemi, tahtadaki her bir döşemeden özyinelemeli bir aramanın başlatılmasını içerecektir. Belirli bir döşemeden başlayan tahta alanı boyunca yapılan her arama bağımsız olduğu için, bunlar gerektiğinde paralelleştirilebilir. Arama yaparken, önek ağacını, aradığınız yöndeki harfin değerine göre "izlersiniz".

Sonunda, çevredeki harflerin hiçbirinin geçerli önek ağacı düğümünüzün alt öğesi olmadığı bir noktaya ulaşacaksınız. Bu noktaya geldiğinizde, geçerli düğümün bir yaprak olduğu da doğruysa, geçerli bir sözcük buldunuz. Aksi takdirde geçerli bir kelime bulamadınız ve aramayı iptal edebilirsiniz.

Örnek kod ve bu tekniğin bir tartışması (ve bir modadan sonra arama alanını "tersine çevirerek daha da hızlı olabilen dinamik bir programlama çözümü gibi) bu arkadaşın blogunda bulunabilir ; Boggle'ı çözmeyi tartışıyor, ancak çözümleri oyununuza uyarlamak, aramanın hangi yönde gerçekleşmesine izin verdiğinizi değiştirme konusudur.


Kaba kuvvet, sizin açıkladığınız gibi değil. :) Bakmaya devam etmenin bir anlamı olmadığını ima eden birçok önek var. (Çoğu [rastgele] dizge kelime değildir. +1
AturSams

Mükemmel cevap. Bir "kelime" oyunun sözlük durağında bir şeydir.
Adam Eberbach

OP kelimeyi bir karakter dizesiyle eşleştirmek için bir algoritmaya sahip olduğunu belirtir. Bu yüzden soruyu cevapladığını sanmıyorum.
Taemyr

OTOH Bence OP şu anda sahip olduğundan daha verimli bir dize eşleştirme algoritması isteyecektir.
Taemyr

1
@Taemyr düz trie kullanıyor, evet. Ancak biraz değiştirilmiş üçgeni kullanan Aho-Corasick algoritması çok daha etkili (doğrusal) olabilir. Aho-Corasick algoritması ile nxn matrisindeki tüm geçerli kelimeler O (n ^ 2) zamanında bulunabilir.
el.pescado

3

Bunu denemiş olabilirsiniz, bunu zaten uygulamış olabilirsiniz, belki de başka bir cevap, vb. İle birlikte daha iyi olabilir.

Nelerin değiştiğini ve nelerin değişmediğini takip ederek birçok kontrolü atabilirsiniz. Örneğin:

On a 5x5 field, A vertical word is found on base of the third column,
All the rows change. However, the first, second, fourth, and fifth,
columns do not change, so you dont need to worry about them (the third did change.)

On a 5x5 field, A 3 letter word is found horizontally on row 2, column 3, to column 5.
So you need to check row 1 and 2 (row 1 because the words on that one
fell down and where replaced), as-well as columns 3, 4, and 5.

veya psudo kodunda

// update the board

// and check
if (vertical_word)
{
    check(updated_column)

    for (i in range 0 to updated_row_base)
        check(i)
}
else // horizontal word
{
    for (i in range 0 to updated_row)
        check(i)

    for (i in range 0 to updated_column_start)
        check(i)

    for (i in range updated_column_end+1 to final_column)
        check(i)
}

Ve önemsiz sorular:

Derleyici hız optimizasyonlarını ayarladınız mı? (eğer kullanıyorsanız)

Kelime arama algoritmanız hiç optimize edilebilir mi? Herhangi bir şekilde?


Oyuncuların satırları döndürmelerine izin verilmedikçe, üçüncü sütunda bir kelime bulmak diğer sütunları etkileyecektir.
Taemyr

@Taemyr IF(rowMoved){ checkColumns(); checkMovedRow(); } IF(columnMoved){ checkRows() checkMovedColumn();} Bir kullanıcı aynı anda yalnızca bir tanesini taşıyabiliyorsa, o hareketin sonunda paralel harfler hareket etmediği için bunları yeniden kontrol etmeye gerek yoktur.
David Starkey

2

Her karakterin bir değer olduğunu unutmayın. Yani bunu kendi yararınıza kullanın. Alt dizelerde yinelendiğinde hızlı bir şekilde hesaplanabilen bazı karma işlevler vardır. Örneğin, her harfe 5 bitlik bir kod verdiğimizi varsayalım (sadece c - 'a' + 1C ile yapın):

space = 00000;
a = 00001;
c = 00011;
e = 00101;
t = 01100;

Bundan sonra, belirli bir boyuttaki tüm alt dizeleri hızla çalıştırabilirsiniz:

a b [c a t] e t h e = 00011 00001 01100;
//Now we just remove the 5 msb and shfit the rest 5 bits left and add the new character.
a b  c [a t e] t h e = (([c a t] & 0xffff) << 5) | e; // == a t e

Bugün en yaygın mimarilerde bu şekilde 12 harfe kadar alt dizeleri kontrol edebiliriz.

Sözlüğünüzde bir karma kodu varsa, oradan hızlı bir şekilde kelime çekebilirsiniz, bunun gibi karma kodlar benzersizdir. En fazla 12 harfe ulaştığınızda, bu 12 harften başlayan kelimeler için başka bir veri yapısı eklemek isteyebilirsiniz. Belirli bir 12 harfle başlayan bir kelime bulursanız, bu önekle başlayan her kelimenin sonekleri için bir liste veya başka bir küçük karma tablo oluşturun.

Mevcut tüm kelime kodlarının bir sözlüğünün saklanması birkaç megabayttan fazla bellek gerektirmemelidir.


0

Kelimeler oluştururken sadece klasik Tetris şekilleri ile sınırlı mısınız yoksa herhangi bir oluşum olur mu? Kelimeler süresiz veya sadece bir kez bükülebilir mi? Bir kelime istediği kadar uzun olabilir mi? İstediğiniz kadar bükme yapabiliyorsanız, 25 karakter uzunluğunda mümkün olan en uzun kelimeleri etkili bir şekilde yapabiliyorsanız, bu oldukça karmaşıktır. Kabul edilen kelimelerin bir listesine sahip olduğunuzu varsayarım. Bu varsayımda şöyle bir şey denemenizi öneririm:

At the start of the game:
  Iterate tiles:
    Use tile as starting letter
      Store previous tile
      Check the four adjacent tiles
      If a tile can continue a word started by the previous tile, carry on
      Store the next tile
      Move check to next tile

Bu, her döşemede, bu döşemenin ızgaradaki etrafındaki kelimelere nasıl bağlandığını gösteren bir harita oluşturur. Bir sütun veya satır taşındığında, harekete bitişik olan veya hareketin yanındaki tüm döşemeleri kontrol edin ve bilgileri yeniden hesaplayın. Bir kelime bulduğunuzda ve o kelimeye başka fayans eklenemez; onu kaldır. Bunun daha hızlı olup olmayacağından emin değilim, gerçekten kaç tane kelimenin yaratıldığına bağlı. Bunun yararı, kullanıcının büyük olasılıkla tahtadaki yarım tam kelimeden bir kelime oluşturmaya çalışmasıdır. Tüm bu kelimeleri saklayarak, bir kelimenin tamamlanıp tamamlanmadığını kontrol etmek kolaydır.

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.