Bronze & Silver Challenge - Ch 15

Here’s what I got for the Silver Challenge. It looks to give me the correct solution. However, any suggestions for optimizing it would be great.

import Foundation

class Vampire: Monster {
   //initialize empty vampire array
   var vampireThrall = [Int]()
    
   //initialize vampireTerrorizing property as bool
   var vampireTerrorizing = false

    override func terrorizeTown() {
        
        //check that a town exist to terrorize
        if town != nil {
            
            //check if vampire is terrorizing
            if vampireTerrorizing == true {
                //add 1 to the vampireThrall array
                vampireThrall.append(1)
                //and decrement the population by 1
                town?.changePopulation(by: -1)
            }
            //call Monster class's implementation of the terrorizeTown function
            super.terrorizeTown()
        }
    }
}

Here’s what I input into main.swift…

import Foundation


var myTown = Town()
myTown.changePopulation(by: 500)
let fredTheZombie = Zombie()
fredTheZombie.town = myTown
fredTheZombie.terrorizeTown()
fredTheZombie.town?.printDescription()


var aTown = Town()
let vickyTheVampire = Vampire()
vickyTheVampire.town = aTown
vickyTheVampire.terrorizeTown()
vickyTheVampire.town?.printDescription()


and here’s the final result in main.swift…

Monster is terrorizing a town!
Population: 5912, number of stoplights: 4
Monster is terrorizing a town!
Population: 5422, number of stoplights: 4
Program ended with exit code: 0

Again any suggestions to improve or something I did wrong would be greatly appreciated.

Hi

The attribute vampireTerrorizing that you have is initialised to false but never modified as far as I can see so it doesn’t look like the code after

if vampireTerrorizing == true {

is ever executed

Never modified? So I need to implement some sort of switch on the vampireTerrorizing bool?

Before doing that, ask yourself: when terrorizeTown is executed, could the vampire not be terrorizing the town? Would it ever make sense for that variable to be false?

First of all I think you should look at what JonAult wrote because that is much more important here.

But in general, of course you need to change your attributes and variables somehow. Either from inside the class or like in this instance where it is a public attribute from other class or main.swift

Okay so you’re saying that where I have

super.terrorizeTown( )

will only execute if vampireTerrorizing is true so initializing…

var vampireTerrorizing = false

is unnecessary?

Okay yeah I see I need to have the variables change

Given the following input…

var myTown = Town()
var aTown = Town()
myTown.changePopulation(by: 500)
let vickyTheVampire = Vampire()
vickyTheVampire.town = aTown
vickyTheVampire.terrorizeTown()
vickyTheVampire.town?.printDescription()
vickyTheVampire.terrorizeTown()
vickyTheVampire.town?.printDescription()
vickyTheVampire.terrorizeTown()
vickyTheVampire.town?.printDescription()

I get the following output (haven’t changed name to “Vampire” yet)…

Monster is terrorizing a town!
Population: 5422, number of stoplights: 4
Monster is terrorizing a town!
Population: 5422, number of stoplights: 4
Monster is terrorizing a town!
Population: 5422, number of stoplights: 4
Program ended with exit code: 0

So it doesn’t work. Still working on it

@Tiberius

This code now works…

Vampire.swift

import Foundation

class Vampire: Monster {
   //initialize empty vampire array
   var vampireThrall = [Int]()
    
   //initialize vampireTerrorizing property as bool
    var vampireTerrorizing: Bool = true

    override func terrorizeTown() {
        
        //check that a town exist to terrorize
        if town != nil {
            
            //check if vampire is terrorizing
            if vampireTerrorizing {
                //add 1 to the vampireThrall array
                vampireThrall.append(1)
                //and decrement the population by 1
                town?.changePopulation(by: -1)
            }
            //call Monster class's implementation of the terrorizeTown function
            super.terrorizeTown()
        }
    }
}

Output:

Monster is terrorizing a town!
Population: 5421, number of stoplights: 4
Monster is terrorizing a town!
Population: 5420, number of stoplights: 4
Monster is terrorizing a town!
Population: 5419, number of stoplights: 4
Program ended with exit code: 0

I just have to change “Monster” to “Vampire”

@Tiberius

What I was trying to suggest is that you don’t need the vampireTerrorizing property at all.

But if you’re going to keep it, then you should move the super.terrorizeTown() call inside the if statement, so that it is only called if vampireTerrorizing is true. With what you have now, if vampireTerrorizing is false you won’t change the town population or add to the vampire’s list of thralls but you’ll still print the “Monster is terrorizing a town!” message, which doesn’t make sense. Either the vampire is terrorizing the town or it isn’t.

It’s been a while since I looked at this, but if I remember correctly the monster class has a name variable, so when you create your vampire you should set the name of your instance to vampire.

You should also include a check to make sure the population isn’t 0, otherwise you could be generating negative numbers.

In the spirit of vampires, when I did this challenge I took it one step further. Every time a vampire creates a thrall, the next attack consumes more population, however since baby vampires are notorious from destroying their prey, I left it as only +1 one thrall being created.

That all said, I’m not a big of checking for nil (that feels so Obj-C or C++), you’re better off doing something like:

if let population = town?.population {
    // insert logic here
}

Okay like this right?

import Foundation

class Vampire: Monster {
   //initialize empty vampire array
   var vampireThrall = [Int]()

    
    
   //initialize vampireTerrorizing property as bool
    var vampireTerrorizing: Bool = true

    override func terrorizeTown() {
        
        //check that a town exist to terrorize
        if let population = town?.population  {
            
            //check if vampire is terrorizing
            if vampireTerrorizing && population > 0 {
                //add 1 to the vampireThrall array
                vampireThrall.append(1)
                //and decrement the population by 1
                town?.changePopulation(by: -1)
                
                 //call Monster class's implementation of the terrorizeTown function
                super.terrorizeTown()
                
            }
        }
    }
}

“It’s been a while since I looked at this, but if I remember correctly the monster class has a name variable, so when you create your vampire you should set the name of your instance to vampire.”

You mean like this?

 var vampireThrall = [Int]()
 var name = "Vampire"

It gives me the error:


Cannot override with a stored property 'name'

So do I have to override the name variable?

But here’s the rest the code so far with the optional town population and checking for a population > 0 you suggested:


import Foundation

class Vampire: Monster {
   //initialize empty vampire array
   var vampireThrall = [Int]()

   //initialize vampireTerrorizing property as bool
    var vampireTerrorizing: Bool = true

    override func terrorizeTown() {
        
        //check that a town exist to terrorize
        if let population = town?.population  {
            
            //check if vampire is terrorizing
            if vampireTerrorizing && population > 0 {
                //add 1 to the vampireThrall array
                vampireThrall.append(1)
                //and decrement the population by 1
                town?.changePopulation(by: -1)
                
                 //call Monster class's implementation of the terrorizeTown function
                super.terrorizeTown()
                
            }
        }
    }
}

1 Like

You don’t want to declare a new name variable, you just need to change the value of the one you already have (which was inherited from Monster).

But in order to do that, you’ll have to declare an initializer function for Vampire (which the book doesn’t talk about until Chapter 17). If you haven’t gotten to that yet, the init() function is getting called automatically when a new Vampire object is created. The compiler creates a default init() for you, but you can explicitly define one yourself if needed.

    override init()
    {
        super.init()
        name = "Vampire"
    }

The updated terrorizeTown looks pretty good. :+1:

You don’t need to override. In your main.swift file when you created your vampire, the monster class already has a name property. So you just need to set it. So something like this:

let klausTheVampire = Vampire()
klausTheVampire.town = myTown
klausTheVampire.name = "Vampire"
klausTheVampire.terrorizeTown()
klausTheVampire.town?.printDescription()
1 Like

This is my Bronze Challenge:

struct Town {
var population = 10
var numberOfStoplights = 4

func printTownDescription() {
    print("Population: \(population), number of stoplights: \(numberOfStoplights).")
}

mutating func changePopulation(amount: Int) {
    population += amount
    population = population < 0 ? 0 : population
    }
}

This is my silver challenge:

class Vampire: Monster {
var vampire: [Victim]? = []

override func terrorizeTown() {
    vampire?.append(.thrall)
    town?.changePopulation(amount: -1)
    super.terrorizeTown()
    }
}

enum Victim {
   case thrall
}
1 Like

I’m curious about why you created var vampireTerrorizing: Bool = true? If you’re already calling Vampire.terrorizeTown(), then it doesn’t seem like you would need the additional check in at if vampireTerrorizing && population > 0. You’ve already called the method that that is part the Vampire class, which means you know that when this is called, it’s a vampire that is terrorizing the town.

Good job so far. It looks like you’re almost there.

ok, my answer is still that odd
import Foundation
//Zombie类继承父类Monster的所有属性和方法
class Zombie:Monster{
//创建变量类型为bool,值为true
var walksWithLimp = true;
//获取并重写父类方法
//如果town 为true 那么每执行一次,population就会-6000
final override func terrorizeTonw() {
//检测即将减少的人口是否大于当前人口
if town!.populatiom > 6000{
town?.changePopulation(by: -6000);
print(“僵尸攻击了小镇”);
super.terrorizeTonw();
//打印出僵尸攻击之后的人口
print(“现在还有(town!.populatiom)人存活”);
}else{
print(“僵尸攻击了小镇”);
town!.populatiom = 0;
print(“现在还有(town!.populatiom)人存活”);
}
}
}

My solution to the silver challenge

import Foundation

class Vampire: Monster {
    var vampireThrall: [String] = []

    override func terrorizeTown() {
        if town != nil {
            if (town?.population)! > 0 {
               town?.changePopulation(by: -1)
                vampireThrall.append("\(name)")
                print(vampireThrall)
            } else {
               town?.population = 0
            }
        super.terrorizeTown()
        }
    }
}