Cesare Cesare - 5 months ago 36
Swift Question

Remove/exclude enum cases in Swift

This is a struct that contains the operations enabled in the game:

struct OperationsEnabled {
var addition = 1
var subtraction = 0 // disabled
var multiplication = 1
var division = 1
}


This is the enum I use to generate simple arithmetic questions:

enum BinaryOperation: String {
case Addition = "+"
case Subtraction = "-"
case Multiplication = "×"
case Division = "÷"

func rangesForDifficulty(difficulty: Difficulty) -> (Range<Int>, Range<Int>) {
switch self {
case .Addition:
switch difficulty {
case .Easy: return (1...10, 1...10)
case .Intermediate: return (10...100, 1...100)
case .Difficult: return (109...999, 109...999)
}
case .Subtraction:
switch difficulty {
case .Easy: return (1...10, 1...10)
case .Intermediate: return (10...100, 1...100)
case .Difficult: return (109...999, 109...999)
}
case .Multiplication:
switch difficulty {
case .Easy: return (1...10, 2...4)
case .Intermediate: return (1...50, 3...7)
case .Difficult: return (10...100, 4...15)
}
case .Division:
switch difficulty {
case .Easy: return (1...10, 2...4)
case .Intermediate: return (1...50, 3...7)
case .Difficult: return (10...100, 4...15)
}
}
}

func apply(number1: Int, _ number2: Int) -> Int {
switch self {
case .Addition:
return number1 + number2
case .Subtraction:
return number1 - number2
case .Multiplication:
return number1 * number2
case .Division:
return number1 / number2
}
}
}

// Let's make a new question
func newQuestion() {
let (range1, range2) = binaryOperation.rangesForDifficulty(difficulty)
let number1 = Int.random(range1)
let number2 = Int.random(range2)
let answer = binaryOperation.apply(number1, number2)
}


I want to filter out the operations. For example, I need to exclude the operations not allowed in the game, but there seems to be no way to use conditionals in here. How can I do it?

Answer

You want to choose a random operation from the available operations. Create an initializer for BinaryOperation that takes OperationsEnabled and creates a BinaryOperation.

init?(enabled: OperationsEnabled) {
    let all: [(BinaryOperation, Int)] = [(.Addition, enabled.addition), (.Subtraction, enabled.subtraction),
             (.Multiplication, enabled.multiplication), (.Division, enabled.division)]
    let avail = all.flatMap { (op, on) in on == 1 ? op : nil }
    if avail.isEmpty {
        return nil
    }
    else {
        let index = Int(arc4random_uniform(UInt32(avail.count)))
        self = avail[index]
    }
}

Usage:

let enabled = OperationsEnabled(addition: 1, subtraction: 1, multiplication: 0, division: 0)
let binaryOperation = BinaryOperation(enabled: enabled)!    

Notes:

  1. This works by first creating a paired list of tuples that contain an operation paired with its availability.
  2. flatMap is used to select just those operations that are available.
  3. If none of the operations were marked as available, then avail will be empty and this failable initializer will return nil.
  4. The operation is chosen randomly from the list of available operations.