4を4つ使って任意の数字を作るゲームのJavaScriptによる自動化の試み。
2011/03/19
数字の4を4つ使った組み合わせで任意の自然数を作る有名なゲーム、4つの4(FourFours)について、JavaScriptを用いて可能な限り高速に答えを自動生成させるスクリプトの開発を試みた。
元となっているのはJavaScriptによる4つの数字ゲームのときに作ったコードで、これを簡略化、更に最適化を施した。元となった4つの数字よりも格段に優れたものになった。
このページでは現在、1000以下の自然数を1秒以内(GoogleChromeでの測定、IE8では10秒程度を要する)に求めることに成功し、更に2個を除いて5000以下のほとんど全ての自然数についての解を得ることに成功している。
(2015/04/20)続編ができた。
2011/03/19
全コードはNumCmbFFオブジェクトの内部に作成した。その上で、個々の動作について簡単に説明する。
4つの4は、4を4個使って数式を作るものだ。数式を扱いやすいように、数式とその値を格納する演算オブジェクトを作った。
NumCmbFF.Formu = function(val,comp) { this.value = parseInt(val); this.formula = '["none",'+val+']'; this.complex = (comp)? comp : 0; }
演算オブジェクト、NumCmbFF.Formuは3つの変数を持つ。
valueはその数式の計算結果の数値を持つ。
formulaはその数式の形を持つ。形式は文字列で、一変数演算子は["演算子名",変数1]、二変数演算子は["演算子名",変数1,変数2]で、入力される変数も全く同様の数式の形式を持ち、それらの入れ子構造になっている。これを文字列で格納しておき、最後に読める数式の形に変換する。
complexは数式の複雑さを表す。演算子ごとに複雑さの数値を設定し、演算子を作用させるたびに数値が増えていく。全く同じ結果になる数式や、無駄な演算子を繰り返しただけの数式を消去するため、最も値の小さな結果のみを残して消去されるようにする。
例として加算を挙げる。
NumCmbFF.Formu.add = function(obj1,obj2) { var res = new NumCmbFF.Formu(); res.value = obj1.value+obj2.value; res.formula = '["add",'+obj1.formula+","+obj2.formula+']'; res.complex = obj1.complex+obj2.complex+NumCmbFF.Formu.v.comps[0][0]; return res; }
演算オブジェクトを引数とした各演算子の関数があり、ここにオブジェクトを渡すことで計算結果の演算オブジェクトを得る。
formulaの文字列形式は、そのままスクリプトと認識させると多次元配列に変換されるようになっている。この多次元配列データから読みやすい数式に翻訳する。コードは煩雑なのでここには記載しない。
演算オブジェクトは4の使用回数毎に、1回、2回、3回、4回の4つの配列に格納する。初期値には4,44,444を入れている。
NumCmbFF.v.list = new Array(); NumCmbFF.v.list[0] = [new NumCmbFF.Formu(num)]//1 NumCmbFF.v.list[1] = [new NumCmbFF.Formu(num*11,1)]//2 NumCmbFF.v.list[2] = [new NumCmbFF.Formu(num*111,2)]//3 NumCmbFF.v.list[3] = []//4
この配列を操作する関数は大きく3つある。中身の具体的なコードは複雑なのでここには挙げない。
引数には格納配列listの番号を指定し、指定された番号の配列内の演算オブジェクトに、設定されている回数だけ一変数演算子を適用する。ただし範囲制限の外にはみ出した適用結果は無視されリストに追加されない。
引数には格納配列listの番号として、入力2つと出力1つの3つを指定し、2つの入力リストを変数とした二変数演算子を作用させ、3つ目のリストに出力する。singleSと同じく範囲制限の外にはみ出した適用結果は無視されリストに追加されない。
引数には格納配列listの番号を指定し、リスト内にある演算オブジェクトのうち、同じ値を持つものを、最も複雑さの小さいものを除いて全て消去する。この処理を実行するとリスト内にあるオブジェクトの数値は異なるものが1つずつだけになる。
3つの関数が揃えば、4つの4問題を実行するのは簡単だ。作用は4の使用回数を考え、1+1=2,1+2=3,1+3=4,2+2=4の4回の二変数演算子の適用と、その全てで一変数演算子を適用させれば良い。
//一変数演算子の適用 NumCmbFF.s.singleS(0); NumCmbFF.s.classifyAry(0); /* ----------第2項---------- */ //二変数演算子の適用 NumCmbFF.s.doubleS(0,0,1); NumCmbFF.s.classifyAry(1); //一変数演算子の適用 NumCmbFF.s.singleS(1); NumCmbFF.s.classifyAry(1); /* ----------第3項---------- */ //二変数演算子の適用 NumCmbFF.s.doubleS(0,1,2); NumCmbFF.s.classifyAry(2); //一変数演算子の適用 NumCmbFF.s.singleS(2); NumCmbFF.s.classifyAry(2); /* ----------第4項---------- */ //二変数演算子の適用 NumCmbFF.s.doubleS(0,2,3); NumCmbFF.s.classifyAry(3); NumCmbFF.s.doubleS(1,1,3); NumCmbFF.s.classifyAry(3); //一変数演算子の適用 NumCmbFF.s.singleS(3);
最後に、4つすべてを使った配列から、複雑さの最も低い自然数を抜き出せば解の一覧を得ることができる。
2011/03/19
ツールは初期設定で実行すると、手元の環境ではGoogleChromeを使うと0.5秒程度で1〜1000までの解を得ることに成功している。設定箇所が多いので、各項目について簡単に説明しておく。何れの項目もいたずらに値を増やすと計算が終了せずブラウザが応答しなくなる可能性があるので、注意を要する。
また製作途中の古い物を幾つか残してあるので、リンクしておく。
2011/03/19
スクリプトの結果を使って、1から100までの作り方について吟味してみた。ここでは小数点や小循環小数を一切考えていないので、それらを用いればより簡単に構成できる可能性がある。他の演算子については今後検討を予定している。
1から順調に始めて、18までは四則演算・(累乗)・平方根だけで構成できる。
1 : (4+4)/(4+4) 2 : 4-(4+4)/4 3 : (4+4+4)/4 4 : 4+4*(4-4) 5 : (4+4*4)/4 6 : 4+(4+4)/4 7 : 4+4-4/4 8 : 4+4+4-4 9 : 4+4+4/4 10 : (44-4)/4 11 : 44/√(4*4) 12 : 4*(4-4/4) 13 : √4+44/4 14 : √4+4+4+4 15 : 4*4-4/4 16 : 4+4+4+4 17 : 4/4+4*4 18 : 4-√4+4*4
しかし、これだけでは19は作れない。19を作るには1〜nまでの自然数を全てかけ合わせる階乗!が必要になる。4!=1*2*3*4=24だ。この調子で38まで作ることができる。
19 : 4!-(4+4/4) 20 : 4*(4+4/4) 21 : 4!+4/4-4 22 : √4+4+4*4 23 : (4*4!-4)/4 24 : 4+4+4*4 25 : (4+4*4!)/4 26 : 4!+(4+4)/4 27 : 4+4!-4/4 28 : 4*(4+4)-4 29 : 4!+4+4/4 30 : 4*(4+4)-√4 31 : 4!+(4+4!)/4 32 : 4*4+4*4 33 : (√4+(√√√4)^4!)/√4 34 : √4+4*(4+4) 35 : 4!+44/4 36 : 4+4*(4+4) 37 : 4!+(√4+4!)/√4 38 : 44-(√4+4)
中でも33は面白い。33は平方根を3度使用して4の8乗根を得、これを4!乗することで4^3を得ている。(4^3+2)/2=32+1=33だ。
39以上はさらに総和を使用する必要がある。Σnと書いて、1〜nまでの自然数を全て足した数を意味する。Σ4=1+2+3+4=10、というふうに。Σの使用を許可すると、一気に100まで作ることができる。それどころか、1000まで全て作ることができてしまう。1000までの答えは、計算スクリプトの初期設定で計算すれば直ぐに答えを見ることができる。
39 : 4*Σ4-4/4 40 : 4*(√4+4+4) 41 : 4/4+4*Σ4 42 : √4+44-4 43 : 44-4/4 44 : 4+44-4 45 : 4/4+44 46 : 4+44-√4 47 : 4!+4!-4/4 48 : 4*(4+4+4) 49 : 4!+4!+4/4 50 : √4+4+44 51 : Σ(√4+4+4)-4 52 : 4+4+44 53 : Σ(√4+4+4)-√4 54 : (√4+4)^4/4! 55 : Σ((44-4)/4) 56 : 4!+4*(4+4) 57 : √4+Σ(√4+4+4) 58 : (4^4-4!)/4 59 : 4+Σ(√4+4+4) 60 : 4*4*4-4 61 : 4*4*4-Σ(√4) 62 : 4*4*4-√4 63 : (4^4-4)/4 64 : (4+4)*(4+4) 65 : (4+4^4)/4 66 : √4+4*4*4 67 : Σ(√4)+4*4*4 68 : 4+4*4*4 69 : Σ(4!-4/4)/4 70 : (4!+4^4)/4 71 : (Σ(4!)-4*4)/4 72 : 4+4!+44 73 : (Σ(4!)-(4+4))/4 74 : √4+4*4!-4! 75 : 4+Σ(4!)/4-4 76 : 4*(4!-4)-4 77 : (Σ(4!)+4+4)/4 78 : 4*(4!-4)-√4 79 : (Σ(4!)+4*4)/4 80 : 4*(4+4*4) 81 : (4-4/4)^4 82 : √4+4*(4!-4) 83 : 4+4+Σ(4!)/4 84 : 4+4*(4!-4) 85 : 4+(Σ(4-√4))^4 86 : √4*44-√4 87 : √4+4+(Σ(√4))^4 88 : 44+44 89 : 4+4+(Σ(√4))^4 90 : 4*4!-(√4+4) 91 : 4*4+Σ(4!)/4 92 : 4+√4*44 93 : 4*4!-Σ(4-√4) 94 : √4+4*4!-4 95 : 4*4!-4/4 96 : 4!*(4+4-4) 97 : 4/4+4*4! 98 : 4-√4+4*4! 99 : (√(Σ4))^4-4/4 100 : 4*(4!+4/4)
1000未満で面白い解を幾つか抜粋。
138:分子が全て階乗。
159:初めて出現するΣ2重式。
162:平方根の3重式。
210:階乗式の多重分数。
511:平方根ばかりの式。
767:初めて出現するΣの3重式。
2011/03/19
作成したスクリプトで広い範囲を調べた結果を掲載。5000以下を対象にできるだけ広い範囲で調べた結果、上記ページのような結果を得た。全リストはページ参照。
小数点をカットし、上限値がそこそこの値では5000以下の答えのうち、4992個までは簡単に見つけることができる。残り8個のうち2個の作り方は現時点では不明で、さらに範囲を広げて見つけた6つの式は、4つの4の中でも飛び抜けて難解で巨大な数を経由するものだ。その6つの数式表現を並べておく。動作概要にあった3つの関数の動作だけで、これほど複雑な数式まで踏み込むことができた。