24 game/Solve: Difference between revisions

Content added Content deleted
m (→‎{{header|Phix}}: added syntax colouring the hard way)
(Added Wren)
Line 9,038: Line 9,038:
((7-8)+5)*6
((7-8)+5)*6
((5-8)+7)*6
((5-8)+7)*6
</pre>

=={{header|Wren}}==
{{trans|Kotlin}}
{{libheader|Wren-dynamic}}
<lang ecmascript>import "random" for Random
import "/dynamic" for Tuple, Enum, Struct

var N_CARDS = 4
var SOLVE_GOAL = 24
var MAX_DIGIT = 9

var Frac = Tuple.create("Frac", ["num", "den"])

var OpType = Enum.create("OpType", ["NUM", "ADD", "SUB", "MUL", "DIV"])

var Expr = Struct.create("Expr", ["op", "left", "right", "value"])

var showExpr // recursive function
showExpr = Fn.new { |e, prec, isRight|
if (!e) return
if (e.op == OpType.NUM) {
System.write(e.value)
return
}
var op = (e.op == OpType.ADD) ? " + " :
(e.op == OpType.SUB) ? " - " :
(e.op == OpType.MUL) ? " x " :
(e.op == OpType.DIV) ? " / " : e.op
if ((e.op == prec && isRight) || e.op < prec) System.write("(")
showExpr.call(e.left, e.op, false)
System.write(op)
showExpr.call(e.right, e.op, true)
if ((e.op == prec && isRight) || e.op < prec) System.write(")")
}

var evalExpr // recursive function
evalExpr = Fn.new { |e|
if (!e) return Frac.new(0, 1)
if (e.op == OpType.NUM) return Frac.new(e.value, 1)
var l = evalExpr.call(e.left)
var r = evalExpr.call(e.right)
var res = (e.op == OpType.ADD) ? Frac.new(l.num * r.den + l.den * r.num, l.den * r.den) :
(e.op == OpType.SUB) ? Frac.new(l.num * r.den - l.den * r.num, l.den * r.den) :
(e.op == OpType.MUL) ? Frac.new(l.num * r.num, l.den * r.den) :
(e.op == OpType.DIV) ? Frac.new(l.num * r.den, l.den * r.num) :
Fiber.abort("Unknown op: %(e.op)")
return res
}

var solve // recursive function
solve = Fn.new { |ea, len|
if (len == 1) {
var final = evalExpr.call(ea[0])
if (final.num == final.den * SOLVE_GOAL && final.den != 0) {
showExpr.call(ea[0], OpType.NUM, false)
return true
}
}
var ex = List.filled(N_CARDS, null)
for (i in 0...len - 1) {
for (j in i + 1...len) ex[j - 1] = ea[j]
var node = Expr.new(OpType.NUM, null, null, 0)
ex[i] = node
for (j in i + 1...len) {
node.left = ea[i]
node.right = ea[j]
for (k in OpType.startsFrom+1...OpType.members.count) {
node.op = k
if (solve.call(ex, len - 1)) return true
}
node.left = ea[j]
node.right = ea[i]
node.op = OpType.SUB
if (solve.call(ex, len - 1)) return true
node.op = OpType.DIV
if (solve.call(ex, len - 1)) return true
ex[j] = ea[j]
}
ex[i] = ea[i]
}
return false
}

var solve24 = Fn.new { |n|
var l = List.filled(N_CARDS, null)
for (i in 0...N_CARDS) l[i] = Expr.new(OpType.NUM, null, null, n[i])
return solve.call(l, N_CARDS)
}

var r = Random.new()
var n = List.filled(N_CARDS, 0)
for (j in 0..9) {
for (i in 0...N_CARDS) {
n[i] = 1 + r.int(MAX_DIGIT)
System.write(" %(n[i])")
}
System.write(": ")
System.print(solve24.call(n) ? "" : "No solution")
}</lang>

{{out}}
Sample run:
<pre>
5 4 2 6: (5 + 4) x 2 + 6
5 3 2 9: (5 - 2) x 9 - 3
4 8 4 3: ((4 + 8) - 4) x 3
3 8 4 7: 8 - (3 - 7) x 4
7 9 9 2: No solution
1 6 5 5: (1 + 5) x 5 - 6
3 2 7 8: (8 - (3 - 7)) x 2
2 2 8 8: (2 + 2) x 8 - 8
6 4 2 5: (6 - 2) x 5 + 4
9 2 1 6: 9 x 2 x 1 + 6
</pre>
</pre>