Chapter 17, Silver Challenge Solution

I modified the required initializer of the Zombie class to call across the class to the class’s only designated initializer. I moved the default values for walksWithLimp and isFallingApart into the designated initializer’s parameters for limp and fallingApart. I also added the convenience keyword to the required initializer.

//
//  Zombie.swift
//  MonsterTown
//

import Foundation

class Zombie: Monster {
    class override var spookyNoise: String {
        return "Brains..."
    }
    var walksWithLimp: Bool
    private(set) var isFallingApart: Bool
    
    init(limp: Bool,
         fallingApart: Bool,
         town: Town?,
         monsterName: String) {
        walksWithLimp = limp
        isFallingApart = fallingApart
        super.init(town: town, monsterName: monsterName)
    }
    
    convenience init(limp: Bool, fallingApart: Bool) {
        self.init(limp: limp,
                  fallingApart: fallingApart,
                  town: nil,
                  monsterName: "Fred")
        if walksWithLimp {
            print("This zombie has a bad knee.")
        }
    }
    
    convenience required init(town: Town?, monsterName: String) {
        self.init(limp: false,
                  fallingApart: false,
                  town: town,
                  monsterName: monsterName)
    }
    
    deinit {
        print("Zombie \(name) is no longer with us.")
    }
    
    func regenerate() {
        walksWithLimp = false
    }
    
    override func terrorizeTown() {
        if !isFallingApart {
            town?.changePopulation(by: -10)
        }
        super.terrorizeTown()
        regenerate()
    }
}

I added a convenientZombieTwo variable to test that my convenience initializer works.

//
//  main.swift
//  MonsterTown
//

import Foundation

var myTown = Town(population: 0, stoplights: 6)
myTown?.printDescription()
let myTownSize = myTown?.townSize
print(String(describing: myTownSize))
myTown?.changePopulation(by: 1_000_000)
print("Size: \(String(describing: myTown?.townSize)); population: "
      + "\(String(describing: myTown?.population))")

var fredTheZombie: Zombie? = Zombie(limp: false,
                           fallingApart: false,
                           town: myTown,
                           monsterName: "Fred")
fredTheZombie?.terrorizeTown()
fredTheZombie?.town?.printDescription()

var convenientZombie = Zombie(limp: true, fallingApart: false)

// Silver challenge
var convenientZombieTwo = Zombie(town: myTown, monsterName: "Barney")
convenientZombieTwo.terrorizeTown()

print("Victim pool: \(String(describing: fredTheZombie?.victimPool))")
fredTheZombie?.victimPool = 500
print("Victim pool: \(String(describing: fredTheZombie?.victimPool))")
print(Zombie.spookyNoise)
if Zombie.isTerrifying {
    print("Run away!")
}
fredTheZombie = nil

The relevant output is Barney hasn't found a town to terrorize yet... because myTown doesn’t have a population in this sample code.

Silver Challenge
Just added the convenience keyword to call its designated init
required convenience init(town: Town?, monsterName: String)
{
self.init(limp: false, fallingApart: false, town: town, monsterName: monsterName)
}