Created
May 6, 2020 21:13
-
-
Save DeCarabas/7f2a66e4272b87fbf95f6e7914659edb to your computer and use it in GitHub Desktop.
This is a typescript port of the code in https://github.com/ftrain/code-commonplace/blob/master/code/clojure/rhymes.org
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
let fs = require('fs') | |
const cmu_dict: string = fs.readFileSync('cmudict-0.7b', 'utf-8') | |
type Rhyme = string[] | |
type WordToRhyme = { | |
[word: string]: Rhyme | |
}; | |
const word_to_rhyme = | |
cmu_dict.split('\n') | |
.filter(line => !line.startsWith(';')) | |
.map(line => line.split(/\s+/)) | |
.reduce((m: WordToRhyme, [word, ...phonemes]): WordToRhyme => { | |
m[word] = phonemes.reverse(); | |
return m; | |
}, {}) | |
type TrieNode = { | |
[syllable: string]: string|TrieNode|undefined, | |
terminate?: string | |
}; | |
const rhyme_to_words: TrieNode = (function() { | |
let result: TrieNode = {}; | |
for (let [k, v] of Object.entries(word_to_rhyme)) { | |
let cursor = result; | |
for (let syllable of v) { | |
const next = cursor[syllable]; | |
if (typeof next === 'string') { | |
throw Error('Unexpected syllable: ' + syllable); | |
} else if (next === undefined) { | |
cursor = cursor[syllable] = {} | |
} else { | |
cursor = next; | |
} | |
} | |
cursor['terminate'] = k; | |
} | |
return result; | |
})(); | |
function findAllWords(m: TrieNode): string[] { | |
let results = []; | |
let stack = [m]; | |
for (;;) { | |
let top = stack.pop(); | |
if (!top) { | |
break; | |
} | |
for (let [k, v] of Object.entries(top)) { | |
if (typeof v === 'string') { | |
results.push(v); | |
} else { | |
stack.push(v ?? {}); | |
} | |
} | |
} | |
return results; | |
} | |
function findRhymes(word: string): string[] { | |
let rhyme = (word_to_rhyme[word.toUpperCase()] || []).slice(0, 3) | |
let cursor: TrieNode = rhyme_to_words | |
for (let syllable of rhyme) { | |
const next = cursor[syllable]; | |
if (next === undefined || typeof next === 'string') { | |
cursor = {}; | |
} else { | |
cursor = next; | |
} | |
} | |
return findAllWords(cursor) | |
} | |
console.log(findRhymes('adamant')); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment