ここは、技術情報、身の回りに起こった出来事を、「もしかしたらみんなの役に立つかもしれない」と思って書き留めておく場所です。

Image

【PHP】プログラミングゲーム「エンジニアが死滅シタ世界」をやってみた【解答例】

2019年1月26日
 

 

piazaというプログラマ向け学習等のサービスを行っているサイトがあります。

そのコンテンツの一部としてプログラミング学習が出来るゲームがありまして、過去何回か記事に書いた事があります。

過去の記事の一つ→【paiza】プログラミングでアイドルをプロデュースPHP編

今回新たにゲームが追加されたそうなので、遊んでみます。

 

概要

ゲームのタイトルは

エンジニアが死滅シタ世界 ~アンドロイドとふたりぼっちで生きろ~

です。

プログラミング問題が出題され、コードを書いて解答する

感じになります。

プログラミングが好きな人なら面白いのではないかと思います。

百聞は一見に如かずですので、ぜひサイトに行ってみてください。(宣伝ではない)

 

せっかくなので

このページでは、私が記述したPHPでの解答例を出していきたいとます。

いろんなコードを見ると勉強になるので、私以外の人のPHPの勉強になればという思いです。

きっと「皆さんが自分で書いたコード」とは違うと思いますし…

コードを書くにあたって考慮した点も、一緒に記述しています。

 

荒れ果てた警察署

概要

  • ランク:D
  • アイテム:ショート
  • 問題:二つの数字から計算して答えを出す

 

解答例

<?php
echo array_sum(explode(' ', trim(fgets(STDIN)))) % 10;
?> 

 

二つの数字を足して10で割った余りを出力します。自分で足すのもアレなので配列にして勝手に計算させます。

こうしておくと、数字が増えていってもコードがそのままで対応できます。

 

荒れ果てたオフィス

概要

  • ランク:D
  • アイテム:たれ目
  • 問題:重要度が3のタイトルを出力する

 

解答例

<?php
for ($i = trim(fgets(STDIN)); $i > 0; $i --) {
	fscanf(STDIN, '%s %d', $s, $e);
	$o[$e][] = $s;
}
echo implode("\n", $o[3]);
?> 

 

重要度ごとに配列に格納します。

最後に3のものを出力しています。

配列の後ろに追加する[]は非常によく使います。

配列の初期化をしていませんが、本来はちゃんと初期化しましょう。

 

アンドロイドの生産工場

概要

  • ランク:D
  • アイテム:ロング
  • 問題:文字列の奇数文字を取り出す

 

解答例

<?php
echo implode(array_filter(str_split(trim(fgets(STDIN))), function ($k) {
	return $k % 2 == 0;
}, ARRAY_FILTER_USE_KEY));
?> 

 

別に文字列を一文字ずつ飛ばして出力していってもいいのですが、つまらないのでやりません。

str_splitで入力された文字列を、一文字ずつバラバラの配列に変換します。

array_filterは関数の戻り値がtrueの条件で配列をフィルタリングしてくれます。ARRAY_FILTER_USE_KEYを使う事で、関数に値ではなくキー値を渡すことができます。

$k文字目が偶数の場合trueにします。配列なので1文字目(奇数)は0(偶数)から始まります。

implodeで文字列に戻します。

 

錆びついた電波塔

概要

  • ランク:D
  • アイテム:ニーソックス
  • 問題:任意の電波強度以上の回数を出力する

 

解答例

<?php
fgets(STDIN);
echo count(array_filter(explode(' ', trim(fgets(STDIN))), function ($d) {
	return $d > 5;
}));
?> 

 

またarray_filterを使います。

今回は素直に値で判断します。

普通にcount取ればよいです。

 

お金が引き出せない銀行

概要

  • ランク:D
  • アイテム:探索服
  • 問題:お金を引き出し残高を判定する

 

解答例

<?php
$a = trim(fgets(STDIN)) - trim(fgets(STDIN));
echo $a < 0 ? 'error' : $a;
?> 

 

何も言う事はないくらいこのままです。

考慮点は、マイナス演算子の左右どちらが先になるか、くらいですかね。

 

荒れ果てたショップ

概要

  • ランク:C
  • アイテム:街
  • 問題:入力された数字をN桁で0埋め

 

解答例1 - すぐ思いつく版

<?php
fscanf(STDIN, '%d %d %d', $n, $a, $b);
for ($i = $a; $i <= $b; $i ++) {
    printf("%0${n}d\n", $i);
}
?> 

 

0埋めは通常printfで行いますので、そのまま使います。

printfのフォーマット文字列の部分は、ダブルクォーテーションを使うと変数をそのまま埋め込めるため、そうしています。

本来ならば、$nと記述したいところですが、後ろにdがあるため「%nd」という変数だと扱われてエラーとなります。

そのため、変数の区切りを明確にする{}を使用して囲みます。

$aから$bは常識的なループです。

 

解答例2 - range版

<?php
fscanf(STDIN, '%d %d %d', $n, $a, $b);
foreach (range($a, $b) as $i) {
	printf("%0${n}d\n", $i);
}
?> 

 

ループの仕方が違います。rangeで最初に配列を作成しループさせています。

range部分を任意の配列に置き換えることが出来るため、柔軟性が高くなります。

 

解答例3 - array_map版

<?php
fscanf(STDIN, '%d %d %d', $n, $a, $b);
$f = "%0${n}d";
echo implode("\n", array_map(function($i) use ($f) {
	return sprintf($f, $i);
}, range($a, $b)));
?> 

 

もはや、行けるところまで行った感があります。

rangeで配列になったので、出力値も配列にしましょうという事で、array_mapを使用します。

array_mapは配列の要素分、関数を呼び出し、関数の戻り値を配列にしてくれます。

その時に無名関数を使うわけですが、sprintfのフォーマットがスコープ内にないため、useを使いグローバルスコープから持ってきます。JavaScript等では何も書かなくても外の変数を参照することができますが、PHPではuseで明示して持ってくる必要があります。

 

機械の総合病院

概要

  • ランク:C
  • アイテム:ニットセーター
  • 問題:ユーザーが設定するパスワードのチェック

 

解答例

<?php
$t = trim(fgets(STDIN));
echo (preg_match('/(.)\1\1/', $t) == 0 
    && preg_match('/[a-zA-Z]+/', $t) 
    && preg_match('/\d+/', $t) 
    && strlen($t) >= 6) ? 'Valid' : 'Invalid';
?> 

 

ユーザーから入力された値のチェックは、正規表現で行うことが多いです。

今回のチェックでの特殊な条件は「同じ文字を3つ以上連続で使用することはできない」です。

逆に言うと3つ以上の連続を検出しなかった(preg_matchの戻り値が0)ならばOKです。

本来はpreg_matchの戻り値にはFALSEもあるため===を使います。

正規表現

'/(.)\1\1/'

の意味ですが、任意の文字を表す「.」を()で囲みキャプチャしています。それを「\1」で使用することで同じ文字を表しています。

 

学べない学校

概要

  • ランク:C
  • アイテム:おさげ
  • 問題:じゃんけんの勝った数、負けた数を出力

 

解答例

<?php
$j = ['gc'=>1,'pg'=>1,'cp'=>1,'cg'=>2,'gp'=>2,'pc'=>2,'gg'=>0,'pp'=>0,'cc'=>0];
$r = [0, 0, 0];
for ($i = trim(fgets(STDIN)); $i > 0; $i --) {
	$r[$j[str_replace([' ', "\n"], '', fgets(STDIN))]] ++;
}
printf("%d\n%d", $r[1], $r[2]);
?> 

 

このような処理の場合、どれだけ最初にパターンを用意するかでロジックの簡易さが変わります。

上記のような、あらかじめ全パターンが少なく、特殊な条件がない場合、そのまま最初にデータ化しておけば条件分岐が必要なくなります。

データ部さえ差し替えれば良くなるため、後から例えば

「あいこの時も負けにしない?」

のように気軽に言われた場合の変更も、容易にできるようになります。

 

次回

続き→【PHP】プログラミングゲーム「エンジニアが死滅シタ世界」をやってみた その2