今日は「ジャマイカ」というおもちゃを持ってきました。ご存知の方は手を挙げてください。半分もいませんね。このジャマイカはイスラエル製の知育玩具です。
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で見るほうがいいでしょう.
- 出版社/メーカー: トモエ算盤
- 発売日: 2006/12/08
- メディア: 新書
- 購入: 1人 クリック: 22回
- この商品を含むブログ (2件) を見る
ではこれの答えを求めるプログラムを,Rubyで書いてみますか…の前に,他の人がやっているか調査したところ,あっさり見つかりました.
JavaScriptで解いています.ソースを見ると,5重ループを使っています.
なのでこれと差別化を図るよう,Rubyでコーディングしていくとしましょう.出来上がったソースはGistに置いています.
特徴は次のとおりです.
- ゴールとなる値を得るために使う数字は,5個固定ではなく,任意個としました.コマンドライン引数より取得し,最初がゴール(2つの黒のサイコロの和),残りの引数が,それを求めるために使う数字列です.
- 固定のループのネストではなく,再帰呼び出しによって,解を求めました.
- 解の出力には,「プログラマモード」と「小学校モード」を用意しました.デフォルト問題(上のAmazonの画像)の最初の解は,それぞれ次のように出力されます.
インスタンス変数@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 朝)