わさっきhb

大学(教育研究)とか ,親馬鹿とか,和歌山とか,とか,とか.

JAMAICA solver

今日は「ジャマイカ」というおもちゃを持ってきました。ご存知の方は手を挙げてください。半分もいませんね。このジャマイカイスラエル製の知育玩具です。
1つの円から6つの円が飛び出したような形をしていて,それぞれの円の部分にサイコロが入っています。黒いサイコロが2つと白いサイコロが5つあります。中心の黒いサイコロには10,20,30,40,50,60と書かれています。ジャマイカをガラガラと振って机に置くと,それぞれのサイコロがランダムに振られた状態になります。
ちょっとやってみましょう。黒のサイコロが20と5。白のサイコロが3,1,5,2,2と出ました。どうやって遊ぶかというと,まず黒のサイコロの和を求めます。20と5をたすと25になります。白のサイコロで出た目すべてをたしたり,ひいたり,かけたり,わったりして,この25という数をつくろうという遊びです。何人かでやって速く25をつくった人が勝ちです。わかったら「ジャマイカ!」と言ってください。
では,3,1,5,2,2を使って25をつくってみてください。
(作業中)
見つけた方は「ジャマイカ!」と言ってくださいね。
参加者 ジャマイカ
はい,どうぞ。
参加者 2÷2+1+3で5になります。これに残った5をかけたら25になります。
はい,正解です。でも,ジャマイカがおもしろいのは,答えが1つではないということです。まだあるでしょう。たとえば,2+3=5です。その5に5をかけて25。2と1が残っていますので2−1=1。それで25×1,あるいは25÷1で25。
こういうゲームです。ルールはわかりましたか。(略)
(『山本良和の算数授業のつくり方 (プレミアム講座ライブ)』pp.50-51)

本にはジャマイカのイラストもありますが,我々としては,Amazonで見るほうがいいでしょう.

ジャマイカ赤色

ジャマイカ赤色

黒は20と1,白は4,1,3,6,4です.….ジャマイカ! 6+4=10,4×3=12,10+12−1=22−1=21を見つけました.
ではこれの答えを求めるプログラムを,Rubyで書いてみますか…の前に,他の人がやっているか調査したところ,あっさり見つかりました.

JavaScriptで解いています.ソースを見ると,5重ループを使っています.
なのでこれと差別化を図るよう,Rubyでコーディングしていくとしましょう.出来上がったソースはGistに置いています.
特徴は次のとおりです.

  • ゴールとなる値を得るために使う数字は,5個固定ではなく,任意個としました.コマンドライン引数より取得し,最初がゴール(2つの黒のサイコロの和),残りの引数が,それを求めるために使う数字列です.
  • 固定のループのネストではなく,再帰呼び出しによって,解を求めました.
  • 解の出力には,「プログラマモード」と「小学校モード」を用意しました.デフォルト問題(上のAmazonの画像)の最初の解は,それぞれ次のように出力されます.
    • プログラマモード:(((1+6)*3)*4)/4 = 21
    • 小学校モード:1×4=4 4÷4=1 1+6=7 3×7=21*1

インスタンス変数@opt_elをtrueにすると,小学校モードになります.その際,計算途中に負数や分数が現れないようにもしています.デフォルト問題で,負数が現れる式には6-(4*(1-4)-3),分数が現れる式には4/(4/(3*(6+1)))などがあります.
アルゴリズムとしては,「4,1,3,6,4を組み合わせて21を得る」を「4,1,3,6を組み合わせて84が得られたら,84/4で21が得られる」というふうに,使える数から一つを取り出し,演算の候補と組み合わせて,サブゴール(21をゴールとしたとき,この例では21*4=84)を求めることにします.
このようなサブゴールの考え方は,『山本良和の算数授業のつくり方』にも「残り4つの数字でどうやって26をつくろうか」(p.53)と記されていて,おそらく少々遊べば誰でも思いつく戦略と思われます.
サブゴールを得るために使用できる数字の数は,必ず,ゴールを得るために使用できる数字の数よりも少なくなっているので,再帰呼び出し*2を繰り返しても停止するという次第です.
ところで,このプログラムは,すべての式を生成していないことが分かっています.というのは,
ruby jamaica.rb 25 1 3 2 4 1
を実行すると,解は440通り得られますが,その中に「(1+3)*(2+4)+1」が見当たりません.
次の注意書きは,今回自作したプログラム(1個と,残りでサブゴールという戦略)にも当てはまるのです.

数を順番に一つずつ加減乗除する計算(例「((((1+2)*3)+4)*5」)に対応しています。括弧同士を組み合わせた計算(例「(1+2)*(3+4)*5」)には対応していません。

JAMAICA(ジャマイカ)自動計算

その種の解も得ようとすると,2個と,残りでサブゴールという戦略も必要になります.当初はそれも行おうとして,配列から漏れなく重複なく,2個の値を順に取り出すメソッドArray#each_twoを定義したのですが,現状でもそれなりの数,解が出てくるので,とりあえず拡張はストップしています.

(最終更新:2013-07-16 朝)

*1:最後は7×3=21じゃないの? と思った方へ…それは2番目の出力です.実のところ「... 3×7=21」と「... 7×3=21」を区別しています.Rubyスクリプトの視点で言うと,解が得られれば文字列を作って配列に追加していき,そのあとsortとuniqにより,並べ替えるとともに重複を取り除いています.

*2:深さ優先探索でもあります.