Du könntest das Problem in zwei Teile aufteilen:
- Einige Art von Suchalgorithmus, der mögliche Zeichenfolgen im Gitter aufzählt.
- Eine Möglichkeit zu überprüfen, ob eine Zeichenfolge ein gültiges Wort ist.
Idealerweise sollte (2) auch eine Möglichkeit enthalten zu überprüfen, ob eine Zeichenfolge ein Präfix eines gültigen Wortes ist – dadurch kannst du deine Suche optimieren und eine Menge Zeit sparen.
Adams Rosenfields Trie ist eine Lösung für (2). Es ist elegant und wahrscheinlich das, was dein Algorithmus-Spezialist bevorzugen würde, aber mit modernen Sprachen und modernen Computern können wir etwas fauler sein. Außerdem können wir, wie Kent vorschlägt, die Größe unseres Wörterbuchs reduzieren, indem wir Wörter verwerfen, die Buchstaben enthalten, die im Gitter nicht vorhanden sind. Hier ist ein bisschen Python:
def make_lookups(grid, fn='dict.txt'):
# Set von gültigen Zeichen erstellen.
chars = set()
for word in grid:
chars.update(word)
words = set(x.strip() for x in open(fn) if set(x.strip()) <= chars)
prefixes = set()
for w in words:
for i in range(len(w)+1):
prefixes.add(w[:i])
return words, prefixes
Wow; Konstante Zeit für Präfix-Tests. Es dauert nur ein paar Sekunden, um das von dir verlinkte Wörterbuch zu laden, aber nur ein paar :-) (beachte, dass words <= prefixes
)
Jetzt, für Teil (1), neige ich dazu, in Begriffen von Graphen zu denken. Also werde ich ein Wörterbuch aufbauen, das ungefähr so aussieht:
graph = { (x, y):set([(x0,y0), (x1,y1), (x2,y2)]), }
dh. graph[(x, y)]
ist die Menge der Koordinaten, die du von der Position (x, y)
aus erreichen kannst. Ich werde auch einen Dummy-Knoten None
hinzufügen, der mit allem verbunden ist.
Das Aufbauen ist ein bisschen umständlich, weil es 8 mögliche Positionen gibt und du Grenzüberprüfungen durchführen musst. Hier ist entsprechend umständlicher Python-Code:
def make_graph(grid):
root = None
graph = { root:set() }
chardict = { root:'' }
for i, row in enumerate(grid):
for j, char in enumerate(row):
chardict[(i, j)] = char
node = (i, j)
children = set()
graph[node] = children
graph[root].add(node)
add_children(node, children, grid)
return graph, chardict
def add_children(node, children, grid):
x0, y0 = node
for i in [-1,0,1]:
x = x0 + i
if not (0 <= x < len(grid)):
continue
for j in [-1,0,1]:
y = y0 + j
if not (0 <= y < len(grid[0])) or (i == j == 0):
continue
children.add((x,y))
Dieser Code baut auch ein Wörterbuch auf, das (x,y)
auf das entsprechende Zeichen abbildet. Dadurch kann ich eine Liste von Positionen in ein Wort umwandeln:
def to_word(chardict, pos_list):
return ''.join(chardict[x] for x in pos_list)
Zuletzt führen wir eine Tiefensuche durch. Das grundlegende Verfahren ist:
- Die Suche erreicht einen bestimmten Knoten.
- Überprüfe, ob der bisherige Pfad Teil eines Wortes sein könnte. Wenn nicht, erkunde diesen Zweig nicht weiter.
- Überprüfe, ob der bisherige Pfad ein Wort ist. Wenn ja, füge es zur Ergebnisliste hinzu.
- Erkunde alle Kinder, die nicht Teil des bisherigen Pfades sind.
Python:
def find_words(graph, chardict, position, prefix, results, words, prefixes):
""" Argumente:
graph :: Zuordnung (x,y) zu Menge von erreichbaren Positionen
chardict :: Zuordnung (x,y) zu Zeichen
position :: aktuelle Position (x,y) -- entspricht prefix[-1]
prefix :: Liste von Positionen im aktuellen String
results :: Menge gefundener Wörter
words :: Menge gültiger Wörter im Wörterbuch
prefixes :: Menge gültiger Wörter oder Präfixe davon
"""
word = to_word(chardict, prefix)
if word not in prefixes:
return
if word in words:
results.add(word)
for child in graph[position]:
if child not in prefix:
find_words(graph, chardict, child, prefix+[child], results, words, prefixes)
Führe den Code aus:
grid = ['fxie', 'amlo', 'ewbx', 'astu']
g, c = make_graph(grid)
w, p = make_lookups(grid)
res = set()
find_words(g, c, None, [], res, w, p)
und inspiziere res
, um die Antworten zu sehen. Hier ist eine Liste der für dein Beispiel gefundenen Wörter, sortiert nach Größe:
['a', 'b', 'e', 'f', 'i', 'l', 'm', 'o', 's', 't',
'u', 'w', 'x', 'ae', 'am', 'as', 'aw', 'ax', 'bo',
'bu', 'ea', 'el', 'em', 'es', 'fa', 'ie', 'io', 'li',
'lo', 'ma', 'me', 'mi', 'oe', 'ox', 'sa', 'se', 'st',
'tu', 'ut', 'wa', 'we', 'xi', 'aes', 'ame', 'ami',
'ase', 'ast', 'awa', 'awe', 'awl', 'blo', 'but', 'elb',
'elm', 'fae', 'fam', 'lei', 'lie', 'lim', 'lob', 'lox',
'mae', 'maw', 'mew', 'mil', 'mix', 'oil', 'olm', 'saw',
'sea', 'sew', 'swa', 'tub', 'tux', 'twa', 'wae', 'was',
'wax', 'wem', 'ambo', 'amil', 'amli', 'asem', 'axil',
'axle', 'bleo', 'boil', 'bole', 'east', 'fame', 'limb',
'lime', 'mesa', 'mewl', 'mile', 'milo', 'oime', 'sawt',
'seam', 'seax', 'semi', 'stub', 'swam', 'twae', 'twas',
'wame', 'wase', 'wast', 'weam', 'west', 'amble', 'awest',
'axile', 'embox', 'limbo', 'limes', 'swami', 'embole',
'famble', 'semble', 'wamble']
Der Code benötigt (wortwörtlich) ein paar Sekunden, um das Wörterbuch zu laden, aber der Rest erfolgt auf meinem Computer sofort.
1 Stimmen
Eine einfache Lösung ist die Klasse BoggleFinder aima.cs.berkeley.edu/python/search.html
0 Stimmen
Das macht doch keinen Spaß, oder? :)
18 Stimmen
Bitte übersetzen Sie dies beibehalten die gleichen HTML-Tags, wenn diese vorhanden sind von en nach de: Featureanfrage MEHR RÄTSEL
6 Stimmen
In Bezug auf die Zeitpunkte: In meiner Lösung wird praktisch die gesamte Zeit damit verbracht, den Trie aufzubauen. Sobald der Trie erstellt ist, kann er viele Male wiederverwendet werden. Wenn nur ein Rätsel gelöst wird, wäre es effizienter, eine einfachere Datenstruktur zu verwenden (wie eine Menge aller Wörter und aller Präfixe).
3 Stimmen
Auch Adam hat ein größeres Wörterbuch, wie durch die Anzahl der längeren Wörter in seiner Lösung belegt wird. Sie sollten alle basierend auf einem gemeinsamen Wörterbuch getestet werden.
0 Stimmen
@Reich: Ich führe sie alle auf meinem Computer mit meinem eigenen Wörterbuch aus.
2 Stimmen
Ich nehme an, dass niemand viel Boggle spielt? "Qu" ist ein "Buchstabe" und ich bin mir nicht sicher, wie viele der Lösungen dieses kleine Detail beachtet haben. Es sieht so aus, als ob einige von ihnen es ermöglichen würden, das "u" unabhängig zu verwenden, unter anderem Probleme.
2 Stimmen
Ich hatte kürzlich diese Frage bei einem Vorstellungsgespräch und bin nett in den Details steckengeblieben. Ich behandelte es als ein Graphenproblem, was in Ordnung ist, aber die Lösungen hier verwenden viel weniger Speicher. Ich code jetzt meine eigene Lösung. Gut gemacht an alle, die beigetragen haben!
0 Stimmen
Diese Frage scheint nicht zum Thema zu gehören, da es um Rätsellösungen geht. Es wäre passender auf codegolf.stackexchange.com
0 Stimmen
@Blazemonger Die Frage ist nach dem effizientesten Algorithmus zur Lösung eines Boggle gestellt, nicht nach dem kürzesten, und es handelt sich nicht um ein Rätsel im Codegolf-Stil. Soweit ich weiß, waren algorithmusbezogene Fragen fair für StackOverflow. Dies ist nicht off-topic, und ich denke, die Community hat ziemlich laut darüber gesprochen.
2 Stimmen
Sie sagen, dass Sie einen allgemeinen Algorithmus möchten, aber "Sie suchen hauptsächlich" nach konkretem Code in Python, PHP oder Perl. Sie haben keine eigene Arbeit geleistet, was heutzutage als wesentlich für SO-Fragen angesehen wird. Kommentare kennzeichnen dies eindeutig als "Rätsel" und nicht als eng definiertes Problem mit einer einzigen Lösung. Alles zusammen genommen könnte es als Codegolf geeignet sein, wie es geschrieben ist, aber wenn Sie diese Frage heute eingereicht hätten, würde sie sicherlich nicht als angemessen für SO angesehen. Meiner Meinung nach setzt es ein schlechtes Beispiel für Neulinge, was hier als "gute Frage" angesehen wird, wenn Sie sie offen lassen.
1 Stimmen
@Blazemonger 1. Die Bitte um bestimmte Sprachen ist für die Frage nach einem Algorithmus irrelevant. 2. Ich habe meine versuchte Lösung beschrieben und meine eigene gepostet. 3. Es ist definitiv eng und ausreichend definiert. 4. Es würde sicherlich offen bleiben, wenn es heute gepostet würde. 5. Wenn Neuankömmlinge Fragen stellen würden, die nur halb so gut sind wie diese, wären wir in guter Verfassung. Kurz gesagt, ich widerspreche respektvoll praktisch allem, was du gesagt hast.
0 Stimmen
@PaoloBergantino Tatsächlich sind offene Fragen, die zum analytischen Denken anregen, viel besser als die "Mach meinen Job, während ich Mittagessen gehe" Art von sogenannten Anfängerfragen, die heutzutage auf SO so verbreitet sind.
0 Stimmen
Ich erwarte, dass diese Frage gesperrt wird, da der Wert der Antworten darin liegt, aber ich stimme zu, dass sie nicht zum Thema gehört. Ich werde es erneut versuchen zu schließen. cc @Blazemonger.