Kelime arama bulmaca üretimi


13

Dizelerin bir listesi verildiğinde , ilk dizelerin her birini içeren en küçük kare matrisi bulun . Dizeler, bu soru Kelime Arama Bulmaca gibi yatay, dikey veya çapraz ve ileri veya geri görünebilir .

Kelimeler kareye, her yönde en az bir kelime olacak şekilde yerleştirilmelidir (yatay, dikey ve çapraz). Kelimeler sadece bir kez görünmelidir.

Yani, girdi sadece bir kelime listesidir. Örneğin: CAT, TRAIN, CUBE, BICYCLE. Olası bir çözüm:

B N * * * * *
* I * * C A T
* A C * * * *
* R * Y * * C
* T * * C * U
* * * * * L B
* * * * * * E

Sadece netlik için harfleri yıldızlarla değiştirdim. İstenen çıktı rastgele doldurma harflerini içermelidir.


Her kelime yalnızca bir konumda mı bulunmalıdır (tipik kelime aramaları gibi)? Örneğin, örneğinizde kalan harf öyleyse ACbaşka bir harf yapar . CATT
Geobits

" Kelimeler her yöne rastgele yerleştirilmelidir " ile tam olarak ne demek istediğinizi net değil . Sözcüğü belirleyici olarak ortaya koyduktan sonra, meydanın sekiz simetrisinden birini rastgele seçerse, bir cevap bu kriteri karşılar mıydı? Veya diğer uçta, çıktı kelimeleri içeren tüm olası en küçük karelerden eşit olarak mı seçilmelidir? Yoksa çizgi bu uçlar arasında bir yere mi çizilmiş?
Peter Taylor

Evet, yalnızca bir konumda bulunmalıdır.
Migue

1
Gerçekten değil, hayır. Bir yanıtın rastgele örneklemesinin hangi alanın ne olduğu ve bu alanın öğelerinin ağırlıklandırılmasında ne kadar esnekliğe izin verildiğini hala netleştiremiyorum.
Peter Taylor

1
Şu an itibariyle, sorunun çözülemeyen girdileri var, ancak bununla nasıl başa çıkmanız gerektiğinden bahsedilmiyor. Örneğin setin bir A B C D E F G H I J K L M N O P Q R S T U V W X Y Zçözümü yok.
orlp

Yanıtlar:


6

JavaScript (ES6), 595 628 680

Düzenle Bazı temizleme ve birleştirme:
- işlev P, R işlevi içinde birleştirildi
- aynı xmac içinde x ve z,
çözüm bulunduğunda, dış döngü
birleştirilmiş tanım ve W çağrısından çıkmak için x değerini 0 olarak ayarlayın .

Edit2 daha golf, rastgele dolgu kısaltılmış, dış döngü revize edildi ... daha okunabilir bir şey için geçmişe bakın

Kabul edilen cevabın aksine, bu çoğu girdi için işe yarayacaktır. Sadece tek harfli kelimelerden kaçının. Bir çıktı bulunursa, optimum ve 3 yönün hepsini kullanır.

Kelimeleri tekrar etmekten kaçınmak çok zor. Izgaraya kelime ekleyerek her adımda ve her rastgele doldurma karakterinde yinelenen kelime aramak zorunda kaldım.

Ana alt fonksiyonlar:

  • P (w) eğer palindrom kelimesi doğruysa. Tekrarlanan kelimeleri kontrol ederken iki kez bir palindrom kelime bulunur.

  • R (s) grid s üzerinde tekrar eden kelimeleri kontrol et

  • Q (s) ızgaraları rastgele karakterlerle doldurur - yinelenen sözcükler olması durumunda yinelemeli ve geriye doğru izler - ve başarısız olabilir.

  • W () özyinelemeli, mümkünse belirli bir boyuttaki ızgarayı doldurmaya çalışın.

Ana işlev, girişteki en uzun kelimenin boyutundan tüm kelimelerin uzunluğunun toplamına kadar bir çıkış ızgarası bulmak için W () kullanır.

F=l=>{
  for(z=Math.max(...l.map(w=>(w=w.length,x+=w,w),x=0));
      ++z<=x;
      (W=(k,s,m,w=l[k])=>w?s.some((a,p)=>!!a&&
            D.some((d,j,_,r=[...s],q=p-d)=>
              [...w].every(c=>r[q+=d]==c?c:r[q]==1?r[q]=c:0)
              &&R(r)&&W(k+1,r,m|1<<(j/2))
            )
          )
        :m>12&&Q(s)&&(console.log(''+s),z=x) 
      )(0,[...Array(z*z-z)+99].map((c,i)=>i%z?1:'\n'))
    )
    D=[~z,-~z,1-z,z-1,z,-z,1,-1]
    ,R=u=>!l.some(w=>u.map((a,p)=>a==w[0]&&D.map(d=>n+=[...w].every(c=>u[q+=d]==c,q=p-d)),
      n=~([...w]+''==[...w].reverse()))&&n>0)
    ,Q=(u,p=u.indexOf(1),r=[...'ABCDEFGHIJHLMNOPQRSTUVWXYZ'])=>
      ~p?r.some((v,c)=>(r[u[p]=r[j=0|c+Math.random()*(26-c)],j]=v,R(u)&&Q(u)))||(u[p]=1):1
    //,Q=u=>u.map((c,i,u)=>u[i]=c!=1?c:' ') // uncomment to avoid random fill
}

Açıklanmamış ve açıklanmış (eksik, üzgünüm çocuklar çok iş)

F=l=>
{
  var x, z, s, q, D, R, Q, W;
  // length of longest word in z
  z = Math.max( ... l.map(w => w.length))
  // sum of all words length in x
  x = 0;
  l.forEach(w => x += w.length);

  for(; ++z <= x; ) // test square size from z to x
  {
    // grid in s[], each row of len z + 1 newline as separator, plus leading and trailing newline
    // given z==offset between rows, total length of s is z*(z-1)+1
    // gridsize: 2, z:3, s.length: 7 
    // gridsize: 3, z:4, s.length: 13
    // ...
    // All empty, nonseparator cells, filled with 1, so
    // - valid cells have a truthy value (1 or string)
    // - invalid cells have falsy value ('\n' or undefined)
    s = Array(z*z-z+1).fill(1) 
    s = s.map((v,i) => i % z != 0 ? 1 : '\n');

    // offset for 8 directions 
    D = [z+1, -z-1, 1-z, z-1, z, -z, 1, -1]; // 4 diags, then 2 vertical, then 2 horizontal 

    // Function to check repeating words
    R = u => // return true if no repetition
      ! l.some( w => // for each word (exit early when true)
      {
          n = -1 -([...w]+''==[...w].reverse()); // counter starts at -1 or -2 if palindrome word
          u.forEach( (a, p) => // for each cell if grid 
          {
            if (a == [0]) // do check if cell == first letter of word, else next word
               D.forEach( d => // check all directions 
                 n += // word counter
                   [...w].every( c => // for each char in word, exit early if not equal
                     u[q += d] == c, // if word char == cell, continue to next cell using current offset
                     q = p-d  // starting position for cell
                   )
               ) // end for each direction
          } ) // end for each cell
          return n > 0 // if n>0 the word was found more than once
      } ) // end for each word

    // Recursive function to fill empty space with random chars
    // each call add a single char
    Q = 
    ( u, 
      p = u.indexOf(1), // position of first remaining empty cell 
      r = [...'ABCDEFGHIJHLMNOPQRSTUVWXYZ'] // char array to be random shuffled
    ) => {
      if (~p) // proceed if p >= 0
        return r.some((v,c)=>(r[u[p]=r[j=0|c+Math.random()*(26-c)],j]=v,R(u)&&Q(u)))||(u[p]=1)
      else 
        return 1; // when p < 0, no more empty cells, return 1 as true
    }
    // Main working function, recursive fill of grid          
    W = 
    ( k, // current word position in list
      s, // grid
      m, // bitmask with all directions used so far (8 H, 4V, 2 or 1 diag)
      w = l[k] // get current word
    ) => {
      var res = false
      if (w) { // if current word exists
        res = s.some((a,p)=>!!a&&
            D.some((d,j,_,r=[...s],q=p-d)=>
              [...w].every(c=>r[q+=d]==c?c:r[q]==1?r[q]=c:0)
              &&R(r)&&W(k+1,r,m|1<<(j/2))
            )
          )
      } 
      else 
      { // word list completed, check additional constraints
        if (m > 12 // m == 13, 14 or 15, means all directions used
            && Q(s) ) // try to fill with random, proceed if ok
        { // solution found !!
          console.log(''+s) // output grid
          z = x // z = x to stop outer loop
          res = x//return value non zero to stop recursion
        }
      }
      return res
    };
    W(0,s)
  }    
}

Firefox / FireBug konsolunda test edin

F (['TREN', 'KÜP', 'KUTU', 'BİSİKLET'])

,T,C,B,O,X,B,H,  
,H,R,U,H,L,I,H,  
,Y,A,A,B,E,C,B,  
,D,H,S,I,E,Y,I,  
,H,E,R,L,N,C,T,  
,G,S,T,Y,F,L,U,  
,H,U,Y,F,O,E,H,  

dolu değil

,T,C,B,O,X,B, ,
, ,R,U, , ,I, ,
, , ,A,B, ,C, ,
, , , ,I,E,Y, ,
, , , , ,N,C, ,
, , , , , ,L, ,
, , , , , ,E, ,

F (['TREN', 'SANATLAR', 'RAT', 'KÜP', 'KUTU', 'BİSİKLET', 'STORM', 'BEYİN', 'DERİNLİK', 'AĞZ', 'SLAB'])

,T,A,R,C,S,T,H,
,S,R,R,L,U,D,T,
,T,B,A,T,N,B,P,
,O,B,O,I,S,A,E,
,R,B,A,X,N,H,D,
,M,R,M,O,U,T,H,
,B,I,C,Y,C,L,E,

F ([AA ', 'AB', 'ac', 'MS', 'AE', 'AF', 'AG'])

,A,U,B,C,
,T,A,E,Z,
,C,D,O,F,
,Q,C,G,A,

F ([AA ', 'AB', 'ac', 'MS', 'AE', 'AF'])

çıktı dolu değil - @nathan: Artık tekrarlama olmadan başka bir A x ekleyemezsiniz . Daha büyük bir ızgaraya ihtiyacınız olacak.

,A, ,C,
, ,A,F,
,D,E,B,

Son test durumunuzda, 3x3 ızgarada mümkün değil mi?
Nathan Merrill

@NathanMerrill no. Cevap metninde daha fazla detay
edc65

tamamen okunamayan kod :) ama bayt / nokta "ödül" dezavantajı güzel bir insan derleyici olma
firephil

1
@firephil bir açıklama eklemeye çalışıyor, kolay değil ...
edc65

1

C #

İşte hala yapılması gereken işler ile basit bir uygulama. En küçük boyutu elde etmek için çok fazla kombinasyon var. Yani sadece kullanılan en basit algoritmayı düşünebiliriz.

class Tile
{
    public char C;
    public int X, Y;
}

class Grid
{
    List<Tile> tiles;

    public Grid()
    {
        tiles = new List<Tile>();
    }
    public int MaxX()
    {
        return tiles.Max(x => x.X);
    }
    public int MaxY()
    {
        return tiles.Max(x => x.Y);
    }
    public void AddWords(List<string> list)
    {
        int n = list.Count;
        for (int i = 0; i < n; i++)
        {
            string s = list[i];
            if(i==0)
            {
                Vert(s, 0, 0);
            }
            else if(i==n-1)
            {
                int my = MaxY();
                Diag(s, 0, my+1);
            }
            else
            {
                Horiz(s, 0, i);
            }
        }

    }
    private void Vert(string s, int x, int y)
    {
        for (int i = 0; i < s.Length; i++)
        {
            Tile t = new Tile();
            t.C = s[i];
            t.X = x+i;
            t.Y = y;
            tiles.Add(t);
        }
    }
    private void Horiz(string s, int x, int y)
    {
        for (int i = 0; i < s.Length; i++)
        {
            Tile t = new Tile();
            t.C = s[i];
            t.X = x+i;
            t.Y = y;
            tiles.Add(t);
        }
    }
    private void Diag(string s, int x, int y)
    {
        for (int i = 0; i < s.Length; i++)
        {
            Tile t = new Tile();
            t.C = s[i];
            t.X = x++;
            t.Y = y++;
            tiles.Add(t);
        }
    }
    public void Print()
    {
        int mx = this.MaxX();
        int my = this.MaxY();
        int S = Math.Max(mx, my) + 1;
        char[,] grid = new char[S, S];
        Random r = new Random(DateTime.Now.Millisecond);
        //fill random chars
        for (int i = 0; i < S; i++)
        {
            for (int j = 0; j < S; j++)
            {
                grid[i, j] = (char)(r.Next() % 26 + 'A');
            }
        }
        //fill words
        tiles.ForEach(t => grid[t.X, t.Y] = t.C);
        //print
        for (int i = 0; i < S; i++)
        {
            for (int j = 0; j < S; j++)
            {
                Console.Write("{0} ", grid[i,j]);
            }
            Console.WriteLine();
        }
    }
}

class WordSearch
{
    public static void Generate(List<string>list)
    {
        list.Sort((x, y) =>
        { int s = 0; if (x.Length < y.Length)s = -1; else if (y.Length < x.Length)s = 1; return s; });
        list.Reverse();
        Grid g = new Grid();
        g.AddWords(list);
        g.Print();
    }

}

Ölçek

class Program
{
    static void Main(string[] args)
    {
        string words = "CAT, TRAIN, CUBE, BICYCLE";
        string comma=",";
        List<string> w = words.Split(comma.ToArray()).ToList();
        List<string> t = new List<string>();
        foreach(string s in w)
        {
           t.Add(s.Trim());
        }
        WordSearch.Generate(t);

        Console.ReadKey();
    }
}

çalışır fakat optimal değildir: örnek dize kelimeleri = "CAT, DOG, HR, RUN, CMD";
firephil

Rasgele doldurma karakterlerinin ızgarada bir sözcüğün tekrarlanmasına neden olup olmadığını kontrol ediyor musunuz?
edc65

-1 Denedim. Özellikleri takip etmez at least one word in each direction (horizontal, vertical and diagonal). Test programını çalıştırma, yatay kelime yok (3 dikey, 1 diag)
edc65

3
Bu soru kod golf , bu yüzden başlıkta kaç bayt yayınlamanız ve muhtemelen programınızı bir demet kısaltmanız gerekir. Teşekkürler.
mbomb007

@ edc65 Bir dikey, bir diyagonal ve diğerleri yatay yapar. Mükemmel bir çözüm elde etmek için yorum yaptığım gibi, sorunun yanı sıra kontrol etmek için çok sayıda kombinasyon gerektirecektir.
bacchusbeale
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.