问题描述
我正在用Xcode开发游戏,需要弄清楚3个数字的所有可能的数学结果。玩家试图使用这三个数字来尽可能接近目标数字。例如,如果目标为10,而您的三个数字分别为8、6和4,则可以使用8 + 6-4。如果目标数字为12,则可以使用8 * 6/4并得到12。运行142种可能的组合并将结果存储在数组中
resultsArray[0] = firstNum+secondNum+thirdNum;
resultsArray[1] = firstNum+secondNum-thirdNum;
resultsArray[2] = firstNum+secondNum*thirdNum;
resultsArray[3] = firstNum+secondNum/thirdNum;
...
resultsArray[143] = thirdNum/(secondNum-firstNum);
然后我正在检查数组中最接近的正确答案,如下所示:
let x = 10 //target number
let closest = resultsArray.enumerated().min( by: { abs($0.1 - x) < abs($1.1 - x) } )!
correctAnswer = resultsArray[closest.offset]
除除零错误外,它都起作用。
我知道有一个更好的方法,但是我已经在网上搜寻并空手而归。 有什么想法吗?
解决方法
这是一个有趣的问题,让您使用Swift的自定义枚举,可选,集,高阶函数(map
)的功能以及从一个函数返回多个值的功能。
144个方程!即使我们有代码,也很难确认您已涵盖所有内容。除以零是一个棘手的情况,需要特别注意。
这是我对这个问题的看法。我的解决方案的目标是:
- 将其分解为易于验证的步骤
- 避免被零除
- 避免分数计算
- 避免使用负数
- 以易于阅读的形式显示方程式
- 找到最接近目标的所有方程式
// Generate all 6 permuations of the 3 numbers.
// Use Set() to remove duplicates
func permuteNumbers(_ a: Int,_ b: Int,_ c: Int) -> [(Int,Int,Int)] {
return Set([[a,b,c],[a,c,b],[b,a,a],[c,a]]).map { ($0[0],$0[1],$0[2]) }
}
enum Operation: String,CaseIterable {
case addition = "+"
case subtraction = "-"
case multiplication = "*"
case division = "/"
}
// Generate all 16 combinations of the 4 operations
func allOperations() -> [(Operation,Operation)] {
var all = [(Operation,Operation)]()
for op1 in Operation.allCases {
for op2 in Operation.allCases {
all.append((op1,op2))
}
}
return all
}
// Return nil on divide by zero.
// Return nil when the result would be a negative number.
// Return nil when the result would be a fraction (not a whole number).
func performOperation(_ a: Int,_ op: Operation) -> Int? {
switch op {
case .addition: return a + b
case .subtraction: return (b > a) ? nil : a - b
case .multiplication: return a * b
case .division: return ((b == 0) || (a % b != 0)) ? nil : a / b
}
}
// Perform (a op1 b) op2 c
// return (result,equation)
func performOp1First(a: Int,b: Int,c: Int,op1: Operation,op2: Operation) -> (Int?,String) {
let str = "(\(a) \(op1.rawValue) \(b)) \(op2.rawValue) \(c)"
if let r1 = performOperation(a,op1) {
if let r2 = performOperation(r1,op2) {
return (r2,str)
}
}
return (nil,str)
}
// Perform a op1 (b op2 c)
// return (result,equation)
func performOp2First(a: Int,String) {
let str = "\(a) \(op1.rawValue) (\(b) \(op2.rawValue) \(c))"
if let r1 = performOperation(b,op2) {
if let r2 = performOperation(a,r1,op1) {
return (r2,str)
}
// Perform a op1 b op2 c - order doesn't matter for (+,+),(+,-),(*,*),and (*,/)
// return (result,equation)
func performNoParens(a: Int,String) {
let str = "\(a) \(op1.rawValue) \(b) \(op2.rawValue) \(c)"
if let r1 = performOperation(a,str)
}
// Search all permutations of the numbers,operations,and operation order
func findBest(a: Int,target: Int) -> (diff: Int,equations: [String]) {
let numbers = permuteNumbers(a,c)
var best = Int.max
var equations = [String]()
for (a,c) in numbers {
for (op1,op2) in allOperations() {
// Parentheses are not needed if the operators are (+,/)
let noparens = [["+","+"],["+","-"],["*","*"],"/"]].contains([op1.rawValue,op2.rawValue])
for f in (noparens ? [performNoParens] : [performOp1First,performOp2First]) {
let (result,equation) = f(a,op1,op2)
if let result = result {
let diff = abs(result - target)
if diff == best {
equations.append(equation)
} else if diff < best {
best = diff
equations = [equation]
}
}
}
}
}
return (best,equations)
}
示例:
print(findBest(a: 8,b: 6,c: 4,target: 10))
(diff: 0,equations: ["8 + 6 - 4","6 + 8 - 4","(6 - 4) + 8","(8 - 4) + 6"])
print(findBest(a: 8,target: 12))
(diff: 0,equations: ["6 * 8 / 4","8 * 6 / 4","(8 / 4) * 6"])
print(findBest(a: 8,target: 4))
(diff: 0,equations: ["6 - (8 / 4)","8 / (6 - 4)"])
print(findBest(a: 8,target: 5))
(diff: 1,"4 + 8 - 6","(8 - 6) + 4","8 - (6 - 4)","8 / (6 - 4)","8 + 4 - 6"])
print(findBest(a: 8,target: 7))
(diff: 1,equations: ["(8 - 6) + 4","(8 - 6) * 4","6 + (8 / 4)","4 * (8 - 6)","8 + 4 - 6","(8 / 4) + 6"])
科林版本
这里是从Swift版本手动翻译过来的Kotlin版本。这是我的第一个Kotlin程序,所以我确定我并不是以最惯用的方式进行任何操作。我在Online Kotlin Playground
上测试了该程序import kotlin.math.abs
// Generate all 6 permuations of the 3 numbers.
// Use Set() to remove duplicates
fun permuteNumbers(a: Int,c: Int): Set<List<Int>> {
return setOf(
listOf(a,c),listOf(a,b),listOf(b,a),listOf(c,a)
)
}
enum class Operation(val string: String) {
ADDITION("+"),SUBTRACTION("-"),MULTIPLICATION("*"),DIVISION("/")
}
fun allOperations(): List<Pair<Operation,Operation>> {
val result = mutableListOf<Pair<Operation,Operation>>()
for (op1 in Operation.values()) {
for (op2 in Operation.values()) {
result.add(Pair(op1,op2))
}
}
return result
}
fun performOperation(a: Int,op: Operation): Int? {
return when (op) {
Operation.ADDITION -> (a + b)
Operation.SUBTRACTION -> if (b > a) { null } else { a - b }
Operation.MULTIPLICATION -> a * b
Operation.DIVISION -> if ((b == 0) || (a % b != 0)) { null} else { a / b }
}
}
// Perform (a op1 b) op2 c
// return (result,equation)
fun performOp1First(a: Int,op2: Operation): Pair<Int?,String> {
val str = "($a ${op1.string} $b) ${op2.string} $c"
performOperation(a,op1)?.also { r1 ->
performOperation(r1,op2)?.also { r2 ->
return Pair(r2,str)
}
}
return Pair(null,equation)
fun performOp2First(a: Int,String> {
val str = "$a ${op1.string} ($b ${op2.string} $c)"
performOperation(b,op2)?.also { r1 ->
performOperation(a,op1)?.also { r2 ->
return Pair(r2,equation)
fun performNoParens(a: Int,String> {
val str = "$a ${op1.string} $b ${op2.string} $c"
performOperation(a,and operation order
fun findBest(a: Int,target: Int): Pair<Int,List<String>> {
val numbers = permuteNumbers(a,c)
var best = Int.MAX_VALUE
var equations = mutableListOf<String>()
for ((a1,b1,c1) in numbers) {
for ((op1,op2) in allOperations()) {
// Parentheses are not needed if the operators are (+,/)
val noparens = listOf(listOf("+","+"),listOf("+","-"),listOf("*","*"),"/"))
.contains(listOf(op1.string,op2.string))
for (f in if (noparens) { listOf(::performNoParens) } else { listOf(::performOp1First,::performOp2First) }) {
val (result,equation) = f(a1,c1,op2)
result?.also { result2 ->
val delta = abs(target - result2)
if (delta == best) {
equations.add(equation)
} else if (delta < best) {
best = delta
equations = mutableListOf(equation)
}
}
}
}
}
return Pair(best,equations)
}
fun main() {
println(findBest(4,6,8,4))
}