I recently posted my Hangman game, and got some amazing feedback! The main thing suggested was to create a word generator that could read JSON files so that my hangman brain class didn't have to generate the word used on top of handling gameplay. To do this, I created the HangmanWordGenerator
class that parses JSON and generates a word for the HangmanBrain
class. Before, the HangmanBrain
used a set "database" in the form of three arrays (one for each difficulty) and picked a word itself. I am wondering how I did in implementing these improvements.
Hangman Brain
import Foundation
import Darwin
//MARK: - Global Enum
enum DifficultyLevel: String {
case Easy = "Easy"
case Medium = "Medium"
case Hard = "Hard"
}
class HangmanBrain {
init() {
//not sure what to do here? without an empty init xcode says I have to use the one below
}
init(word: String) {
self.word = word //when the user inputs a word
}
//MARK: - Properties
var level: DifficultyLevel? {
didSet {
wordGenerator = HangmanWordGenerator(level: level!)
word = wordGenerator!.generateWord()
setNumberOfGuesses(level: level!)
}
}
var wordGenerator : HangmanWordGenerator? = nil
var guesses: Int? = nil
var word: String? = nil {
didSet {
makeNewGameWord()
}
}
var gameWord = ""
//MARK: - Gameplay Functions
private func makeNewGameWord() {
gameWord = ""
for _ in word!.characters {
createGameWord(character: "_")
}
}
private func setNumberOfGuesses(level level: DifficultyLevel) {
switch level.rawValue {
case "Easy": guesses = 10
case "Medium": guesses = 8
case "Hard": guesses = 6
default: break
}
}
func checkGuessAndUpdateGameWordAndGuesses(character character: String) {
var guessIsCorrect = false
let answer = word!
let currentWord = gameWord as String
gameWord = ""
let currentWordTrimmed = currentWord.stringByReplacingOccurrencesOfString(" ", withString: "")
let numberOfLetters = answer.characters.count as Int
for i in 0...numberOfLetters-1 {
let start = advance(currentWordTrimmed.startIndex, i)
let end = advance(currentWordTrimmed.startIndex, i+1)
let subCurrentWord = currentWordTrimmed.substringWithRange(Range<String.Index>(start: start, end: end))
if subCurrentWord != "_" {
createGameWord(character: subCurrentWord)
} else {
let subAnswer = answer.substringWithRange(Range<String.Index>(start: start, end: end))
if subAnswer == character.lowercaseString {
guessIsCorrect = true
createGameWord(character: subAnswer)
} else {
createGameWord(character: "_")
}
}
}
if(!guessIsCorrect) {
guesses = guesses! - 1
}
}
func buildCorrectWord() {
gameWord = ""
for c in word!.characters {
createGameWord(character: "\(c)")
}
}
func createGameWord(character character: String) {
gameWord += "\(character) "
}
func theUserWon() -> Bool {
for ch in gameWord.characters {
if "\(ch)" == "_" {
return false
}
}
return true
}
func theUserLost() -> Bool {
return guesses == 0
}
}
Hangman Word Generator
import Foundation
class HangmanWordGenerator {
//MARK: - Properties
var wordDatabase: NSArray? = nil {
didSet {
print(wordDatabase)
}
}
var level: DifficultyLevel?
//MARK: - Init functions
init(level: DifficultyLevel) {
self.level = level
switch level.rawValue {
case "Easy": wordDatabase = parseJSONForArrayOfWords(filepath: "EasyWords")
case "Medium": wordDatabase = parseJSONForArrayOfWords(filepath: "MediumWords")
case "Hard": wordDatabase = parseJSONForArrayOfWords(filepath: "hardWords")
default: break
}
}
init(filepath: String) {
wordDatabase = parseJSONForArrayOfWords(filepath: filepath)
}
//MARK: - Parse and Generate Functions
func parseJSONForArrayOfWords(filepath filepath: String) -> NSArray? {
let bundle = NSBundle.mainBundle()
let path = bundle.pathForResource(filepath, ofType: "json")!
let jsonData: NSData = NSData(contentsOfFile: path)!
do {
let JSONDict = try NSJSONSerialization.JSONObjectWithData(jsonData, options: NSJSONReadingOptions(rawValue: 0)) as? NSDictionary
if let dictionary = JSONDict {
if let wordList = dictionary["wordList"] as? NSDictionary {
if let database = wordList["list"] as? NSArray {
return database
}
}
}
} catch let error as NSError {
print("\(error)")
}
return nil
}
func generateWord() -> String {
let dataBase = wordDatabase!
let UInt = UInt32(dataBase.count - 1)
let wordNumber = Int(arc4random_uniform(UInt))
return dataBase[wordNumber] as! String
}
}