Friday, August 21, 2015

boggle game

// time: 8^(rows*cols)
//  as 8 calls for each direction, for each of rows*cols squares
bool boggle(m, word):
    if m == null || word == null:
        throw
    cols = m.length()
    rows = m[0].length()
    for c = 0, c < cols, col++:
        for r = 0, r < rows, r++:
            if boggle(m, c, cols, r, rows, word):
                return true
    return false

bool boggle(m, c, cols, r, rows, word, i = 0, visited = new):
    // needs to be before the out-of-bounds checks
    if i == word.length():
        return true
    if !(0 <= c < cols) || !(0 <= r < rows):
        return false
    if visited[i][j]:
        return false
    if m[i][j] != word[i]:
        return false
    visited[i][j] = true
    if
        boggle(m, c  , cols, r+1, rows, word, i+1, visited) ||
        boggle(m, c  , cols, r-1, rows, word, i+1, visited) ||
        boggle(m, c+1, cols, r  , rows, word, i+1, visited) ||
        boggle(m, c-1, cols, r  , rows, word, i+1, visited) ||
        boggle(m, c-1, cols, r+1, rows, word, i+1, visited) ||
        boggle(m, c+1, cols, r+1, rows, word, i+1, visited) ||
        boggle(m, c-1, cols, r-1, rows, word, i+1, visited) ||
        boggle(m, c+1, cols, r-1, rows, word, i+1, visited):
        return true
    visited[i][j] = false
    return false
[Hat tip to SM]

Optimization: Precompute all words using a dictionary.
boggle:
    trie trie
    set words
    ctor(m, trie):
        if m == null || trie == null:
            throw
        trie = trie
        words = bogglePrecompute(m, trie)
    
    result hasWord(word):
        if word == null:
            throw
        if !trie.hasWord(word):
            return result.wordNotInDictionary
        if !words.has(word):
            return result.wordNotInBoggle
        return result.Ok
    
    set bogglePrecompute(m, trie):
        set words = new
        for c = 0, c < cols, col++:
            for r = 0, r < rows, r++:
                bogglePrecompute(m, c, cols, r, rows, trie.root, words)
        return words
    
    bogglePrecompute(m, c, cols, r, rows, trieNode, words,
        visited = new, buffer = new):
        if !(0 <= r < rows) || !(0 <= c < cols):
            return
        if visited[c][r]:
            return
        ch = m[c][r]
        // word prefix not in dictionary
        if !trieNode.hasChild(ch):
            return
        visited[c][r] = true
        buffer.append(ch)
        trieNode = trieNode.getChild(ch)
        if trieNode.isWord():
            words.add(buffer.toString())
        boggle(m, c  , cols, r+1, rows, trieNode, words, visited, buffer)
        boggle(m, c  , cols, r-1, rows, trieNode, words, visited, buffer)
        boggle(m, c+1, cols, r  , rows, trieNode, words, visited, buffer)
        boggle(m, c-1, cols, r  , rows, trieNode, words, visited, buffer)
        boggle(m, c-1, cols, r+1, rows, trieNode, words, visited, buffer)
        boggle(m, c+1, cols, r+1, rows, trieNode, words, visited, buffer)
        boggle(m, c-1, cols, r-1, rows, trieNode, words, visited, buffer)
        boggle(m, c+1, cols, r-1, rows, trieNode, words, visited, buffer)
        visited[i][j] = false
        buffer.removeLast()

// interfaces for trie
itrie:
    trieNode root

itrieNode:
    itrieNode getChild(ch):
    bool hasChild(ch):
    bool isWord():
[Hat tip to ML]

No comments:

Post a Comment