【Perl】ランダムな文字列から指定された文字列を目で探すクイズを作る
2014-06-25-3
[Programming]
ランダムな文字列から指定された文字列を目で探すというクイズの作り方を実装してみました。
「なんのこっちゃ」という人のため、まずは問題です!
【問題】下記の文字列から「なんのこっちゃ」を探してください。
「んこゃなちちっゃなこのこののっっっんんっん
ここのんこんこちこんんなのゃっこゃこちんゃの
なちっなこのんこのこちちっゃこなちっゃなんの
こっちゃんのんのちこちゃなゃなゃんのこっのな
んこんのっんのゃゃっここゃ」
【答え】(黒い部分をクリック)
「■■■■■■■■■■■■■■■■■■■■■
■■■■■■■■■■■■■■■■■■■■■■
■■■■■■■■■■■■■■■■■■■なんの
こっちゃ■■■■■■■■■■■■■■■■■■
■■■■■■■■■■■■■」
おわかりいただけただろうか。
このクイズを作る Perl スクリプトです。
■コード (ranpu.pl):
関数 make_quiz は、ターゲットの文字列(上記では「なんのこっちゃ」)と出力文字列数(上記では100文字)が与えられると、ターゲット文字列が1回だけあらわれる指定の長さの文字列を出力します。ロジックは単純で、ターゲットに含まれる文字をランダムに配置した指定長の文字列を作り、ターゲットが1回のみ現れていたらOK、そうでなければやりなおし、って感じです。
ターゲット文字列が短い場合などこの段階で2回以上現れることが頻発し、ループが終わらないこともあります。例えば「ココア」「あり」「山」とか。ご注意ください。また、出力文字列数に対してターゲットの文字列が相対的に長めの場合もループが終わらなそうですが、それ用の処理をしているので、まあ大丈夫です。
以下、実行例です。出力はコピペの際に適当に fold しています。
■実行例:
- 工場研修の生産性のなさに嫌気が差してきたので...
- もんたメソッドの簡単サンプル[2005-06-01-3]
「なんのこっちゃ」という人のため、まずは問題です!
【問題】下記の文字列から「なんのこっちゃ」を探してください。
「んこゃなちちっゃなこのこののっっっんんっん
ここのんこんこちこんんなのゃっこゃこちんゃの
なちっなこのんこのこちちっゃこなちっゃなんの
こっちゃんのんのちこちゃなゃなゃんのこっのな
んこんのっんのゃゃっここゃ」
【答え】(黒い部分をクリック)
「■■■■■■■■■■■■■■■■■■■■■
■■■■■■■■■■■■■■■■■■■■■■
■■■■■■■■■■■■■■■■■■■なんの
こっちゃ■■■■■■■■■■■■■■■■■■
■■■■■■■■■■■■■」
おわかりいただけただろうか。
このクイズを作る Perl スクリプトです。
■コード (ranpu.pl):
#!/usr/bin/perl use strict; use warnings; use utf8; use open ':utf8'; binmode STDOUT, ":utf8"; binmode STDIN, ":utf8"; while (<>) { chomp; my $key = $_; my ($str, $idx) = make_quiz($key, 100); print "T:$key\nQ:$str\n"; substr($str, $idx, length($key) + 2, "*$key*"); print "A:$str (at $idx)\n"; } sub make_quiz { my ($key, $len) = @_; my @c = split(//, $key); my $klen = length($key); my ($str, @pos); while (@pos != 1) { $str = ""; @pos = (); for (my $i = 0; $i < $len; $i++) { # 文字をランダムに配置 $str .= $c[int(rand(@c))]; } if ($str !~ /$key/) { # $key が長めのとき対策 substr($str, int(rand($len - $klen)), $klen, $key) } for (my $i = 0; $i < $len - $klen; $i++) { # 正解を格納 push @pos, $i if substr($str, $i, $klen) eq $key; } } return $str, $pos[0]; }
関数 make_quiz は、ターゲットの文字列(上記では「なんのこっちゃ」)と出力文字列数(上記では100文字)が与えられると、ターゲット文字列が1回だけあらわれる指定の長さの文字列を出力します。ロジックは単純で、ターゲットに含まれる文字をランダムに配置した指定長の文字列を作り、ターゲットが1回のみ現れていたらOK、そうでなければやりなおし、って感じです。
ターゲット文字列が短い場合などこの段階で2回以上現れることが頻発し、ループが終わらないこともあります。例えば「ココア」「あり」「山」とか。ご注意ください。また、出力文字列数に対してターゲットの文字列が相対的に長めの場合もループが終わらなそうですが、それ用の処理をしているので、まあ大丈夫です。
以下、実行例です。出力はコピペの際に適当に fold しています。
■実行例:
% echo 'ありさん' | ./ranpu.pl T:ありさん Q:りありりあさんさりんさりさあさありさあんりんあんさんんさんんんあ りんさりりんあありんあんんさあんさりあさありさああさささんんああり さんんんんさああんりりんさんあありりんあささあさんりりさんありさあ あん A:りありりあさんさりんさりさあさありさあんりんあんさんんさんんんあ りんさりりんあありんあんんさあんさりあさありさああさささんんあ*あ りさん*んさああんりりんさんあありりんあささあさんりりさんありさあ あん (at 63) % echo 'スリジャヤワルダナプラコッテ' | ./ranpu.pl T:スリジャヤワルダナプラコッテ Q:ダワャラジッダリワラテッジワナルャスダワラワッラテコダララスッコ ジジヤプコダナテワテダルスリスコルジヤダココリワジスリジヤッダスヤ ルャダワスリジャヤワルダナプラコッテリスダリャラリプステジコダヤス ププ A:ダワャラジッダリワラテッジワナルャスダワラワッラテコダララスッコ ジジヤプコダナテワテダルスリスコルジヤダココリワジスリジヤッダスヤ ルャダワ*スリジャヤワルダナプラコッテ*ダリャラリプステジコダヤスプ プ (at 69) % echo 'まだ東京で消耗' | ./ranpu.pl T:まだ東京で消耗 Q:耗東消だだだ京東耗だ消でだ京東耗耗消東まだ東京で消耗東ま京ま京消 東京耗京ま京耗だま耗だででま京京消耗で耗でま耗でま京耗までで耗東で 東でまだで東京京で消東消消京耗だ消京京で耗京京京消だまま東だ耗消京 耗耗 A:耗東消だだだ京東耗だ消でだ京東耗耗消東*まだ東京で消耗*京ま京消東 京耗京ま京耗だま耗だででま京京消耗で耗でま耗でま京耗までで耗東で東 でまだで東京京で消東消消京耗だ消京京で耗京京京消だまま東だ耗消京耗 耗 (at 19)
参考
- 工場研修の生産性のなさに嫌気が差してきたので...
工場研修の生産性のなさに嫌気が差してきたので「ボ」「ン」「ジョ」「ヴィ」をランダムに表示して「ジョン・ボン・ジョヴィ」が揃ったら終了するプログラム作りました pic.twitter.com/xX4pyLbq3s
— YaGi (@yagiyyyy) 2014, 6月 2
- もんたメソッドの簡単サンプル[2005-06-01-3]