1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
| import Foundation //necessary to import this
class CalculatorBrain { //define a class without inherit from any objective-c class private enum Op { //define a private enum case Operand(Double) //for the numbers may be entered case Unaryoperation(String, Double -> Double) //for the operation such as sqrt case Binaryoperation(String, (Double,Double) -> Double) //for the operation such as plus or minus
var description: String { //define a read-only string for enum values get { //without set so this is read-only switch self { //from each enum value itself to figure out the description for each one case .Operand(let operand): return "\(operand)" //in case of numbers, use the number as description case .Unaryoperation(let symbol, _): return symbol case .Binaryoperation(let symbol, _): return symbol //in case of operations, use the symbol as description string, _ just means that we dont care for that } } } } private var opStack = [Op]() //define the opStack for store the numbers or operation symbols as an array private var knownOps = [String: Op]() //define the knownOps for known operations in dictionary for later use init () { //here initiate for the knownOps dictionary knownOps["✕"] = Op.Binaryoperation("✕",*) //* is the build-in operating function that does (Double,Double) -> Double knownOps["÷"] = Op.Binaryoperation("÷") { $0 / $1 } //if the func is the last parameter, then it is legit to leave outside like this knownOps["+"] = Op.Binaryoperation("+",+) //similar to "x" knownOps["−"] = Op.Binaryoperation("−") { $0 - $1 } //also $0 refers to the first operand when passed in, $1 for the second knownOps["√"] = Op.Unaryoperation("√", sqrt) } //for example, knownOps["x"] would be "x" : "x", * private func evaluate(ops:[Op]) -> (result:Double?, remainingOps:[Op]) { //define a private func named evaluate and takes ops as input and two output as result and remainingOps for iteration if necessary if !ops.isEmpty { //only when ops is not empty var remainingOps = ops //for the purpose of manipulating the send-in parameter ops, otherwise it is just constant copy of ops let op = remainingOps.removeLast() //then we really removed the last item in ops and return the last item value to op for next swith process switch op { //swith has to look after every possibility, or you need a default case case .Operand(let operand): return (operand, remainingOps) //in case of number, return a tuple (the number, and the remaining opStack), quite descriptive case .Unaryoperation(_, let operation): //get the certain operation let operandEvaluation = evaluate(remainingOps) //try iteration if let operand = operandEvaluation.result { //only if iteration comes back with the result return (operation(operand),operandEvaluation.remainingOps) //then the operation of the result is returned as first parameter and remaining Ops of the operandEvaluation as the second } case .Binaryoperation(_, let operation): //not so triky if take a deep look let operandEvaluation = evaluate(remainingOps) if let operand1 = operandEvaluation.result { //because it is binary operation which means it need two operands, how to get them, by two .result from twice operandEvaluation let operandEvaluation = evaluate(remainingOps) if let operand2 = operandEvaluation.result { //get the second operand return (operation(operand1,operand2),operandEvaluation.remainingOps) //perform the binary operation, return the result as the first parameter and the remaining opStack for further handling } } } } return (nil, ops) //if ops is empty, return nil and ops which is empty } func evaluate() -> Double? { //only in the swift, we can overload function with the same name let (result, _) = evaluate(opStack) //you see, actually we are doing the evaluate(opStack) return result //and only return the result of it } func pushOperand(operand:Double) -> Double? { //pass in the number and will pass out the number opStack.append(Op.Operand(operand)) //append the number to opStack return evaluate() //result is the number } func performOperation(symbol:String) -> Double? { //pass in the operation symbol and will pass out the operation result if it could if let operation = knownOps[symbol] { //check if the operation is known opStack.append(operation) //if the symbol is known then add to opStack } return evaluate() //try to return of the known operation }
}
|