문자 그리드에서 유효한 단어를 어떻게 찾을 수 있습니까?


12

테트리스와 비슷한 게임을 만들고 있는데 두 가지 차이점이 있습니다. 화면은 이미 타일로 채워져 있고 (닌텐도 DS 및 PC 용 퍼즐 퀘스트에서와 같이) 각 타일에는 글자가 있습니다. 플레이어의 목표는 타일과 함께 유효한 단어를 만들어 타일을 제거하는 것입니다. 단어는 대각선을 제외하고 어떤 방향으로도 서로 옆에 문자를 배치하여 형성됩니다.

플레이어는 원하는만큼 많은 공간에 대해 타일의 전체 행을 왼쪽 또는 오른쪽으로 또는 타일의 전체 열을 위 또는 아래로 이동할 수 있습니다 (행 / 열의 이동이 보드의 한계를 초과하는 경우, 한도를 초과하는 문자는 행 / 열의 다른 끝에 표시되는 "사이클"입니다. 플레이어의 행동이 끝나면 게임은 전체 단어를 확인하여 유효한 단어를 찾고 해당 단어를 형성하는 글자를 보드에서 제거해야합니다. 제거 된 문자 위의 문자는 제거 된 문자 대신 쓰러지고 보드가 다시 채워질 때까지 새 문자가 화면 상단에서 떨어집니다.

나는 이미 일련의 문자가 유효한 영어 단어인지 결정하는 선형 알고리즘을 작성했습니다. 내가 겪고있는 문제는 보드에서 유효한 단어를 어떻게 확인할 수 있습니까? 무차별적인 힘이 유일한 방법입니까? 보드에서 가능한 모든 조합을 테스트하여 유효한지 여부를 확인하는 것은 작은 (5x5) 보드에서도 매우 느립니다. 어떤 도움이라도 대단히 감사하겠습니다!


불행히도, 당신 말이 맞아요. 숫자 (3, 4, 5, ... 25 문자의 모든 조합) 때문에 매우 느립니다. 성능을 향상시키기 위해 "단어를 가로 또는 세로로 정렬해야합니다"로 제한하고 플레이어가 보지 못한 임의의 단어를 얻지 못할 수 있습니다.
ashes999

일련의 문자를 단어와 일치시키는 알고리즘을 다시 살펴 봐야한다고 생각합니다. 내 계산에 따르면 5x5 그리드에는 2700 개의 잠재적 단어가 있으며 알고리즘이 불려야합니다 (예 : Josh의 답변 참조).
Taemyr

나는 다음과 같은 방식으로 2700 단어에 도달합니다. 첫 번째 행에서 왼쪽에서 오른쪽으로 시작하십시오. 5 개의 글자, 2 개의 4 개의 단어, 3 개의 3 개의 단어, 4 개의 2 개의 단어 및 5 개의 1 개의 단어가있는 1 개의 위치가 있습니다. 단어의 문자 중 하나를 다른 열의 문자로 바꿀 수 있습니다. 우리는 일반성을 잃지 않고 한 글자로 된 글자는 교환되지 않으며 첫 글자는 두 글자로 교체되지 않는다고 가정 할 수 있습니다. 이것은 준다; 5 * 5 * 1 + 4 * 5 * 2 + 3 * 5 * 3 + 1 * 5 * 4 + 1 = 135. 행과 방향의 수를 곱하십시오. 135 * 5 * 4 = 2700
Taemyr

나는 이것을 명확히하지 않았다고 생각하지만 대각선을 제외하고는 모든 방향으로 단어를 형성하고 모서리를 만들 수도 있습니다 (예 : 첫 번째 행의 첫 번째 타일, 첫 번째 행의 오른쪽에 두 번째 타일, 그다음에 아래에서 두 번째 행의 타일).
Tavio

@Tavio 몇 가지 생각 : 검사는 더 긴 단어를 먼저 가야합니다 ( "aside"로 만들면 "as"를 원하지 않습니다. 또한 한 글자로 된 단어는 무시하는 것이 좋습니다. 그렇지 않으면 a를 사용할 수 없습니다. 다 마치면이 게임의 이름을 알고 싶습니다.
David Starkey

답변:


22

무차별 힘이 유일한 방법은 아닙니다.

게임 보드를 해결하는 것은 더 간단한 것을 제외하고 Boggle 보드 를 해결하는 것과 유사합니다 . 보드의 모든 타일을 확인하고 적절한 지침에 따라 단어를 만들 수 있는지 확인하려고합니다.

단어를 만들 수없는 경우 방향을 따라 검색하지 않아도되도록 검색 공간을 더 세분화하고 싶습니다. 예를 들어, q행에서 두 개의을 찾으면 중단해야합니다. 이를 위해 주어진 문자 집합이 유효한 단어의 접두사인지 알 수있는 일종의 데이터 구조가 필요합니다. 이를 위해 trie 또는 접두사 트리를 사용할 수 있습니다 . 이와 같은 문제를 해결할 때 유용한 데이터 구조.

접두사 트리는 계층 적 노드 기반 구조로, 모든 노드는 자식의 접두사를 나타내며 리프 노드는 일반적으로 최종 값을 나타냅니다. 예를 들어 유효한 단어 사전에 "cat", "car"및 "cell"이 포함되어 있으면 trie는 다음과 같습니다.

    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

따라서 게임에서 유효한 모든 단어로 접두사 트리를 채우는 것으로 시작하십시오.

주어진 시간에 보드에서 유효한 단어를 찾는 실제 과정은 보드의 각 타일에서 재귀 검색을 시작하는 것입니다. 특정 타일에서 시작하는 보드 공간을 통한 각 검색은 독립적이므로 필요한 경우 병렬로 처리 할 수 ​​있습니다. 검색 할 때 검색 방향의 문자 값을 기준으로 접두사 트리를 "따릅니다".

결국 현재 접두사 트리 노드의 자식이 아닌 주변 문자가없는 지점에 도달합니다. 해당 지점에 도달했을 때 현재 노드가 잎인 경우에도 유효한 단어를 찾았습니다. 그렇지 않으면 유효한 단어를 찾지 못해 검색을 중단 할 수 있습니다.

이 동료의 블로그에서 예제 코드와이 기술에 대한 설명 (및 패션 후 검색 공간을 "반전"하여 더 빠른 동적 프로그래밍 솔루션과 같은 기타 기술)을 찾을 수 있습니다 . 그는 Boggle 해결에 대해 설명하지만 솔루션을 게임에 적용하는 것은 검색이 발생하는 방향을 변경하는 문제입니다.


당신이 스스로를 설명하는 것처럼 무차별 힘이 유일한 방법은 아닙니다. :) 계속 볼 필요가 없다는 힌트를주는 많은 접두사가 있습니다. (대부분의 [무작위] 문자열은 단어가 아닙니다. +1
AturSams

좋은 대답입니다. "단어"는 게임 사전의 전체 정지에있는 것입니다.
Adam Eberbach

OP는 단어를 문자열과 일치시키는 알고리즘을 가지고 있다고 말합니다. 그래서 나는 이것이 질문에 대답하지 않는다고 생각합니다.
Taemyr

OTOH OP는 현재 가지고있는 것보다 더 효율적인 문자열 매칭 알고리즘을 원할 것이라고 생각합니다.
Taemyr

1
@Taemyr는 일반 trie를 사용합니다. 그러나 약간 수정 된 trie를 사용하는 Aho-Corasick 알고리즘이 훨씬 더 효과적입니다 (선형). Aho-Corasick 알고리즘을 사용하면 nxn 행렬의 모든 유효한 단어를 O (n ^ 2) 시간 내에 찾을 수 있습니다.
el.pescado 2014 년

3

당신은 이것을 시도했을 수도 있고, 이미 이것을 구현했을 수도 있습니다. 아마도 다른 대답을 동반하는 것이 더 좋을 수도 있습니다.

변경된 내용과 변경되지 않은 내용을 추적하여 많은 수표를 폐기 할 수 있습니다. 예를 들면 다음과 같습니다.

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.

또는 의사 코드에서

// 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)
}

그리고 사소한 질문 :

컴파일러 속도 최적화가 설정되어 있습니까? (사용중인 경우)

단어 검색 알고리즘을 전혀 최적화 할 수 있습니까? 어떠한 방식으로?


플레이어가 행을 회전 할 수있는 것을 제외하고 세 번째 열에서 단어를 찾으면 다른 열에 영향을 미칩니다.
Taemyr

@Taemyr IF(rowMoved){ checkColumns(); checkMovedRow(); } IF(columnMoved){ checkRows() checkMovedColumn();} 사용자가 한 번에 한 번만 이동할 수 있으면 해당 이동이 끝날 때 평행 문자가 이동하지 않으므로 다시 확인할 필요가 없습니다.
David Starkey

2

모든 문자는 가치라는 것을 기억하십시오. 따라서 그것을 유리하게 사용하십시오. 부분 문자열을 반복 할 때 빠르게 계산할 수있는 해시 함수가 있습니다. 예를 들어 모든 문자에 5 비트 코드 ( c - 'a' + 1C 로만 수행) 를 제공한다고 가정 해 보겠습니다 .

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

특정 크기의 모든 하위 문자열을 빠르게 실행할 수있는 것보다 :

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

오늘날 가장 일반적인 아키텍처에서 이러한 방식으로 최대 12 자의 하위 문자열을 확인할 수 있습니다.

사전에 해시 코드가 존재하는 경우 단어를 빨리 가져 와서 해시 코드를 독특하게 만들 수 있습니다. 최대 12 글자에 도달하면 12 글자로 시작하는 단어에 다른 데이터 구조를 추가 할 수 있습니다. 특정 12 자로 시작하는 단어를 찾으면 해당 접두사로 시작하는 각 단어의 접미사에 대한 목록 또는 다른 작은 해시 테이블을 만드는 것보다.

기존의 모든 단어 코드의 사전을 저장하는 데 몇 메가 바이트 이상의 메모리가 필요하지 않습니다.


0

단어를 만들 때 고전적인 테트리스 모양에만 국한됩니까? 단어가 무한정 또는 한 번만 구부릴 수 있습니까? 단어는 원하는만큼 길 수 있습니까? 원하는만큼 구부릴 수 있고 가능한 한 가장 긴 단어를 25 자 길이로 효과적으로 만들면이 방법은 매우 복잡해집니다. 나는 당신이 받아 들인 단어의 목록이 있다고 가정합니다. 그 가정에 따라 다음과 같이 시도해보십시오.

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

이렇게하면이 타일이 그리드에서 주변의 단어에 어떻게 연결되는지에 대한 정보가있는 각 타일에 맵이 만들어집니다. 열 또는 행이 이동되면 이동했거나 인접한 타일을 모두 확인하고 정보를 다시 계산하십시오. 단어를 찾으면 해당 단어에 더 이상 타일을 추가 할 수 없습니다. 제거하십시오. 이것이 더 빠를 지 확신 할 수 없으며 실제로 절반의 단어가 얼마나 많이 생성되는지에 달려 있습니다. 이것의 장점은 사용자가 보드에서 반 완전한 단어로 단어를 만들려고하는 것입니다. 이러한 모든 단어를 저장하면 단어가 완료되었는지 쉽게 확인할 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.