Estou criando um jogo semelhante ao Tetris, com duas diferenças principais: a tela já começa cheia de peças (como no Puzzle Quest para Nintendo DS e PC) e cada peça individual tem uma letra. O objetivo do jogador é eliminar peças, formando palavras válidas com elas. As palavras são formadas colocando letras próximas umas das outras, em qualquer direção, exceto na diagonal.
O jogador pode mover uma linha inteira de peças para a esquerda ou para a direita ou uma coluna inteira de peças para cima ou para baixo, pelo espaço que desejar (se o movimento de uma linha / coluna ultrapassar os limites do tabuleiro, o A letra que ultrapassa o limite "circula", aparecendo no outro extremo da linha / coluna). Após a ação do jogador, o jogo deve verificar o tabuleiro inteiro para procurar palavras válidas e remover as letras que formam essas palavras do tabuleiro. As letras acima daquelas que foram removidas cairão no lugar daquelas que foram removidas e novas cartas cairão da parte superior da tela até que o quadro seja preenchido novamente.
Eu já escrevi um algoritmo linear que, dada uma sequência de caracteres, determina se é uma palavra válida em inglês. O problema que estou enfrentando é: como posso verificar se há palavras válidas no quadro? A força bruta é a única maneira? Testar todas as combinações possíveis do quadro para ver se elas são válidas é muito lento, mesmo para um quadro pequeno (5x5). Qualquer ajuda será muito apreciada, obrigado!
fonte
Respostas:
A força bruta não é o único caminho.
Resolver seu tabuleiro de jogo é semelhante a resolver um tabuleiro Boggle , exceto mais simples. Você deseja verificar todos os blocos no quadro, procurando ver se há alguma palavra que possa ser feita nas instruções apropriadas.
Você ainda deseja refinar ainda mais o seu espaço de pesquisa para não se preocupar em pesquisar ao longo de uma direção se souber que não pode fazer uma palavra. Por exemplo, se você encontrar dois
q
s seguidos, deverá abortar. Para esse fim, você desejará algum tipo de estrutura de dados que permita dizer se um determinado conjunto de caracteres é um prefixo de uma palavra válida. Para isso, você pode usar uma árvore trie ou prefixo; uma estrutura de dados útil ao resolver problemas como este.Uma árvore de prefixos é uma estrutura hierárquica baseada em nó, em que cada nó representa algum prefixo de seus filhos e os nós folha (geralmente) representam os valores finais. Por exemplo, se seu dicionário de palavras válidas contiver "gato", "carro" e "célula", um trie pode se parecer com:
Assim, comece preenchendo uma árvore de prefixos com todas as palavras válidas no seu jogo.
O processo real de encontrar palavras válidas no quadro a qualquer momento envolve o início de uma pesquisa recursiva de cada bloco do quadro. Como cada pesquisa no espaço do quadro, iniciando em um determinado bloco, é independente, elas podem ser paralelizadas, se necessário. Ao pesquisar, você "segue" a árvore de prefixos com base no valor da letra na direção em que está pesquisando.
Você chegará a um ponto em que nenhuma das letras ao redor é filha do nó atual da árvore do prefixo. Quando você chega nesse ponto, se também é verdade que o nó atual é uma folha, você encontrou uma palavra válida. Caso contrário, você não encontrou uma palavra válida e poderá abortar a pesquisa.
Um código de exemplo e uma discussão sobre essa técnica (e outros, como uma solução de programação dinâmica que pode ser ainda mais rápida "invertendo" o espaço de pesquisa de uma maneira) podem ser encontrados no blog desse colega aqui ; ele discute a solução do Boggle, mas adaptar as soluções ao seu jogo é mais ou menos uma questão de mudar em quais direções você permite que a pesquisa ocorra.
fonte
Você pode ter tentado isso, já implementado isso, talvez seja melhor acompanhado por outra resposta, etc. Mas eu não os vi mencionados (ainda), então aqui está:
Você pode descartar muitas verificações acompanhando o que mudou e o que não mudou. Por exemplo:
ou, no código psudo
E as perguntas triviais:
Você tem as otimizações de velocidade dos compiladores definidas? (se você estiver usando um)
O seu algoritmo de busca por palavras pode ser otimizado? De alguma forma?
fonte
IF(rowMoved){ checkColumns(); checkMovedRow(); } IF(columnMoved){ checkRows() checkMovedColumn();}
Se um usuário puder mover apenas um de cada vez, no final desse movimento, nenhuma letra paralela foi movida e, portanto, não será necessário verificar novamente.Lembre-se de que todo caractere é um valor. Então use isso para sua vantagem. Existem algumas funções de hash que podem ser calculadas rapidamente ao iterar em substrings. Por exemplo, digamos que damos a cada letra um código de 5 bits (basta fazer
c - 'a' + 1
em C):Você pode executar rapidamente todas as substrings de um determinado tamanho:
Podemos verificar substrings com até 12 letras dessa maneira nas arquiteturas mais comuns hoje em dia.
Se existir um código de hash no seu dicionário, você poderá extrair a palavra rapidamente, pois códigos de hash como esse são únicos. Quando você atingir o máximo de 12 letras, poderá adicionar outras estruturas de dados para palavras que começam com essas 12 letras. Se você encontrar uma palavra que comece com 12 letras específicas, basta criar uma lista ou outra pequena tabela de hash para os sufixos de cada palavra que começa com esse prefixo.
Armazenar um dicionário de todos os códigos de palavras existentes não deve levar mais do que alguns megabytes de memória.
fonte
Você está limitado apenas às formas clássicas de Tetris ao formar palavras, ou será que alguma formação servirá? As palavras podem dobrar indefinidamente ou apenas uma vez? Uma palavra pode durar o quanto quiser? Isso é bastante complexo se você puder fazer as dobras que quiser, tornando efetivamente as palavras mais longas possíveis com 25 caracteres. Eu diria que você tem uma lista de palavras aceitas. Nessa suposição, sugiro que tente algo como isto:
Isso criará um mapa em cada bloco com informações sobre como esse bloco é conectado às palavras ao redor dele na grade. Quando uma coluna ou linha é movida, verifique todos os blocos que foram ou são adjacentes ao movimento e recalcule as informações. Quando você encontra uma palavra, não é possível adicionar mais blocos a essa palavra; remova. Não tenho certeza se isso será mais rápido, mas realmente se resume a quantas palavras são criadas pela metade. O benefício disso é que o usuário provavelmente está tentando criar uma palavra a partir de uma palavra meia completa no quadro. Mantendo todas essas palavras armazenadas, é fácil verificar se uma palavra foi concluída.
fonte