【スキルチェック過去問題セット 】みんなでしりとり (paizaランク B 相当) 解答例 – PHP編【paiza】
【スキルチェック過去問題セット】 > みんなでしりとり (paizaランク B 相当)
※リンク先へ移動する為には「paiza」へのログインが必要です。
すごく難しかった…><。神経衰弱と同じかなぁっと思ったら見事に躓いた。
神経衰弱との違いはゲームプレイヤーが脱落していくことです。この部分をどう再現するかが鍵でした。「ポインタの操作」でなんとか再現でき、クリアできましたが…半日かかったよぉ( ;∀;)
解答例
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
<?php $input = explode(" ",trim(fgets(STDIN))); $n = $input[0]; $k = $input[1]; $m = $input[2]; $playerarray = array(); $wordarray = array(); $array = array(); $remark = array(); for($i = 0;$i < $n;$i++){ array_push($playerarray,$i+1); } for($i = 0;$i < $k;$i++){ array_push($wordarray,trim(fgets(STDIN))); } for($i = 0;$i < $m;$i++){ array_push($array,trim(fgets(STDIN))); } $judge = 0; for($i = 0;$i < $m;$i++){ if($i == 0){ $playerkey = key($playerarray); } else { if(empty($playerkey)){ reset($playerarray); $playerkey = key($playerarray); } else{ $playerkey = key($playerarray); } } $nowplayer = $playerarray[$playerkey]; //現在のプレイヤー $word = $array[$i]; $headword1 = substr($word,0,1); $wordcheck = in_array($word,$wordarray,true); $remarkcheck = in_array($word,$remark,true); $beforeword = substr($word,-1); //最後の文字を取得する array_push($remark,$word); //発言した単語をリストに追加する if($i == 0 || $judge == 0){ if($wordcheck == false || $remarkcheck == true || $beforeword == "z"){ unset($playerarray[$playerkey]); $playerkey = key($playerarray); } else { $judge = 1; $headword2 = $beforeword; next($playerarray); $playerkey = key($playerarray); } } else { if($wordcheck == false || $remarkcheck == true || $beforeword == "z" || $headword1 != $headword2){ unset($playerarray[$playerkey]); $playerkey = key($playerarray); $judge = 0; } else { $judge = 1; $headword2 = $beforeword; next($playerarray); $playerkey = key($playerarray); } } } $count = count($playerarray); echo $count."\n"; foreach($playerarray as $value){ echo $value."\n"; } ?> |
解答方針
この問題は管理するべき項目が多いことが難易度を押し上げてると思います。まず大きな部分の管理項目として、ゲームに生き残っているプレイヤーを管理する「プレイヤー配列($playerarray)」、発言可能なワードを管理する「ワードリスト($wordarray)」、そして実際のゲームプレイで発言されるワード「ゲームプレイ配列($array)」、最後に既に発言されたワードを管理する配列「発言済み配列($remark)」の配列を活用して答えを導きます。
求める答えは「ゲームに脱落せず残っているプレイヤー」です。ゲームを進めながら、「プレイヤー配列」をどう動かしていくかが鍵となります。それでは各コードを見ていきます。
各情報の取得
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
$input = explode(" ",trim(fgets(STDIN))); //標準入力から情報を取得 $n = $input[0]; //プレイヤー人数 $k = $input[1]; //ワード数 $m = $input[2]; //ゲームのプレイ数 $playerarray = array(); //「プレイヤー配列」の空作成 $wordarray = array(); //「ワードリスト配列」の空作成 $array = array(); //「ゲームプレイ配列」の空作成 $remark = array(); //「発言済み配列」の空作成 for($i = 0;$i < $n;$i++){ array_push($playerarray,$i+1); //「プレイヤー配列」へ情報を入れる } for($i = 0;$i < $k;$i++){ array_push($wordarray,trim(fgets(STDIN))); //「ワードリスト配列」へ情報を入れる } for($i = 0;$i < $m;$i++){ array_push($array,trim(fgets(STDIN))); //「ゲームプレイ配列」へ情報を入れる } $judge = 0; //「ルール2」を守る必要があるかないかを切り替えるフラグ |
ゲームプレイ(しりとり)部分
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
for($i = 0;$i < $m;$i++){ /*-------------------------ゲームプレイ開始前(しりとり発言前)の準備----------------*/ if($i == 0){ //しりとりの一番最初の処理 $playerkey = key($playerarray); //「$playerkey」にポインタがセットされている要素のインデックスキーを入れる } else { //しりとり2番目以降の処理 if(empty($playerkey)){ //「$playerkey」が空ならば… reset($playerarray); //「$playerkey」のポインタを先頭にセットする $playerkey = key($playerarray); //「$playerkey」にポインタがセットされている要素のインデックスキーを入れる } else{ $playerkey = key($playerarray); //「$playerkey」にポインタがセットされている要素のインデックスキーを入れる } } $nowplayer = $playerarray[$playerkey]; //現在のプレイヤー(プレイヤーの決定) $word = $array[$i]; //発言されるワード $headword1 = substr($word,0,1); //発言されるワードの頭文字をいれる $wordcheck = in_array($word,$wordarray,true); //発言されるワードが「ワードリスト」に入っているかチェック $remarkcheck = in_array($word,$remark,true); //発言されるワードが既に発言されたかどうかチェック $beforeword = substr($word,-1); //最後の文字を取得する array_push($remark,$word); //発言した単語をリストに追加する /*-------------------------ゲームプレイ開始前(しりとり発言前)の準備終わり----------------*/ /*------------------------------------------ゲームプレイ-------------------------------*/ if($i == 0 || $judge == 0){ //ゲームの開始、またはルール2を守る必要がない場合 if($wordcheck == false || $remarkcheck == true || $beforeword == "z"){ //「ワードリストにない単語」、「既に発言した単語」、「発言した単語の末尾が"z"」ならば… unset($playerarray[$playerkey]); //発言したプレイヤーを脱落させる(プレイヤー配列から削除する) $playerkey = key($playerarray); //「$playerkey」にポインタがセットされている要素のインデックスキーを入れる } else { //しりとりの結果が通過した場合 $judge = 1; //次のプレイヤーはルール2を守る必要があるフラグを立てる $headword2 = $beforeword; 1; //次のプレイヤーが発言しなければならない頭文字 next($playerarray); //ポインタを一つ進める $playerkey = key($playerarray); //「$playerkey」にポインタがセットされている要素のインデックスキーを入れる } } else { if($wordcheck == false || $remarkcheck == true || $beforeword == "z" || $headword1 != $headword2){ //「ワードリストにない単語」、「既に発言した単語」、「発言した単語の末尾が"z"」、「前回の末尾の文字と発言した頭文字が違う」ならば… unset($playerarray[$playerkey]); //発言したプレイヤーを脱落させる(プレイヤー配列から削除する) $playerkey = key($playerarray); //「$playerkey」にポインタがセットされている要素のインデックスキーを入れる $judge = 0; //次のプレイヤーはルール2を守る必要がないフラグを立てる } else { $judge = 1; //次のプレイヤーはルール2を守る必要があるフラグを立てる $headword2 = $beforeword; //次のプレイヤーが発言しなければならない頭文字 next($playerarray); //ポインタを一つ進める $playerkey = key($playerarray); //「$playerkey」にポインタがセットされている要素のインデックスキーを入れる } } } |
ターンプレイヤーの切り替え
ポイントがセットされているインデックスキーを「$playerkey = key($playerarray)」で取得し、「$nowplayer = $playerarray[$playerkey]」とすることで現在のターンプレイヤーを決定しています。しりとりの結果、次のプレイヤーに切り替わります。しりとりが普通に通過した場合は「next($playerarray)」でポインタを進めればいいのですが、プレイヤーが脱落した場合、「unset($playerarray[$playerkey])」でポイントがセットされているプレイヤーを削除します。このときセットされていたポインタはどのような挙動を行うのでしょうか?
答えは、ポインタは一つ進みます。ポインタが乗っている要素が削除されると自動的に次の要素にポインタが移るんですね。今回はこの原理を利用しています。
ただここで諸注意があります。それは配列の末尾のプレイヤーを削除、並びに「next()」でそれ以上要素がないのにポインタを移動させた場合です。その場合、「false」が返ってくるのですが「$playerkey = key($playerarray);」で変数に入れると変数が空になります。これを利用して発言前の
|
1 2 3 4 5 |
if(empty($playerkey)){ reset($playerarray); $playerkey = key($playerarray); } } |
の部分で「$playerkeyが空の場合、ポインタを先頭に戻し、$playerkeyにポインタがセットされている要素をいれなさい」というコードで、残っている最後のプレイヤーから最初のプレイヤーへターンを回す仕組みを作っています。
これもっといい方法ありそうなんだけどなぁ(;^ω^)