3

I'm looking to create a function that returns a math equation that can be preformed in ones head (Clearly thats a bit subjective but I'm not sure how else to phrase it).

I want to use the operations +,-,*,/,% and ().

Currently I have this function:

func createMathString() -> String{

let firstNum = Int(arc4random_uniform(300))
let secNum = Int(arc4random_uniform(300))
let exp = Int(arc4random_uniform(4))
print("\(firstNum) \(self.expressions[exp]) \(secNum)")
return "\(firstNum) \(self.expressions[exp]) \(secNum)"

}

where self.expression is an array that contains +,-,*,/.

This function returns a string which is then interpreted using this function:

let question = createMathString()
                let mathExpression = NSExpression(format: question)
                let mathValue = mathExpression.expressionValue(with: nil, context: nil) as? Int

My problems:

1) Division and Multiplication get difficult as numbers get higher

2) I'm not sure had to add the ( ). (Not every problem will consist of them, depends on the number of terms.

3) I want the questions to be easy enough to be completed in someones head but not to easy that I'm reducing the random numbers to 0-50.

I looked for a possible API but could not find one that suited my needs.

huddie96
  • 1,240
  • 2
  • 13
  • 26

1 Answers1

4

I started programming with Turbo Pascal and as Niklaus Wirth said: Algorithms + Data Structure = Programs. You need to define data structures appropriate for your program.

First, some basic data structures. (Swift enum is much more powerful than that in other languages)

enum MathElement : CustomStringConvertible {
    case Integer(value: Int)
    case Percentage(value: Int)
    case Expression(expression: MathExpression)

    var description: String {
        switch self {
        case .Integer(let value): return "\(value)"
        case .Percentage(let percentage): return "\(percentage)%"
        case .Expression(let expr): return expr.description
        }
    }

    var nsExpressionFormatString : String {
        switch self {
        case .Integer(let value): return "\(value).0"
        case .Percentage(let percentage): return "\(Double(percentage) / 100)"
        case .Expression(let expr): return "(\(expr.description))"
        }
    }
}

enum MathOperator : String {
    case plus = "+"
    case minus = "-"
    case multiply = "*"
    case divide = "/"

    static func random() -> MathOperator {
        let allMathOperators: [MathOperator] = [.plus, .minus, .multiply, .divide]
        let index = Int(arc4random_uniform(UInt32(allMathOperators.count)))

        return allMathOperators[index]
    }
}

Now the main class:

class MathExpression : CustomStringConvertible {
    var lhs: MathElement
    var rhs: MathElement
    var `operator`: MathOperator

    init(lhs: MathElement, rhs: MathElement, operator: MathOperator) {
        self.lhs = lhs
        self.rhs = rhs
        self.operator = `operator`
    }

    var description: String {
        var leftString = ""
        var rightString = ""

        if case .Expression(_) = lhs {
            leftString = "(\(lhs))"
        } else {
            leftString = lhs.description
        }
        if case .Expression(_) = rhs {
            rightString = "(\(rhs))"
        } else {
            rightString = rhs.description
        }

        return "\(leftString) \(self.operator.rawValue) \(rightString)"
    }

    var result : Any? {
        let format = "\(lhs.nsExpressionFormatString) \(`operator`.rawValue) \(rhs.nsExpressionFormatString)"
        let expr = NSExpression(format: format)
        return expr.expressionValue(with: nil, context: nil)
    }

    static func random() -> MathExpression {
        let lhs = MathElement.Integer(value: Int(arc4random_uniform(10)))
        let rhs = MathElement.Integer(value: Int(arc4random_uniform(10)))

        return MathExpression(lhs: lhs, rhs: rhs, operator: .random())
    }
}

Usage:

let a = MathExpression(lhs: .Integer(value: 1), rhs: .Integer(value: 2), operator: .divide)
let b = MathExpression(lhs: .Integer(value: 10), rhs: .Percentage(value: 20), operator: .minus)
let c = MathExpression.random()

let d = MathExpression(lhs: .Integer(value: 1), rhs: .Integer(value: 2), operator: .plus)
let e = MathExpression(lhs: .Integer(value: 3), rhs: .Integer(value: 4), operator: .plus)
let f = MathExpression(lhs: .Expression(expression: d), rhs: .Expression(expression: e), operator: .multiply)

let x = MathExpression.random()
let y = MathExpression.random()
let z = MathExpression(lhs: .Expression(expression: x), rhs: .Expression(expression: y), operator: .plus)


print("a: \(a) = \(a.result!)")
print("b: \(b) = \(b.result!)")
print("c: \(c) = \(c.result!)")

print("f: \(f) = \(f.result!)") // the classic (1 + 2) * (3 + 4)
print("z: \(z) = \(z.result!)") // this is completely random
Code Different
  • 90,614
  • 16
  • 144
  • 163