M.Hiroi's Home Page

Puzzle DE Programming

テンパズル

[ Home | Puzzle ]

問題の説明

「テンパズル」は 4 桁の数字を 1 桁ずつに分解し、それに四則演算とカッコを使って 10 を作るパズルです。「メイク10」とか「切符番号の問題」と呼ばれることもあります。一般的なルールの場合、数字の順番を入れ替えてもよいのですが、数字を結合させることはできません。今回は 10 になる式だけではなく、いろいろな値で試してみましょう

それでは問題です。+, -, ×, ÷, ( ,) を使って、指定した値となる式を作ってください。すべての問題で符号 - を使うことは禁止します。

  1. 数字 1, 2, 6, 9, 値が 10 になる式
  2. 数字 1, 6, 1, 7, 値が 10 になる式
  3. 数字 8, 8, 8, 8, 値が 10 になる式
  4. 数字 2, 3, 4, 5, 値が 1 から 10 になる式、数字の並べ替えは禁止
  5. 数字 1, 4, 1, 5, 値が 1 から 20 になる式
  6. 数字 2, 4, 1, 6, 値が 1 から 20 になる式
  7. 数字 2, 5, 1, 7, 値が 1 から 25 になる式
  8. 数字 1, 2, 3, 4, 値が 1 から 25 になる式
  9. 数字 1, 8, 2, 6, 値が 1 から 30 になる式
  10. +, -, ×, ÷, ( ,) を使い、数字の並び替えができる規則で、値が 10 となる式が一つしかない数字はあるか。
    あるならば、その数字を求めよ。

解法プログラムは four fours のプログラムを改造すれば簡単に作成することができます。説明は省略するので、詳細は プログラムリスト をお読みください。

●参考 URL

  1. テンパズル - Wikipedia












●解答1

>>> 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

●解答2

>>> solver0(10, 1, 6, 1, 7)
(6 / (1 + 1)) + 7 = 10
7 + (6 / (1 + 1)) = 10

●解答3

>>> solver0(10, 8, 8, 8, 8)
((8 + 8) / 8) + 8 = 10
8 + ((8 + 8) / 8) = 10

●解答4

>>> 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

●解答5

>>> 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

●解答6

>>> 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

●解答7

>>> 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

●解答8

>>> 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

●解答9

>>> 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

●解答10

>>>> 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)

Copyright (C) 2022 Makoto Hiroi
All rights reserved.

[ Home | Puzzle ]