【java】アルファベット1種禁止縛りでFizzBuzz【縛り】という面白い記事を見つけたので、これをパクってRubyでもやってみた。
ルール
元記事をだいたい継承する。
- Ruby2.5 (CRuby)
- 標準出力にFizzBuzzを出力する
- 数字1つにつき1行
- 文字は「Fizz」「Buzz」「FizzBuzz」
- ループや条件分岐するところを埋め込みで解決しない
- 余計な標準出力、エラー出力は禁止(改行はOK)
- アルファベットを1種類だけ使用禁止
- 大文字小文字は区別なし
- 外部ファイル禁止(Ruby標準ライブラリのみ可能)
ちなみに、使用していない文字は以下のコマンドで確かめた。
tr -cd 'a-zA-Z' < fizzbuzz.rb | ruby -ne 'p [*"a".."z"] - $_.downcase.split(//)'
結論
Javaと違って全文字縛れます
詳細
acghjkmqvwxy
元記事にならい、ウィキペディアのFizzBuzzのPythonコードをそのままRubyで実装した。
for 数 in 1..20
if 数 % 15 == 0
puts "FizzBuzz"
elsif 数 % 3 == 0
puts "Fizz"
elsif 数 % 5 == 0
puts "Buzz"
else
puts 数
end
end
bfioprtuz
元記事はSystem.out.format
を使っていたので、こちらはString#%
を使ってbuzを削った。
forはeachに(もちろんdo~endではなく{})、ifはcaseに、putsは$> <<
に変えてfioprtの6文字を削った。
ちなみに$>
は$stdout
のエイリアスで、IO#<<
はIO#write
とほぼ同じことをするメソッドである。
(1..20).each { |数|
case 0
when 数 % 15
$> << "%c%c%c%c%c%c%c%c%c" % [70, 105, 122, 122, 66, 117, 122, 122, 10]
when 数 % 3
$> << "%c%c%c%c%c" % [70, 105, 122, 122, 10]
when 数 % 5
$> << "%c%c%c%c%c" % [66, 117, 122, 122, 10]
else
$> << 数 << "%c" % 10
end
}
delns
case ~ when ~ else ~ endを消すため、配列に入れたProcをcallすることで、あまりの判定を配列のインデックスですることにした。elseとendが消えたので、これでdlnsがなくなった。
あとはeachをuptoに変えればeも消える。
1.upto(20) { |i|
p15 = -> {
$> << "%c%c%c%c%c%c%c%c%c" % [70, 105, 122, 122, 66, 117, 122, 122, 10]
}
p3 = -> {
$> << "%c%c%c%c%c" % [70, 105, 122, 122, 10]
}
p5 = -> {
$> << "%c%c%c%c%c" % [66, 117, 122, 122, 10]
}
a = [p15]
a[3] = p3
a[6] = p3
a[9] = p3
a[12] = p3
a[5] = p5
a[10] = p5
(a[i % 15] || -> { $> << i << "%c" % 10 })[]
}
変数名を除けば、アルファベットは文字列のcとuptoの5文字しか使っていない。もはや記号プログラミングに近くなってきた。
まとめ
意外とあっさり全文字出来てしまった。
今回は使わなかったが、"%c" % 数字
でどんな文字列でもつくれるとなれば、evalを使えばcとevalの5文字で何でも出来る。
スクリプト言語で同じことをやる場合はevalも禁止したほうが面白いかもしれない
おまけ
せっかくなので、アルファベット以外でも縛ってみることにした。
ただ数字は1文字縛ったところで足し算引き算でいくらでも作れるので、記号に関してやってみる。
1つ目のfor版のコードに含まれる.%="
を無くしていく。
%="
"は'に置き換えればいいだけ。==はcaseにして回避する。
%はNumeric#modulo
でもいいが、今回はInteger#chr
で得た文字列をsendするやり方にした。
for 数 in 1..20
case 0
when 数.send(37.chr, 15)
puts 'FizzBuzz'
when 数.send(37.chr, 3)
puts 'Fizz'
when 数.send(37.chr, 5)
puts 'Buzz'
else
puts 数
end
end
.
1つ目のコードで.
が登場するのは1..20
のみ。Range.new
にしたいところだが、.
が入るのでRange::new(1, 20)
とする。