M src/main/Main.kt => src/main/Main.kt +1 -100
@@ 1,12 1,7 @@
+import cli.Play
import com.github.ajalt.clikt.core.CliktCommand
import com.github.ajalt.clikt.core.subcommands
-import com.github.ajalt.clikt.parameters.options.default
-import com.github.ajalt.clikt.parameters.options.flag
-import com.github.ajalt.clikt.parameters.options.option
import com.github.ajalt.clikt.parameters.options.versionOption
-import com.github.ajalt.clikt.parameters.types.file
-import com.github.ajalt.clikt.parameters.types.int
-import java.io.File
const val GHOSTSPELLER_VERSION = "0.1.0"
@@ 15,100 10,6 @@ class Ghostspeller : CliktCommand() {
}
/**
- * Command line subcommand for pitting the player against the computer at Ghost.
- */
-class Play : CliktCommand() {
- // Command line options
- private val dictionary by option(
- "-d",
- "--dictionary",
- help = "Path to a new-line separated list of words to be used as the word list (default /usr/share/dict/words)"
- )
- .file()
- .default(File("/usr/share/dict/words"))
- private val minWordLength by option(
- "-m",
- "--min-word-length",
- help = "Minimum word length for a word to be considered in the dictionary (default 4)"
- )
- .int()
- .default(4)
- private val initialStem by option(
- "-i",
- "--initial-stem",
- help = "Start the game midway through a word"
- ).default("")
- private val excludeProperNouns by option(
- "--use-proper-nouns",
- help = "Use words in the dictionary that begin with a capital letter (default false)"
- ).flag(default = false)
-
- /**
- * Starts the Ghost play loop in which the player and computer take turns spelling.
- */
- override fun run() {
- echo("\uD83D\uDC7B Play Ghost! \uD83D\uDC7B")
- print("Loading word list... ")
- val wordList = dictionary.readLines()
- .filter { it.isNotEmpty() }
- .filter { excludeProperNouns || it.first().isLowerCase() }
- .map { it.toLowerCase() }
- .toSet()
- val trie = GhostTrieNode.fromWordList(wordList, minWordLength, initialStem)
- var node = trie
- echo("Done!")
- while (true) {
- echo("\uD83E\uDE84 Spell! \uD83E\uDE84")
- if (initialStem.isNotEmpty()) echo(initialStem)
- while (true) {
- val input = readLine() ?: break
- if (input == "") continue
- if (input.count() > 1) {
- echo("Spell one letter at at time!")
- continue
- }
-
- val c = input.first()
- if (node.children.containsKey(c)) {
- node = node.children[c]!!
- } else {
- echo("There are no words beginning \"${node.s + c}\" in the dictionary. You lose!")
- echo("Words beginning with \"${node.s}\":")
- wordList.filter { it.startsWith(node.s) }.forEach {
- echo("$it - https://www.merriam-webster.com/dictionary/$it")
- }
- break
- }
-
- if (node.isWord) {
- echo("The word \"${node.s}\" is in the dictionary! You lose!")
- echo("Meaning: https://www.merriam-webster.com/dictionary/${node.s}")
- break
- } else {
- if (node.s.count() > 1) echo(node.s) // reminder of word so far
-
- node = when {
- node.winningChildren.isNotEmpty() -> node.winningChildren.values.random()
- node.notWordChildren.isNotEmpty() -> node.notWordChildren.values.random()
- else -> node.children.values.random()
- }
- }
- if (node.isWord) {
- echo("Congratulations! You win with \"${node.s}\".")
- echo("https://www.merriam-webster.com/dictionary/${node.s}")
- break
- } else {
- echo(node.s)
- }
- }
- echo("Play again? (Ctrl + C to quit)")
- readLine()
- node = trie
- }
- }
-}
-
-/**
* Entrypoint for running ghostspeller.
*
* @param args command line arguments passed to the Clikt command.
A src/main/cli/GhostCommand.kt => src/main/cli/GhostCommand.kt +39 -0
@@ 0,0 1,39 @@
+package cli
+
+import com.github.ajalt.clikt.core.CliktCommand
+import com.github.ajalt.clikt.parameters.options.default
+import com.github.ajalt.clikt.parameters.options.flag
+import com.github.ajalt.clikt.parameters.options.option
+import com.github.ajalt.clikt.parameters.types.file
+import com.github.ajalt.clikt.parameters.types.int
+import java.io.File
+
+/**
+ * Abstract class for common command line flags between Ghost subcommands.
+ */
+abstract class GhostCommand : CliktCommand() {
+ // Command line options
+ protected val dictionary by option(
+ "-d",
+ "--dictionary",
+ help = "Path to a new-line separated list of words to be used as the word list (default /usr/share/dict/words)"
+ )
+ .file()
+ .default(File("/usr/share/dict/words"))
+ protected val minWordLength by option(
+ "-m",
+ "--min-word-length",
+ help = "Minimum word length for a word to be considered in the dictionary (default 4)"
+ )
+ .int()
+ .default(4)
+ protected val initialStem by option(
+ "-i",
+ "--initial-stem",
+ help = "Start the game midway through a word"
+ ).default("")
+ protected val excludeProperNouns by option(
+ "--use-proper-nouns",
+ help = "Use words in the dictionary that begin with a capital letter (default false)"
+ ).flag(default = false)
+}
A src/main/cli/Play.kt => src/main/cli/Play.kt +64 -0
@@ 0,0 1,64 @@
+package cli
+
+class Play : GhostCommand() {
+ override fun run() {
+ echo("\uD83D\uDC7B Play Ghost! \uD83D\uDC7B")
+ print("Loading word list... ")
+ val wordList = dictionary.readLines()
+ .filter { it.isNotEmpty() }
+ .filter { excludeProperNouns || it.first().isLowerCase() }
+ .map { it.toLowerCase() }
+ .toSet()
+ val trie = GhostTrieNode.fromWordList(wordList, minWordLength, initialStem)
+ var node = trie
+ echo("Done!")
+ while (true) {
+ echo("\uD83E\uDE84 Spell! \uD83E\uDE84")
+ if (initialStem.isNotEmpty()) echo(initialStem)
+ while (true) {
+ val input = readLine() ?: break
+ if (input == "") continue
+ if (input.count() > 1) {
+ echo("Spell one letter at at time!")
+ continue
+ }
+
+ val c = input.first()
+ if (node.children.containsKey(c)) {
+ node = node.children[c]!!
+ } else {
+ echo("There are no words beginning \"${node.s + c}\" in the dictionary. You lose!")
+ echo("Words beginning with \"${node.s}\":")
+ wordList.filter { it.startsWith(node.s) }.forEach {
+ echo("$it - https://www.merriam-webster.com/dictionary/$it")
+ }
+ break
+ }
+
+ if (node.isWord) {
+ echo("The word \"${node.s}\" is in the dictionary! You lose!")
+ echo("Meaning: https://www.merriam-webster.com/dictionary/${node.s}")
+ break
+ } else {
+ if (node.s.count() > 1) echo(node.s) // reminder of word so far
+
+ node = when {
+ node.winningChildren.isNotEmpty() -> node.winningChildren.values.random()
+ node.notWordChildren.isNotEmpty() -> node.notWordChildren.values.random()
+ else -> node.children.values.random()
+ }
+ }
+ if (node.isWord) {
+ echo("Congratulations! You win with \"${node.s}\".")
+ echo("https://www.merriam-webster.com/dictionary/${node.s}")
+ break
+ } else {
+ echo(node.s)
+ }
+ }
+ echo("Play again? (Ctrl + C to quit)")
+ readLine()
+ node = trie
+ }
+ }
+}