PHPでInverse FizzBuzz(逆FizzBuzz)問題を問題を考えた

Fizz,Buzzとかのリストから最小で最短のFizzBuzzを出力できる連続数列を返すみたいなやつ。
強引に解いた感じでスマートじゃないけど関数型脳みそだから仕方ない。

中身

<?php
header('Content-Type: text/plain');
// Inverse FizzBuzz
inverseFizzBuzz(array('fizz')); // 3
inverseFizzBuzz(array('buzz')); // 5
inverseFizzBuzz(array('fizz', 'buzz')); // 9,10
inverseFizzBuzz(array('buzz', 'fizz')); // 5,6
inverseFizzBuzz(array('fizz', 'buzz', 'fizz')); // 3,4,5,6
inverseFizzBuzz(array('fizz', 'fizz')); // 6,7,8,9
inverseFizzBuzz(array('fizz', 'fizz', 'buzz')); // 6,7,8,9,10
inverseFizzBuzz(array('fizzbuzz', 'fizz')); // 15,16,17,18
// 解なし
inverseFizzBuzz(array('buzz', 'buzz'));
inverseFizzBuzz(array('buzz', 'fizz', 'buzz'));
inverseFizzBuzz(array('fizz', 'hoge'));
exit;
function inverseFizzBuzz($fb) {
    $values = array();
    for ($n = 1; $n < 101; $n++) {
        if ($fb[0] != n2fb($n)) continue;
        if ($arr = fb2array($fb, $n)) $values[] = $arr;
    }
    print implode(', ', $fb) . ' -> ' . implode(', ', fblen($values)) . "n";
}
function fblen($arr) {
    // 最短のを選ぶ
    if (!count($arr)) return $arr;
    $n = count($arr[0]);
    $ifb = $arr[0];
    foreach ($arr as $value) {
        if (count($value) < $n) {
            $ifb = $value;
            $n = count($value);
        }
    }
    return $ifb;
}
function fb2array($fb, $n) {
    // fizz,buzz,fizzbuzzから配列を得る
    $values = array($n);
    $length = count($fb);
    $fb = array_slice($fb, 1);
    for ($i = 1; $i < $length; $i++) {
        if (!count($fb)) break;
        // 15ぐらい先までで十分
        for ($j = $n + 1, $end = $n + 15; $j <= $end; $j++) {
            if ($j > 100) break;
            $values[] = $j;
            // fizz,buzzの順番が違ったらやめる
            if (n2fb($j) && $fb[0] != n2fb($j)) break;
            if ($fb[0] == n2fb($j)) {
                // fizz,buzz,fizzbuzzのどれかの場合は$fb[0]取り出してまた15先まで見る
                $fb = array_slice($fb, 1);
                $end += 15;
                if (!count($fb)) {
                    // 最小で終わらせる
                    break;
                }
            }
        }
    }
    if (count($fb) > 0) {
        return null;
    } else {
        return $values;
    }
}
function n2fb($n) {
    // 数値からfizzbuzzを得る
    return $n % 15 ? $n % 5 ? $n % 3 ? '' : 'fizz' : 'buzz' : 'fizzbuzz';
}
?>

実行結果

fizz -> 3
buzz -> 5
fizz, buzz -> 9, 10
buzz, fizz -> 5, 6
fizz, buzz, fizz -> 3, 4, 5, 6
fizz, fizz -> 6, 7, 8, 9
fizz, fizz, buzz -> 6, 7, 8, 9, 10
fizzbuzz, fizz -> 15, 16, 17, 18
buzz, buzz -> 
buzz, fizz, buzz -> 
fizz, hoge -> 

コメントを残す

メールアドレスが公開されることはありません。