[Perl]らしさをいかして逆FizzBuzzを解いてみた
0 Comments
ひらくん
こんにちは。すっかり波に乗り遅れた感がある逆FizzBuzzに挑戦してみました。私が読んだネタ元はこちらです。
逆FizzBuzz問題 (Inverse FizzBuzz)
おもしろそうだったので自分も挑戦してみました。まあ挑戦と言ってもいつも通り Perl による力技なんですけどね。それではさっそくいってみましょう。
ぱっと問題文を読んだ限り探索するのは100までとかなり狭い範囲なのでここはシンプルに探索用のテーブルを作ってしまうのがわかりやすいです。レインボーアタックならぬモノクロアタック。
まずはFizzをF、BuzzをB、FizzBuzzをC、そのいずれでも無い数字は0として1〜100までのFizzBuzzの結果をずらずら連結します。結果は当然100byteの文字列となります。
00F0BF00FB0F00C00F0BF00FB0F00C
00F0BF00FB0F00C00F0BF00FB0F00C
00F0BF00FB0F00C00F0BF00FB0F00C
00F0BF00FB
次に与えられたFizzBuzzの文字列を検索パターンに置換します。各 F/B/C の間には0個以上の「0」が入りますので仮に与えられた文字が「Fizz Buzz」だとするとこれを「F0*B」という正規表現にするわけです。
つぎに生成した正規表現で検索テーブルにマッチングをかけます。とうぜん複数マッチすることもありますのでその場合は「マッチした文字列が最短のもの=もっとも解を返す数値の範囲がせまい」パターンを解答とします。
数字の範囲ですが検索テーブル内でのbyte位置がそのまま数字の範囲になっているのでバイトを数えて(1byte文字なので単純に文字を数える)範囲を特定します。
以下がソースです。
ソースのダウンロード
結果:
逆FizzBuzz問題 (Inverse FizzBuzz)
おもしろそうだったので自分も挑戦してみました。まあ挑戦と言ってもいつも通り Perl による力技なんですけどね。それではさっそくいってみましょう。
ぱっと問題文を読んだ限り探索するのは100までとかなり狭い範囲なのでここはシンプルに探索用のテーブルを作ってしまうのがわかりやすいです。レインボーアタックならぬモノクロアタック。
まずはFizzをF、BuzzをB、FizzBuzzをC、そのいずれでも無い数字は0として1〜100までのFizzBuzzの結果をずらずら連結します。結果は当然100byteの文字列となります。
00F0BF00FB0F00C00F0BF00FB0F00C
00F0BF00FB0F00C00F0BF00FB0F00C
00F0BF00FB0F00C00F0BF00FB0F00C
00F0BF00FB
次に与えられたFizzBuzzの文字列を検索パターンに置換します。各 F/B/C の間には0個以上の「0」が入りますので仮に与えられた文字が「Fizz Buzz」だとするとこれを「F0*B」という正規表現にするわけです。
つぎに生成した正規表現で検索テーブルにマッチングをかけます。とうぜん複数マッチすることもありますのでその場合は「マッチした文字列が最短のもの=もっとも解を返す数値の範囲がせまい」パターンを解答とします。
数字の範囲ですが検索テーブル内でのbyte位置がそのまま数字の範囲になっているのでバイトを数えて(1byte文字なので単純に文字を数える)範囲を特定します。
以下がソースです。
ソースのダウンロード
#!/usr/bin/perl use strict; use utf8; binmode STDOUT, ":utf8"; #-画面に出力したい文字コード binmode STDERR, ":utf8"; #-エラー出力に使いたい文字コード binmode STDIN, ":utf8"; #-標準入力から入ってくる文字コード # 検索用のテーブルを生成 # Fizz=F Buzz = B FizzBuzz=C 数字=0 my $DB; my $result; my $Max = 100; for (1..$Max) { $result = ''; $result .= 'F' if ($_ % 3 == 0); $result .= 'B' if ($_ % 5 == 0); $result =~ s/FB/C/; $result = '0' if (0 == length($result)); $DB .= $result; } sub GetFizzBuzz { #マッチパターンの生成 my $key = ''; my @FBC = @_; for (@FBC) { $_ =~ s/Fizz/F/i; $_ =~ s/Buzz/B/i; $_ =~ s/FB/C/; } $key = join("0*",@FBC); # 範囲を特定する my $myStart = 0; my $myEnd = 0; my %Ans; if ($DB =~ /$key/g) { $Ans{'length'} = length($&); $Ans{'position'} = pos($DB); while ($DB =~ /$key/g) { if ($Ans{'length'} > length($&)) { $Ans{'length'} = length($&); $Ans{'position'} = pos($DB); } } $myEnd = $Ans{'position'}; $myStart = $myEnd - $Ans{'length'} + 1; return join(" ",@_ , ':' , ($myStart .. $myEnd)); } else { return 'Error'; } } print GetFizzBuzz("fizz") . "\n"; print GetFizzBuzz("buzz") . "\n"; print GetFizzBuzz("fizz","fizz","buzz") . "\n"; print GetFizzBuzz("fizz","buzz") . "\n"; print GetFizzBuzz("buzz","fizz") . "\n"; print GetFizzBuzz("fizz","buzz","fizz") . "\n"; print GetFizzBuzz("fizz","fizz") . "\n"; exit;
結果:
fizz : 3 buzz : 5 fizz fizz buzz : 6 7 8 9 10 fizz buzz : 9 10 buzz fizz : 5 6 fizz buzz fizz : 3 4 5 6 fizz fizz : 6 7 8 9