前回記事に引き続き問題を解いていく。
問題はプログラマ脳を鍛える数学パズルより。
今回の問題
1~100までの番号が書かれた100枚のカードが順番に並べられています。最初、すべてのカードは裏返しの状態で置かれています。ある人が2番のカードが表を向くようになります。
次に、別の人が、3番のカードから2枚おきにカードを裏返していきます。また、別の人が、4番のカードから3番おきに、カードを裏返していきます。
このようにn番目のカードからn-1枚おきにカードを裏返す操作を、どのカードの向きも変わらなくなるまで続けたとします。
問題
カードの向きが変わらなくなったとき、裏向きになっているカードの番号をすべて求めてください。
実装手順
①1から100までのカードの配列を作成する。それぞれの番号に表裏の情報を付与する(今回はtrue, falseとする)。
②めくるカード(問題でいう「n」)のループ文を作成する。問題文の通り2から100までにする。
③実際にめくるカードを決めるループ文を作成する。
④めくるカードが表(true)の時は裏(false)に、裏の時は表にする条件文を書く
⑤結果を出力する
書いたPHPコードと出力結果
<?php
$cards = [];
// ①表裏の情報を持つ1から100までのカード配列を作成する
for ($i = 1; $i <= 101; $i++) {
array_push($cards, 'false');
// 添字の番号とカード番号を合わせたいので、101枚作成して添字0のカードを削除する
unset($cards[0]);
}
// ②nをループさせる
for ($number = 2; $number <= 100; $number++) {
// ③nをn間隔でループさせてめくるカードを決める
for ($i = $number; $i <= 100; $i += $number) {
// ④めくるカードが表(true)の時は裏(false)に、裏の時は表にする
if ($cards[$i] === 'true') {
$cards[$i] = '';
// 参照渡しをする
$cards[$i] .= 'false';
} elseif ($cards[$i] === 'false') {
$cards[$i] = '';
$cards[$i] .= 'true';
}
}
}
// ⑤結果を出力する
foreach ($cards as $key => $value) {
if ($value === 'false') {
echo $key;
echo '<br/>';
}
}
// 結果
1
4
9
16
25
36
49
64
81
100
できた~~
平方数が並んでいるのが何か大きな力を感じます。
今回の学び
- ループ文の中で配列の値を置換し出力する際に手間取ったが、「参照渡し」という概念があることを知った。
- カードの表裏の状態を、カードの値とは別に持っておくと操作しやすい