今回は昔のGoogleのCMにあった
4つの数字で10を作るやつを
解くプログラムです。

解説動画はこちら



Google Nexus7のCM
「1158で10を作る」ってやつ

使っていいのは + , - , * , / と
括弧 (  ) だけです。

四則計算の結果が10になるような
計算式を作れば良いですね。

計算式が分かっていれば
プログラムを書くのは簡単ですが

計算式そのものが分かっていない場合は
計算式そのものを作ってしまえば良い訳です。

そんな
10パズルを解くためのプログラムを
考えてみましょう。

Pythonでは
eval という
文字列で起こした数式を計算してくれる
関数があるのでこれを使っていきましょう。


数式では数の順番も大事になってきます。
ここらへんを作るには
itertools という
組み合わせや順列を生成する
ライブラリがあるのでこれを使いましょう。


最後に「作る数式」を
どう文字列で表現するかですが

(数1)演算子1(数2)演算子2(数3)演算子3(数4)

こんな感じの文字列を再現してあげれば良いですね。

というわけで
コードはこんな感じになりました。

import itertools

f = '{0}{1}{2}{3}{4}{5}{6}{7}{8}{9}{10}{11}{12}{13}{14}'
pares = [['(','','',')','','','',''],['(','','',')','(','','',')'],['(','','','','',')','',''],
         ['','','(','','',')','',''],['','','(','','','','',')'],['','','','','(','','',')']]

def tenpuzzle(nums):
    for n in itertools.permutations(nums,4):
        for o in itertools.product(['+','-','*','/'],repeat=3):
            for p in pares:
                formula = f.format(p[0],n[0],p[1], o[0], p[2],n[1],p[3], o[1], p[4],n[2],p[5], o[2], p[6],n[3],p[7])
                try:
                    answer = eval(formula)
                    if 10.0==answer:
                        return formula
                except:
                    pass
    return 'nothing'

実際に使ってみると

tenpuzzle([1,1,5,8])
'8/(1-1/5)'
tenpuzzle([3,4,7,8])
'(3-7/4)*8'

こんな感じで
うまく計算式を生成することができました。

これでどんな数字が来ても
10にすることが出来そうですね。

これだけだとつまらなそうなので
1,2,3,4で1-10までの数字を作るのも
作ってみました。

import itertools

f = '{0}{1}{2}{3}{4}{5}{6}{7}{8}{9}{10}{11}{12}{13}{14}'
pares = [['(','','',')','','','',''],['(','','',')','(','','',')'],['(','','','','',')','',''],
         ['','','(','','',')','',''],['','','(','','','','',')'],['','','','','(','','',')']]

def numpuzzle(num):
    for n in itertools.permutations([1,2,3,4],4):
        for o in itertools.product(['+','-','*','/'],repeat=3):
            for p in pares:
                formula = f.format(p[0],n[0],p[1], o[0], p[2],n[1],p[3], o[1], p[4],n[2],p[5], o[2], p[6],n[3],p[7])
                try:
                    answer = eval(formula)
                    if num==answer:
                        return formula
                except:
                    pass
    return 'nothing'

for i in range(1,11):
    a = numpuzzle(i)
    print(i ,'\t', a)
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)+3+4
7 1-(2-4)*3
8 (1-2+3)*4
9 (1*2)+3+4
10 (1+2)+3+4


これについては10パズルの関数を
ほんの少しいじっただけです。

eval関数は
数式のもとになる文字列を
実行することができるので
色々応用が効くと思います。

ダメな場合はエラーになるので
try ~ exceptで囲む必要があるので
そこだけお忘れなく。

今回は4つの数字で10を作る
10パズルを解くプログラムを
作ってみました。

それでは。