小野氏の学習日記

プログラミングや書評を徒然と記載していくブログです

プログラマ脳を鍛える数学パズルを解いてみる 第一弾

どうも、小野氏です。

プログラミングのネタを探していたところ、以下の本を見つけました。

今週は本書のQ2についてRubyで実装したので、そちらについて紹介いたします。

(プログラミング初心者なので温かい目で見守っていただけると幸いです。)

Q2 数列の四則演算

問題(要約)

4桁の数字の各桁の間に四則演算の演算子を入れて計算を行う(演算子を入れない箇所があったもよいが、かならず1つは演算子を入れるものとする) この時、計算結果が元の数の桁を逆から並べた数字と同じになるものを求めよ

3桁の数字だと以下のものが考えられます。

  • 351(3*51=153)
  • 621(6*21=126)
  • 886(8*86)

回答

自分のコードをgistに挙げているので、そちらを紹介します。

ざっくり処理の流れを説明すると以下の通りです。

  1. 変数の宣言
  2. 配列numberに1000~9999までの数字を代入
  3. 配列numberに対して拡張for文で要素となる四桁の数字をそれぞれ取り出し、処理を実施
  4. 配列ope×3に対して、拡張for文でオペランドをそれぞれ取り出し、数式valを構成
  5. 数式valに対して、以下の条件を満たすかを確認
    • valが4文字より多いか(オペランドを少なくとも一つ含むか)
    • 0での割り算が含まれていないか
  6. 0n(nは任意の数字)という形式になっているものを、xとなるようにgsub関数で置換
  7. 数式valを数式評価し、元の四桁の数字を反転したものと一致するかを確認する

解説

上述の記載の6が一番苦労をしたので、そこについてある程度解説します。

最初、6の処理を入れていなかったところ以下のエラーが発生しました。

'eval':(eval):1: Invalid octal digit (SyntaxError)

ぱっと見何のことかわからなかったですが、eval関数にかけて文字列→数式で評価する際に不正な8進数」というエラーが発生したので、おそらく文字列→数式に変換するときに変なことになったと予想しました。

それでRubyでの8進数のprefixを確認したところ、以下の通りでした。

項目 prefix
2進数 0bで始まる数値は 2進数とみなされる
8進数 0で始まる数値は 8進数とみなされる
10進数 0dで始まる数値は10進数とみなされる
16進数 0xで始まる数値は16進数とみなされる

0n(nは任意の数字)という並びでオペランドが挿入されなかった場合、そいつが8進数とみなされエラーが発生している模様。。。

解決するためには、0nという並びのときに0を削除してからeval関数にかける必要があり、0を削除する必要があります。

そのため、gsub関数で「{オペランド}0n」という並びになっている個所を探し、最初の0だけを削除しています。

例えば005など、削除した結果再度8進数と判断されてしまう数字の可能性を考慮して、while文で複数回本処理を施しております。

(複数回処理を行うことで005055と置換されうまくいっているはず。。。)

所感

  • 純粋に処理を考えるのは楽しかったです。
  • 仕事でプログラミングをしないので、メソッドを調べるのに時間がかかってしまいました。慣れていければ嬉しいです。
    • evalとか、gsubとか
  • 本には10分で解けるって書いてありましたが、絶対に無理です。60分くらいは余裕でかかりました。
  • if文3つくらいnestしてるけど、可読性は問題ないのか不安です。

今後も、本書ので解いた問題を週1程度で紹介できればいいかなと思います。

以上