Protocol Oriented Enum

Welcome to Lesson 4 of Advanced Enum. So far, you’ve interacted protocols with structs and classes. Today, let us spice things up with enums. By the end of this lesson, you will learn how to create a simple game design with what you’ve learned so far. Also, you will get a taste of creating your own custom operators in the Swift Programming Language.

Problem

Let’s combine the best of the best

Game Design

A player could be either .dead or .alive. When alive, the player has a number of hearts/lives. If the number goes to zero, the player becomes dead.

Design Protocol

Create a protocol called, LifeSpan. It contains one property, numberOfHearts and two mutating functions which will be used to increase/decrease a player’s heart.

  1. protocol LifeSpan {
  2. var numberOfHearts: Int { get }
  3. mutating func increaseHeart() // heart +1
  4. mutating func getAttacked() // heart -1
  5. }

Design Enum

Create an enum called Player. It conforms to LifeSpan. There are two cases. The object can be either dead or alive. The alive case contains an associated value called currentHeart. It also contains a gettable computed property, numberOfHearts. numberOfHearts is determined based on whether self is case or alive.

  1. enum Player: LifeSpan {
  2. case dead
  3. case alive(currentHeart: Int)
  4. var numberOfHearts: Int {
  5. switch self {
  6. case .dead: return 0
  7. case let .alive(numberOfHearts): return numberOfHearts
  8. }
  9. }
  10. mutating func increaseHeart() {
  11. switch self {
  12. case .dead:
  13. self = .alive(currentHeart: 1)
  14. case let .alive(numberOfHearts):
  15. self = .alive(currentHeart: numberOfHearts + 1)
  16. }
  17. }
  18. mutating func getAttacked() {
  19. switch self {
  20. case .alive(let numberOfHearts):
  21. if numberOfHearts == 1 {
  22. self = .dead
  23. } else {
  24. self = .alive(currentHeart: numberOfHearts - 1)
  25. }
  26. case .dead:
  27. break
  28. }
  29. }
  30. }

Important: The break keyword is used to escape out of the switch statement.

Play Game

Let us test. Begin with .dead.

  1. var state = Player.dead // .dead
  2. state.increaseHeart() // 1
  3. state.numberOfHearts // 1
  4. state.increaseHeart() // 2
  5. state.getAttacked() // 1
  6. state.getAttacked() // 0, .dead
  7. state.numberOfHearts // 0

Custom Operators (Taste)

First design a enum, GameAction.

  1. enum GameAction {
  2. case Start
  3. case Pause
  4. case Stop
  5. case Restart(delay: Int)
  6. }

Check whether == works.

  1. GameAction.Stop == GameAction.Stop // Error

You may create your own operator. Follow the code below.

  1. func ==(lhs: GameAction, rhs: GameAction) -> Bool {
  2. switch (lhs, rhs) {
  3. case (.Start, .Start), (.Pause, .Pause), (.Stop, .Stop):
  4. return true
  5. case let (.Restart(lhsDelay), .Restart(rhsDelay)):
  6. return lhsDelay == rhsDelay
  7. default:
  8. return false
  9. }
  10. }
  11. GameAction.Restart(delay: 10) == GameAction.Restart(delay: 10) // true

Note: You will more in de-tail in Chapter 8: Advanced Swift.

Source Code

7004_protocol_enum.playground

Conclusion

Some may feel uncomfortable with the excessive usage of enums. That is good. You are challenged by new ways of thinking. However, you are right. You may not need to use enums. Just like protocols, it could be an overkill for certain implementations. In the following lesson, you will learn a recursive enum structure to add and multiply numbers. After, I will show you alternatives that are much simpler and more zen. Just like protocols, enums are not the ultimate savior. You have to learn and study every tool to a point you are able to calculate tradeoffs and benefits by foreseeing the future.

Note: Learn Swift with Bob is available on Udemy. If you wish to receive a discount link, you may sign up here.