CodeEval fizzbuzz

CodeEval

設問

Fizz Buzz

Description:

Players generally sit in a circle. The player designated to go first says the number "1", and each player thenceforth counts one number in turn. However, any number divisible by 'A' e.g. three is replaced by the word fizz and any divisible by 'B' e.g. five by the word buzz. Numbers divisible by both become fizz buzz. A player who hesitates or makes a mistake is either eliminated.

Write a program that prints out the the pattern generated by such a scenario given the values of 'A'/'B' and 'N' which are read from an input text file. The input text file contains three space delimited numbers i.e. A, B, N. The program should then print out the final series of numbers using 'F' for fizz, 'B' for 'buzz' and 'FB' for fizz buzz.

Input sample:

Your program should read an input file (provided on the command line) which contains multiple newline separated lines. Each line will contain 3 numbers which are space delimited. The first number is first number to divide by ('A' in this example), the second number is the second number to divide by ('B' in this example) and the third number is where you should count till ('N' in this example). You may assume that the input file is formatted correctly and is the numbers are valid positive integers.e.g.

3 5 10
2 7 15
Output sample:

Print out the series 1 through N replacing numbers divisible by 'A' by F, numbers divisible by 'B' by B and numbers divisible by both as 'FB'. Since the input file contains multiple sets of values, your output will print out one line per set. Ensure that there are no trailing empty spaces on each line you print.e.g.

1 2 F 4 B F 7 8 F B
1 F 3 F 5 F B F 9 F 11 F 13 FB 15

要は

inputは下記のようなファイルで
1つ目が"F"を表示する倍数の最小値(通常のfizzbuzzだと3)
2つ目が"B"を表示する倍数の最小値(通常尾fizzbuzzだと5)
3つ目が実行する最大値。

3 5 10
2 7 15


これでfizzbuzzすると、outputはこうなるよ。

1 2 F 4 B F 7 8 F B
1 F 3 F 5 F B F 9 F 11 F 13 FB 15

気分転換にやってみた

#!/usr/bin/env ruby
def fizz_buzz(fizz, buzz, last)
  (1..last).inject([]) do |result, num|
    tmp = ''
    tmp << 'F' if num % fizz == 0
    tmp << 'B' if num % buzz == 0
    tmp << num.to_s if tmp.empty?
    result << tmp
  end.join(' ')
end

File.open(ARGV[0]).each_line do |line|
  fizz, buzz, last = line.split(' ').map(&:to_i)
  puts (fizz_buzz(fizz, buzz, last))
end

2012/01/28 追記

RubyでFizz Buzzを解く -CodeEval - hp12c
keyesberryさんのと見比べてちょっと修正。

少し整理
#!/usr/bin/env ruby

def fizzbuzz(a, b, n)
  rtn = ''
  rtn << 'F' if (n%a).zero?
  rtn << 'B' if (n%b).zero?
  rtn.empty? ? n : rtn
end

ARGF.lines do |line|
  a, b, max = line.split(' ').map(&:to_i)
  puts (1..max).map { |n| fizzbuzz(a,b,n) }.join(" ")
end


fizzbuzz関数がいろいろし過ぎていたのでsimpleに。

ARGF.lines

これ知りませんでした。
多分どっかで読んだことあるんだけど
抜けてたんだな。


わざわざファイル開くのをopen(ARGV[0])としていました。
linesはeach_lineのaliasだったんですね。

おまけ(curry化)

curry化全然知らなかった。
余談だけどHaskellすげー。
ここでは、curry化するメリットは部分適用で下記のように理解。

「複数の引数を取る関数」を「一引数を取る関数のチェインに直す」こと。

fizzbuzzメソッドの最初の2つの引数は、行単位で固定なので
curry化の部分適用を使うことでsimpleに書けます。

fizzbuzz = ->(a, b, n) {
  rtn = ''
  rtn << 'F' if (n%a).zero?
  rtn << 'B' if (n%b).zero?
  rtn.empty? ? n : rtn
}.curry

ARGF.lines do |line|
  a, b, max = line.split(' ').map(&:to_i)
  fb = fizzbuzz[a,b]
  puts (1..max).map { |n| fb[n] }.join(" ")
  #puts (1..max).map { |n| fb.call(n) }.join(" ")
end