「テンパズル」は 4 桁の数字を 1 桁ずつに分解し、それに四則演算とカッコを使って 10 を作るパズルです。「メイク10」とか「切符番号の問題」と呼ばれることもあります。一般的なルールの場合、数字の順番を入れ替えてもよいのですが、数字を結合させることはできません。今回は 10 になる式だけではなく、いろいろな値で試してみましょう
それでは問題です。+, -, ×, ÷, ( ,) を使って、指定した値となる式を作ってください。すべての問題で符号 - を使うことは禁止します。
解法プログラムは「four fours」のプログラムを改造すれば簡単に作成することができます。説明は省略するので、詳細はプログラムリストをお読みください。
>>> solver0(10, 1, 2, 6, 9) (2 * (9 - 1)) - 6 = 10 6 - ((1 - 9) / 2) = 10 6 + ((9 - 1) / 2) = 10 ((9 - 1) / 2) + 6 = 10 ((9 - 1) * 2) - 6 = 10
>>> solver0(10, 1, 6, 1, 7) (6 / (1 + 1)) + 7 = 10 7 + (6 / (1 + 1)) = 10
>>> solver0(10, 8, 8, 8, 8) ((8 + 8) / 8) + 8 = 10 8 + ((8 + 8) / 8) = 10
>>> solver1(range(1, 11), 2, 3, 4, 5) ((2 - 3) * 4) + 5 = 1 ((2 * 3) + 4) / 5 = 2 (2 * (3 - 4)) + 5 = 3 (2 + 3) + (4 - 5) = 4 (2 * 3) + (4 - 5) = 5 2 + ((3 - 4) + 5) = 6 ((2 * 3) - 4) + 5 = 7 ((2 - 3) + 4) + 5 = 8 2 + ((3 * 4) - 5) = 9 ((2 * 3) - 4) * 5 = 10
>>> solver2(range(1, 20), 1, 4, 1, 5) (1 + 4) + (1 - 5) = 1 (1 - 4) + (1 * 5) = 2 ((1 - 4) + 1) + 5 = 3 ((1 - 1) * 5) + 4 = 4 ((1 - 1) * 4) + 5 = 5 ((1 + 1) * 5) - 4 = 6 (4 - (1 + 1)) + 5 = 7 ((1 * 4) - 1) + 5 = 8 1 + ((4 - 1) + 5) = 9 (1 + 4) + (1 * 5) = 10 (1 + 4) + (1 + 5) = 11 (1 - 4) * (1 - 5) = 12 ((1 + 1) * 4) + 5 = 13 ((1 + 1) * 5) + 4 = 14 ((1 * 4) - 1) * 5 = 15 1 + ((4 - 1) * 5) = 16 1 - (4 * (1 - 5)) = 17 (1 + 1) * (4 + 5) = 18 ((1 * 4) * 5) - 1 = 19 (1 + (4 - 1)) * 5 = 20
>>> solver2(range(1, 21), 2, 4, 1, 6) (2 + 4) + (1 - 6) = 1 (2 * 4) - (1 * 6) = 2 (2 - (4 + 1)) + 6 = 3 (2 - 4) + (1 * 6) = 4 ((2 - 4) + 1) + 6 = 5 ((2 + 1) * 4) - 6 = 6 ((2 * 6) - 1) - 4 = 7 ((2 * 1) * 6) - 4 = 8 ((2 / 4) + 1) * 6 = 9 (2 - 4) * (1 - 6) = 10 2 + ((4 - 1) + 6) = 11 (2 + 4) + (1 * 6) = 12 (2 + 4) + (1 + 6) = 13 (2 * 4) + (1 * 6) = 14 ((2 * 4) + 1) + 6 = 15 (2 * (4 + 1)) + 6 = 16 ((2 * 6) + 1) + 4 = 17 2 * ((4 - 1) + 6) = 18 (2 * (4 + 6)) - 1 = 19 2 + ((4 - 1) * 6) = 20
>>> solver2(range(1, 26), 2, 5, 1, 7) (2 + 5) + (1 - 7) = 1 ((2 * 5) - 1) - 7 = 2 (2 - (5 + 1)) + 7 = 3 (2 - 5) + (1 * 7) = 4 ((2 - 5) + 1) + 7 = 5 2 * ((1 - 5) + 7) = 6 2 / (1 - (5 / 7)) = 7 ((2 + 1) * 5) - 7 = 8 ((2 * 1) * 7) - 5 = 9 (2 * 7) + (1 - 5) = 10 (2 * (1 + 7)) - 5 = 11 ((2 - 1) * 5) + 7 = 12 2 + ((5 - 1) + 7) = 13 (2 + 5) + (1 * 7) = 14 (2 + 5) + (1 + 7) = 15 ((2 * 5) - 1) + 7 = 16 (2 * 5) + (1 * 7) = 17 ((2 * 5) + 1) + 7 = 18 (2 * (5 + 1)) + 7 = 19 ((2 * 7) + 1) + 5 = 20 (2 * (1 + 7)) + 5 = 21 2 * ((5 - 1) + 7) = 22 (2 * (5 + 7)) - 1 = 23 2 * (5 + (1 * 7)) = 24 (2 * (5 + 7)) + 1 = 25
>>> solver2(range(1, 31), 1, 2, 3, 4) (1 * 2) + (3 - 4) = 1 (1 + 2) + (3 - 4) = 2 ((1 * 2) - 3) + 4 = 3 1 + ((2 - 3) + 4) = 4 ((1 + 2) / 3) + 4 = 5 ((1 - 2) + 3) + 4 = 6 1 - ((2 - 4) * 3) = 7 ((1 - 2) + 3) * 4 = 8 ((1 * 2) + 3) + 4 = 9 (1 + 2) + (3 + 4) = 10 1 + ((2 * 3) + 4) = 11 1 + ((2 * 4) + 3) = 12 ((1 + 2) * 3) + 4 = 13 (1 * 2) + (3 * 4) = 14 (1 + 2) + (3 * 4) = 15 ((1 + 3) + 4) * 2 = 16 ((1 + 4) * 3) + 2 = 17 ((1 * 2) + 4) * 3 = 18 1 + ((2 + 4) * 3) = 19 ((1 * 2) + 3) * 4 = 20 1 + ((2 + 3) * 4) = 21 2 * ((3 * 4) - 1) = 22 ((2 * 3) * 4) - 1 = 23 ((1 + 2) + 3) * 4 = 24 1 + (2 * (3 * 4)) = 25
>>> solver2(range(1, 31), 1, 8, 2, 6) ((1 - 8) + 2) + 6 = 1 1 + (8 / (2 + 6)) = 2 (1 - (8 / 2)) + 6 = 3 (1 * 8) + (2 - 6) = 4 (1 + 8) + (2 - 6) = 5 1 + (8 - (6 / 2)) = 6 1 * ((8 + 6) / 2) = 7 1 + ((8 + 6) / 2) = 8 ((8 / 2) - 1) + 6 = 9 (1 * (8 / 2)) + 6 = 10 1 + ((8 / 2) + 6) = 11 ((1 * 8) - 2) + 6 = 12 1 + ((8 - 2) + 6) = 13 8 - ((1 - 2) * 6) = 14 ((8 - 1) + 2) + 6 = 15 ((1 * 8) + 2) + 6 = 16 (1 + 8) + (2 + 6) = 17 ((1 + 2) * 8) - 6 = 18 (8 - 1) + (2 * 6) = 19 (1 * 8) + (2 * 6) = 20 (1 + 8) + (2 * 6) = 21 ((1 * 8) * 2) + 6 = 22 1 + ((8 * 2) + 6) = 23 ((1 + 8) * 2) + 6 = 24 1 + ((8 / 2) * 6) = 25 ((1 + 2) * 6) + 8 = 26 ((1 + 8) / 2) * 6 = 27 (1 - 8) * (2 - 6) = 28 1 + ((8 + 6) * 2) = 29 (1 + (8 / 2)) * 6 = 30
>>>> solver3() 8 / (1 - (1 / 5)) = 10
一般的な規則で、値が 10 になる式が一つだけなのは 1, 1, 5, 8 の一通りです。
#
# tenpuz.py : テンパズル (メイク10, 切符番号の問題)
#
# Copyright (C) 2022 Makoto Hiroi
#
from fractions import Fraction
# 順列
def permutations(n, xs, m = 0, ys = []):
if m == n:
ps = xs[:m]
return ys if ps in ys else ys + [ps]
else:
for i in range(m, len(xs)):
xs[i], xs[m] = xs[m], xs[i]
ys = permutations(n, xs, m + 1, ys)
xs[i], xs[m] = xs[m], xs[i]
return ys
# 構文木
class Lf:
def __init__(self, x):
self.item = x
class Nd:
def __init__(self, x, l, r):
self.op = x
self.left = l
self.right = r
# 式の表示
def print_expr(expr, d):
if isinstance(expr, Lf):
print(expr.item, end='')
else:
if d > 0: print('(', end='')
print_expr(expr.left, d + 1)
print(f' {expr.op} ', end='')
print_expr(expr.right, d + 1)
if d > 0: print(')', end='')
# 式の計算
def calc_expr(expr):
if isinstance(expr, Lf):
return expr.item
else:
l = calc_expr(expr.left)
r = calc_expr(expr.right)
op = expr.op
if op == '+':
return l + r
elif op == '-':
return l - r
elif op == '*':
return l * r
else:
return l / r
# 四則演算
opls = ['+', '-', '*', '/']
# 式の生成
def make_expr(n, a, b, c, d):
ans = []
for x in opls:
for y in opls:
for z in opls:
for e in [Nd(x, Nd(y, a, b), Nd(z, c, d)),
Nd(x, a, Nd(y, b, Nd(z, c, d))),
Nd(x, Nd(y, Nd(z, a, b), c), d),
Nd(x, a, Nd(y, Nd(z, b, c), d)),
Nd(x, Nd(y, a, Nd(z, b, c)), d)]:
try:
r = calc_expr(e)
if r.denominator == 1 and r.numerator == n:
ans.append(e)
except ZeroDivisionError:
pass
return ans
#
# 解法
#
# 値が n となる数式を求める
def solver0(n, a, b, c, d):
for xs in permutations(4, [a, b, c, d]):
ys = [Lf(Fraction(x, 1)) for x in xs]
for e in make_expr(n, *ys):
print_expr(e, 0)
print(' =', n)
# ns の中の値となる式を求める
# 式は一つだけ出力する
# 数字の並び替え禁止
def solver1(ns, a, b, c, d):
xs = [Lf(Fraction(x, 1)) for x in [a, b, c, d]]
for n in ns:
es = make_expr(n, *xs)
if es:
print_expr(es[0], 0)
print(' =', n)
# ns の中の値となる式を求める
# 式は一つだけ出力する
def solver2(ns, a, b, c, d):
for n in ns:
for xs in permutations(4, [a, b, c, d]):
ys = [Lf(Fraction(x, 1)) for x in xs]
es = make_expr(n, *ys)
if es:
print_expr(es[0], 0)
print(' =', n)
break
# 数値を桁に分解
def split_number(n, d):
xs = []
for _ in range(d):
xs.append(n % 10)
n //= 10
return xs
# リストを数値に変換
def to_number(xs):
n = 0
for x in xs:
n = n * 10 + x
return n
# 問題 10 の解法
def solver3():
table = [False] * 10000
for n in range(10000):
if table[n]: continue
xs = split_number(n, 4)
es = []
for ys in permutations(4, xs):
table[to_number(ys)] = True
zs = [Lf(Fraction(y, 1)) for y in ys]
es += make_expr(10, *zs)
if len(es) == 1:
print_expr(es[0], 0)
print(' =', 10)