我正在尝试创建一个包含5x5字符矩阵的文字游戏,如下所示:
[['a', 'a', 'u', 'r', 'a'],
['m', 'v', 'g', 'n', 'x'],
['a', 'q', 'h', 'y', 'o'],
['p', 'r', 'h', 'l', 'h'],
['v', 'h', 'y', 'o', 'j']]
我将其列为列表列表。应该找到“xylon”而不是“尼龙”,因为这会重复使用'n'。我发现了一个类似的问题here,但我不知道C.
我当前的解决方案涉及为单词中的每个字母创建一个字典,其中包含其在板上位置的元组列表,如下所示:{'letter':[(row,column),(row,column)] }。然后,对于单词中的每个字母,我检查板上的每个位置是否与前一个字母的位置兼容。如果是,我将该位置添加到新的路径字典。
虽然重复字母和其他情况如“尼龙”确实返回True,但这失败了。它已经相当庞大和令人困惑,我应该重新开始。我可以采用更简洁的解决方案吗? 编辑:
澄清:如果存在连接网格中单词中每个字母的路径,则单词在网格中“。允许上,下,左,右和对角线。 'x'与'y'相邻,它与'l'相邻,依此类推。只要每个字母相邻并且板上没有特定字母被使用两次,该路径就不需要具有特定形状。单词可以具有重复的字母,因此可以使用“pama”,因为有多个'a'可以使用。
@MSW是正确的,游戏是boggle,虽然我第一次发现了这个!
答案 0 :(得分:3)
如果你想检查单词成员资格,你将字母映射到职位的字典的起点是一个很好的:
letter_positions = {}
for (y, row) in enumerate(board):
for (x, letter) in enumerate(row):
letter_positions.setdefault(letter, []).append((x, y))
从那里,您的功能应该跟踪已经使用过哪些字母以确保它们不会复制它们:
def move_valid(position, last_position):
if last_position is None:
return True
return (
abs(position[0] - last_position[0]) <= 1 and
abs(position[1] - last_position[1]) <= 1
)
def find_word(word, used=None):
if word == "":
return []
if used is None:
used = []
letter, rest = word[:1], word[1:]
for position in letter_positions.get(letter) or []:
if position in used:
continue
if not move_valid(position, used and used[-1]):
continue
path = find_word(rest, used + [position])
if path is not None:
return [position] + path
return None
例如:
>>> find_word("xylon")
[(4, 1), (3, 2), (3, 3), (4, 2), (3, 1)]
>>> find_word("bad")
None
现在,请注意,此处的运行时间为O(not great)
,因为position in used
(used
是一个列表,需要O(N)
搜索每个字母位置)和used + [position]
和[position] + path
(每个都会产生分配+副本)。在实践中,这将是〜O(word length ^ 2)
,但可以通过一些更合理的数据结构改进为〜O(word length)
。