もっとコードを書きたい
phpプログラミングを始めて半年以上がたった。その間phpの基本的な文法は一通り学んだが、処理やアルゴリズムに工夫をこらして書く経験も積みたいと思ったので、手始めに「プログラマ脳を鍛える数学パズル」という本の問題を解いてみることにした。
今回の問題
今回の問題は下記のとおりである。
並んでいる数字の各桁の間に四則演算の演算子を入れて計算することにします(演算子を入れない場所があっても構いませんが、最低でも1つは入れるものとします)。
(中略)
できあがった式を計算した結果、「元の数の桁を逆から並べた数字」と同じになるものを考えます。なお、式の計算は数学の順序で行います。
100~999の場合、以下の3つがあります。
351 → 3+51 = 153
621 → 6+21 = 126
886 → 8*86 = 688
問題
1000~9999のうち、上記の条件を満たす数を求めてください
実装手順
実装手順は下記を考えた。
①1000から9999までのループ文を作る
②千の位と百の位、百の位と十の位、十の位と一の位を分け、それぞれの間に加減乗除を差し込む組み合わせを網羅するループ文を作る
③上記で作成した式を計算し、比較対象の4桁数字を反転させた数字と一致するか確認する
書いたPHPコードと問題点、JavaScriptで書き直し
php文は下記のとおりである。
<?php
// 四則演算を格納する配列
// 桁の間に四則演算が入らず数字が連結する場合もあるため、""も入れる
$tools = array("+", "-", "*", "/", "");
// 1000から9999まで数え上げるループ文
for ($i = 1000; $i < 10000; $i++) {
// 千の位と百の位の間に入る四則演算記号を網羅するループ文
for ($j = 0; $j < count($tools); $j++) {
// 百の位と十の位の間に入る四則演算記号を網羅するループ文
for ($k = 0; $k < count($tools); $k++) {
// 十の位と一の位の間に入る四則演算記号を網羅するループ文
for ($l = 0; $l < count($tools); $l++) {
// 四則演算された値を$numberに格納
$number = (substr($i, 0, 1).$tools[$j].substr($i, 1, 1).$tools[$k].substr($i, 2, 1).$tools[$l].substr($i, 3, 1));
// 元の4桁数字を反転させた数字と$numberを比較し、合致すれば出力
if (strrev($i) === $number) {
echo $number;
}
}
}
}
}
ここで1つ問題が発生した。
$tools配列にString型で四則演算記号を入れたが元に戻す方法が分からなかった
ググっても分からなかったため今回はJavaScriptで書き直すことにした。
実装手順はphpとほぼ同じ
<script>
var op = ["+", "-", "*", "/", ""];
for (i = 1000; i < 10000; i++) {
var c = String(i);
for (j = 0; j < op.length; j++) {
for (k = 0; k < op.length; k++) {
for (l = 0; l < op.length; l++) {
val = c.charAt(3) + op[j] + c.charAt(2) + op[k] + c.charAt(1) + op[l] + c.charAt(0);
if (val.length > 4) {
if (i == eval(val)) {
console.log(val + " = " + i);
}
}
}
}
}
}
</script>
答えは5931 = 1395
できた~~
学び
- 頭の中でぼんやりとは解き方は浮かぶが、いざコードで表現しようとすると意外と手間がかかった。今の実力では頭の中でコードが完成することはないので、とにかく書いて体で覚えていこうと思う。
Shut the fuck up and write some code
さっさとコードを書けよハゲ
- substr、strrev、複数のループ処理、まとめておきたい変数の配列格納など実務でも使えそうなアイデアや処理に触れられた。副産物も色々とありそう。