wordladder - code improvement
dwdv
dwdv at posteo.de
Fri Jan 31 01:17:19 UTC 2020
From one noob to another: Not much of a difference, but levenshteinDistance seems to be a good fit
here. About as fast as your solution, slightly lower memory usage. byCodeUnit/byChar might shave off
a few more ms.
For small scripts like these I'm usually not even bothering with const correctness and selective
imports. There's also import std; but that might lead to ambiguous imports.
---
import std.algorithm, std.array, std.conv, std.datetime.stopwatch,
std.functional, std.random, std.range, std.stdio, std.uni;
enum WORDFILE = "/usr/share/hunspell/en_GB.dic";
enum WORDSIZE = 4;
enum STEPS = WORDSIZE;
// could be verified at compile-time
static assert(WORDSIZE % 2 == 0, "WORDSIZE should be even");
alias WordList = string[];
alias WordSet = bool[string];
void main() {
auto sw = StopWatch(AutoStart.yes);
auto words = getWords(WORDFILE, WORDSIZE);
// would be slicker with proper destructuring support
auto res = generate!(() => genLadder(words.dup, STEPS))
.enumerate(1)
.find!(a => !a[1].empty)
.front;
writeln("tries: ", res[0]);
res[1].each!writeln;
writeln(sw.peek); // or sw.peek.total!"msecs"
}
WordSet getWords(string filename, uint wordsize) {
return File(filename).byLine
.map!(line => line.until!(not!isAlpha))
.filter!(word => word.count == wordsize)
.map!(word => word.to!string.toUpper)
.assocArray(true.repeat);
}
WordList genLadder(WordSet words, uint steps) {
WordList ladder;
string update(WordList comps) {
ladder ~= comps.choice;
words.remove(ladder.back);
return ladder.back;
}
WordList compWords(string prev) {
return words.byKey.filter!(word => levenshteinDistance(word, prev) == 1).array;
}
auto prev = update(words.byKey.array);
foreach (comps; generate!(() => compWords(prev)).take(steps + 1)) {
if (comps.empty) return comps;
prev = update(comps);
}
if (levenshteinDistance(ladder.front, ladder.back) < WORDSIZE)
return [];
return ladder;
}
More information about the Digitalmars-d-learn
mailing list