Слово пошуку покоління головоломки


13

Давши список рядків, знайдіть найменшу квадратну матрицю, яка містить кожен з початкових рядків. Рядки можуть відображатися горизонтально, вертикально або по діагоналі і вперед або назад, як у цьому питанні Puzzle Word Search .

Слова повинні бути розміщені у квадраті, принаймні по одному слову в кожному напрямку (горизонтальному, вертикальному та діагональному). Слова повинні з’являтися лише один раз.

Отже, вхід - це лише список слів. Наприклад: CAT, TRAIN, CUBE, BICYCLE. Одне можливе рішення:

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

Я замінив заповнення листів зірочками просто для наочності. Бажаний вихід повинен включати випадкові заповнення літер.


Чи повинно кожне слово знаходитись лише в одній позиції (як типові пошуки слів)? Наприклад, лист, залишений ACу вашому прикладі, зробить інше, CATякщо воно є T.
Геобіт

Мені не зрозуміло, що саме ви маєте на увазі під " Словами слід розміщувати випадковим чином у всіх напрямках ". Чи відповідає відповідь цьому критерію, якщо, детерміновано виклавши слова, він випадковим чином вибирає одну з восьми симетрій квадрата? Або, з іншого боку, чи слід вибирати вихід рівномірно з усіх можливих найменших квадратів, які містять слова? Або лінія намальована десь між цими крайнощами?
Пітер Тейлор

Так, його слід знаходити лише в одному положенні.
Міге

1
Не дуже, ні. Мені все ще не зрозуміло, яким є простір, з якого відповідь має бути випадковим чином, а також скільки гнучкості дозволено у зважуванні елементів цього простору.
Пітер Тейлор

1
На сьогодні питання має вхідні дані, які неможливо вирішити, але не згадується, як ви повинні з цим боротися. Наприклад, набір 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не має рішення.
orlp

Відповіді:


6

JavaScript (ES6), 595 628 680

Відредагуйте деяке очищення та об'єднання:
- функція P об'єднана всередині функції R
- calc x і z у тій самій .map
- коли рішення знайдено, встановіть x на 0, щоб вийти із зовнішньої петлі
- об'єднане визначення та виклик W

Edit2 більше гольфу, випадкове заповнення укорочене, зовнішній цикл переглянуто ... перегляньте історію для чогось більш читабельного

На відміну від прийнятої відповіді, це має працювати для більшості матеріалів. Просто уникайте однословних слів. Якщо вихід знайдений, він оптимальний і використовувати всі 3 напрямки.

Обмеження уникати повторення слів дуже важко. Мені довелося шукати повторюване слово на кожному кроці, додаючи слово до сітки та при кожному випадковому символі заповнення.

Основні підфункції:

  • P (w) вірно, якщо слово паліндром. Слово паліндром знайдеться двічі під час перевірки повторних слів.

  • R (s) перевірити повторювані слова на сітці s

  • Q (и) заповнюють сітку s випадковими символами - це рекурсивна та зворотний трек у разі повторення слова - і може вийти з ладу.

  • W () рекурсивна, спробуйте заповнити сітку заданого розміру, якщо можливо.

Основна функція використовує W () для пошуку вихідної сітки, намагаючись від розміру найдовшого слова, що вводиться, до суми довжини всіх слів.

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
}

Необов’язаний і пояснений (неповне, шкода хлопцям, це багато роботи)

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

F (['TREN', 'CUBE', 'BOX', 'BICYCLE'])

,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,  

не заповнений

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

F (['TREN', 'ARTS', 'RAT', 'CUBE', 'BOX', 'BICYCLE', 'STORM', 'MOIN', 'DEPTH', 'MOUTH', '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', 'AD', 'AE', 'AF', 'AG'])

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

F (['AA', 'AB', 'AC', 'AD', 'AE', 'AF'])

вихід не заповнений - @nathan: тепер ви не можете додати ще один A x без повторів. Вам знадобиться більша сітка.

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

У останньому тестовому випадку, чи не можливо це в сітці 3x3?
Натан Меррілл

@NathanMerrill ні. Більш детально у тексті відповіді
edc65

абсолютно нечитабельний код :), але приємно, що байтом / точкою "нагороди" є не компілятор людини
firephil

1
@firephil намагається додати пояснення, це не просто ...
edc65

1

C #

Ось проста реалізація з ще роботою, яку потрібно виконати. Для отримання найменшого розміру існує дуже багато комбінацій. Тож щойно використаний найпростіший алгоритм можна було придумати.

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();
    }

}

Тест

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();
    }
}

він працює, але не є оптимальним: зразок рядкових слів = "CAT, DOG, HR, RUN, CMD";
firephil

Чи перевіряєте ви, чи випадкові символи заповнення викликають повторення слова у сітці?
edc65

-1 Спробував. Не дотримується специфікацій at least one word in each direction (horizontal, vertical and diagonal). Запуск програми тестування, жодного горизонтального слова (3 вертикальних, 1
діагноз

3
Це питання є кодовим гольфом , тож ви повинні розмістити скільки байт у заголовку та, ймовірно, скоротити програму. Спасибі.
mbomb007

@ edc65 Це одна вертикаль, одна діагональ і всі інші горизонтальні. Як я коментував, щоб отримати ідеальне рішення, для перевірки знадобиться величезна кількість комбінацій, а також технічні характеристики питання.
bacchusbeale
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.