challenge 変形Fizz-Buzz問題

どもraynstardです。
どちらにしようか迷いましたが発想の元ネタがUIさんの投稿からなので
こちらに投稿してみます。
--------------
以下の仕様を満たす文字列を
20行出力するプログラムを作成してください。

1. 1行の出力は「<行番号> ':' <メッセージ>」であること。
2. 行番号が 3の倍数であるとき、メッセージは「Fizz」であること
3. 行番号が 5の倍数であるとき、メッセージは「Buzz」であること
4. 行番号が 3の倍数かつ5の倍数であるとき、メッセージは「FizzBuzz」であること
5. 上記に記した条件以外のメッセージについては「hoge」であること
6. 条件分岐する場合、if文のみが使用でき、
   かつ、論理式が成立した場合の処理のみが記述できます。
#アセンブリなどifがなければif以外でもかまわないです。(意味が同じならば)

というわけでこの問題はFizz-Buzz問題をelseなしならどう書く?という問題です。

出力例:
 1:hoge
 2:hoge
 3:Fizz
 4:hoge
 5:Buzz
 6:Fizz
 7:hoge
 8:hoge
 9:Fizz
10:Buzz
11:hoge
12:Fizz
13:hoge
14:hoge
15:FizzBuzz
16:hoge
17:hoge
18:Fizz
19:hoge
20:Buzz

Posted feedbacks - Flatten

Nested Hidden
elseを使わないってのはこういうことなんでしょうか?
elseと同等のコードがcontinueで書けてしまってますが。

三項演算子を使おうかと思ったけど、三項演算子もelesだよなぁと思った。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
def FizzBuzz(num):
    for x in xrange(1,num+1):
        if x % 15 == 0:
            print "%2d:FizzBuzz" % x
            continue
        if x % 5 == 0:
            print "%2d:Buzz" % x
            continue
        if x % 3 == 0:
            print "%2d:Fizz" % x
            continue
        print "%2d:hoge" % x
        
FizzBuzz(20)

FizzBuzzを表示する行数が可変では無いので、
この答えでもお題を満たすような気がしてきた。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
print ''' 1:hoge
 2:hoge
 3:Fizz
 4:hoge
 5:Buzz
 6:Fizz
 7:hoge
 8:hoge
 9:Fizz
10:Buzz
11:hoge
12:Fizz
13:hoge
14:hoge
15:FizzBuzz
16:hoge
17:hoge
18:Fizz
19:hoge
20:Buzz'''

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
    #i = 1;
    #a[0] =  1; $b[0] = "hoge";
    #a[1] =  3; $b[1] = "Fizz";
    #a[2] =  5; $b[2] = "Buzz";
    #a[3] = 15; $b[3] = "FizzBuzz";
    while( #i <= 20 ) {
        call KetaSoroe #i, 2;
        insert $$return + ":";
        #j = 3;
        while( #j >= 0 ) {
            if( #i % #a[#j] == 0 ) {
                insert $b[#j];
                break;
            }
            #j = #j - 1;
        }
        insert "\n";
        #i = #i + 1;
    }
    endmacro;

KetaSoroe:
    ##i = ##2 - strlen( str( ##1 ) );
    $$result = "";
    if ( ##i >= 0 ) {
        while( ##i > 0 ) {
            $$result = $$result + " ";
            ##i = ##i - 1;
        }
    }
    $$result = $$result + str( ##1 );
    return $$result;

こんなんでいいのかな…。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
Module Module1

    Sub Main()
        For i As Integer = 1 To 20
            If i <= 9 Then
                Console.Write(" ")
            End If
            Console.Write(i & ":")
            If i Mod 3 = 0 Then
                Console.Write("Fizz")
            End If
            If i Mod 5 = 0 Then
                Console.Write("Buzz")
            End If
            If i Mod 3 <> 0 AndAlso i Mod 5 <> 0 Then
                Console.Write("hoge")
            End If
            Console.Write(vbCrLf)
        Next
    End Sub

End Module

以前WiLiKi (http://practical-scheme.net/wiliki/wiliki.cgi?Scheme%3aFizzBuzz)に書いたものの焼き直しですが、hygienic macroで解いてみました。 ただ、素直に解いた方が短いです。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
(define-syntax show-msg
  (syntax-rules ()
    ((_ current v next)
     (define-syntax current
       (syntax-rules ()
         ((_) #t)
         ((_ elem . rest)
          (begin
            (print #`",|elem|:,v")
            (next . rest))))))))

(define-syntax define-fizzbuzz
  (syntax-rules (Fizz Buzz FizzBuzz)
    ((_ v) #t)
    ((_ current Fizz next rest ...)
     (begin
       (show-msg current "Fizz" next)
       (define-fizzbuzz next rest ...)))
    ((_ current Buzz next rest ...)
     (begin
       (show-msg current "Buzz" next)
       (define-fizzbuzz next rest ...)))
    ((_ current FizzBuzz next rest ...)
     (begin
       (show-msg current "FizzBuzz" next)
       (define-fizzbuzz next rest ...)))
    ((_ current next rest ...)
     (begin
       (show-msg current "hoge" next)
       (define-fizzbuzz next rest ...)))))

(define-fizzbuzz a1 a2 a3 Fizz a4 a5 Buzz a6 Fizz a7 a8 a9 Fizz a10 Buzz a11 a12 Fizz a13 a14 a15 FizzBuzz a1)

(a1 1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20)

どうでしょうか?
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
        static void Main(string[] args)
        {
            string str = string.Empty;

            for (int i = 1; i <= 20; ++i)
            {
                Console.Write("{0,2}:", i );

                str = "hoge";

                if (i % 15 == 0)
                {
                    str = "FizzBuzz";
                }
                if (i % 5 == 0 && str == "hoge")
                {
                    str = "Buzz";
                }
                if (i % 3 == 0 && str == "hoge")
                {
                    str = "Fizz";
                }

                Console.WriteLine(str);
            }
        }

出力が分かれてたので修正。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
static void Main(string[] args)
{
    string str = string.Empty;

    for (int i = 1; i <= 20; ++i)
    {
        str = "hoge";

        if (i % 15 == 0)
        {
            str = "FizzBuzz";
        }
        if (i % 5 == 0 && str == "hoge")
        {
            str = "Buzz";
        }
        if (i % 3 == 0 && str == "hoge")
        {
            str = "Fizz";
        }

        Console.WriteLine("{0,2}:{1}", i, str);
    }
}

format で分岐とか……
1
2
3
(loop for x from 1 to 20
  do (format t "~2D:~[Fizz~[Buzz~]~:;~[Buzz~:;hoge~]~]~%"
             x (mod x 3) (mod x 5)))

#3800 がなんとなくインチキっぽい気がしたので別の方針で。
Fermat の小定理を使ってます。
1
2
3
4
5
(loop for x from 1 to 20
  do (format t "~2D:~A~%" x
             (aref #("FizzBuzz" "Buzz" "Fizz" "hoge")
                   (+ (mod (expt x 2) 3)
                      (* 2 (mod (expt x 4) 5))))))

微妙に奇妙。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import std.stdio;

void main(){
    for(int i = 1; i <= 20; i++){
        writef("%2d:", i);
        (i % 3) == 0 && (writef("Fizz"), i % 5) ||
        (i % 5) == 0 && (writef("Buzz"), true) ||
        writef("hoge");
        writefln();
    }
}

elseや!などの否定は使いませんでした、というかifすら使ってないんですがいいんでしょうか?

 いまいちお題が飲み込めない。。。orz
1
map{print("$_:".'Hoge'x($_%3&&$_%5>0).'Fizz'x($_%3==0).'Buzz'x($_%5==0)."\n")}1..20;

オーソドックスに
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
#include <stdio.h>

int main()
{
    int i;

    for (i = 1; i <= 20; i++) {
        printf("%2d:", i);
        if (i%3 == 0)
            printf("Fizz");
        if (i%5 == 0)
            printf("Buzz");
        if (i%3 != 0 && i%5 != 0)
            printf("hoge");
        puts("");
    }

    return 0;
}

上のやつを、ifなしに変形してみる。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
#include <stdio.h>

int main()
{    
    int i;
    for(i = 1; i <= 20; i++){
        printf("%2d:", i);
        (i%3) || printf("Fizz");
        (i%5) || printf("Buzz");
        (i%3) && (i%5) && printf("hoge");
        printf("\n");
    }

    return 0;
}


	
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
def fizzbuzz(n)
  (1..20).each do |i|
    printf("%2d:", i)
    print "Fizz" if i % 3 == 0
    print "Buzz" if i % 5 == 0
    print "hoge" if (i % 3) * (i % 5) != 0
    puts
  end
end

fizzbuzz(20)

お題の意図がいまいち掴めてません。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
let fizzbuzz n =
  let rec fb n i =
    Printf.printf "%2d:%s\n" i
      (match i with
           _ when i mod 15 == 0 -> "FizzBuzz"
         | _ when i mod 3 == 0 -> "Fizz"
         | _ when i mod 5 == 0 -> "Buzz"
         | _ -> "hoge");
    if i < n then fb n (i+1)
  in fb n 1

let _ = fizzbuzz 20

無限リストを使って、明示的条件判断無しでやってみました。

showItのところは

 zipWith4 (printf "%2d: %s%s%s") [1..] fizz buzz hoge

だと型が推測できんと怒られた。そういうもの?
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
import Data.List
import Text.Printf

fizzbuzz = zipWith4 showIt [1..] fizz buzz hoge
  where showIt :: Int->[Char]->[Char]->[Char]->[Char]
        showIt = printf "%2d: %s%s%s"
        fizz = ["","","Fizz"]++fizz
        buzz = ["","","","","Buzz"]++buzz
        hoge = ["hoge","hoge","","hoge","","","hoge","hoge",
                "","","hoge","","hoge","hoge",""]++hoge

main = putStr $ unlines $ take 20 $ fizzbuzz

> 6. 条件分岐する場合、if文のみが使用でき、
>    かつ、論理式が成立した場合の処理のみが記述できます。
ということなので、match withでの分岐はお題を満たさないのでは?


	
1
2
3
4
5
6
7
8
val p = print _
(1 to 20).foreach{i=>
  p(i);p(":")
  if(i%3 == 0) p("Fizz")
  if(i%5 == 0) p("Buzz")
  if(i%3!=0 && i%5!=0) p("hoge")
  p("\n")
}

こんな感じでOKでしょうか。 C#2.0 の ?? 演算子使いましたけど、これは else には該当……するのかなしないのかな。
1
2
3
4
5
6
7
8
9
using System;
static class FizzBuzz {
    public static void Main(String[] args) {
        string[] msg = new string[15];
        for(int i = 2; i <= msg.Length; i += 3) msg[i] += "Fizz";
        for(int i = 4; i <= msg.Length; i += 5) msg[i] += "Buzz";
        for(int i = 0; i < 20; i++) Console.WriteLine("{0,2}:{1}", i + 1, msg[i%msg.Length] ?? "hoge");
    }
}

if文を使わない方法。

あらかじめ3つとばし、5つとばし、15個飛ばしで必要な文字列を書き込んでおきます。後から書いた15飛ばしので上書きされるのでelseが消えるという話。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
def fizzbuzz(n):
    r = range(n + 1)
    map = {}
    for i in r[::3]:
        map[i] = "Fizz"
    for i in r[::5]:
        map[i] = "Buzz"
    for i in r[::15]:
        map[i] = "FizzBuzz"
    for i in r[1:]:
        print "%d:%s" %(i, map.get(i, "hoge"))

        
fizzbuzz(20)

素直に書いてみました。
Rならifすら必要ありませんね。
1
2
3
4
5
6
7
FizzBuzz <- function(n=20){
    v <- rep("hoge", n)
    v[!1:n%%3]  = "Fizz"
    v[!1:n%%5]  = "Buzz"
    v[!1:n%%15] = "FizzBuzz"
    cat(paste(1:n, v, sep=":"), sep="\n")
}

あ、"%2d"にしないと前に空白がつきませんね。

すいません <= じゃなくて < ですね orz

Scheme(Gauche)で。題意に満すのかどうかわかりませんが……。

1
2
3
4
5
6
7
8
(use srfi-1)

(map (lambda (n)
       (format #t "~a:~a\n" n (or (and (= (modulo n 15) 0) "FizzBuzz")
                                  (and (= (modulo n 3)  0) "Fizz")
                                  (and (= (modulo n 5)  0) "Buzz")
                                  "hoge")))
     (iota 20 1))

あ、mapになってた……。for-eachで。

循環リストで。
1
2
3
4
5
6
7
use srfi-1)
(define (fizzbuzz n)
  (for-each (lambda (a b) (print a ":" b))
            (iota n 1)
            (circular-list 'hoge 'hoge 'Fizz 'hoge 'Buzz 'Fizz 'hoge 'hoge 'Fizz 'Buzz 'hoge 'Fizz 'hoge 'hoge 'FizzBuzz)))

(fizzbuzz 20)

Squeak Smalltalk で。
1
2
3
4
5
6
7
8
9
| fizzs buzzs |
fizzs := #('' '' Fizz).
buzzs := #('' '' '' '' Buzz).
World findATranscript: nil.
1 to: 20 do: [:idx |
    | message |
    message := (fizzs atWrap: idx), (buzzs atWrap: idx).
    message ifEmpty: [message := #hoge].
    Transcript cr; show: idx; show: #:, message]

ifもelseもmod演算子も無しで書いてみました。
1
2
3
4
5
6
7
8
let mes = [| "hoge"; "Fizz"; "Buzz"; "FizzBuzz" |]

let f acc i =
  let c = acc land 3 in
  let _ = Printf.printf "%02d:%s\n" i mes.(c) in
  (acc lsr 2) lor (c lsl 28)

let _ = Array.fold_left f 810092048 (Array.init 20 (fun i->i+1))

条件分岐の定義が微妙に曖昧かなぁと。
他の投稿でも if 使ってないけど条件分岐ととれる記述(&& とか)出ていたので、
じゃあ match はあり?なし?という感じで出してみました。

ああ、[1..]の型が曖昧なのがprintfの型情報からだけでは解決できないってことなのかな。
こうしたら通った。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import Data.List
import Text.Printf

fizzbuzz = zipWith4 (printf "%2d: %s%s%s") ([1..]::[Int]) fizz buzz hoge
  where fizz = ["","","Fizz"]++fizz
        buzz = ["","","","","Buzz"]++buzz
        hoge = ["hoge","hoge","","hoge","","","hoge","hoge",
                "","","hoge","","hoge","hoge",""]++hoge

main = putStr $ unlines $ take 20 $ fizzbuzz

言語組込みの条件分岐を使わず、ラムダ算法による真偽値表現を使ってみました。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
(use srfi-1)
(use srfi-42)

(define (fizzbuzz n)
  (define (t x y) x)
  (define (f x y) y)
  (do-ec (:parallel (: i n)
                    (:list mod3 (circular-list f f t))
                    (:list mod5 (circular-list f f f f t)))
         (format #t "~2d: ~a\n" (+ i 1)
                 (mod3 (mod5 "FizzBuzz" "Fizz") (mod5 "Buzz" "hoge")))))

トリッキー萌え。

思いついたままに作ってみました。
意図されている仕様に即していますでしょうか。。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package nt.doukaku;

public class FizzBuzz {
    public static void main(String[] args) {
        for (int i = 1; i <= 20; i++) {
            System.out.print(i);
            System.out.print(":");
            if (i % 15 == 0) {
                System.out.println("FizzBuzz");
                continue;
            }
            if (i % 3 == 0) {
                System.out.println("Fizz");
                continue;
            }
            if (i % 5 == 0) {
                System.out.println("Buzz");
                continue;
            }
            System.out.println("hoge");
        }
    }
}

DRYではありませんが。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
def fizzbuzz(n=20):
  d = len( str(n))
  
  for i in range(1,n+1):
    F,B = i%3==0,i%5==0
    
    if F==B:
      if not F:  print "%*d:hoge"%(d,i)
      if F:     print "%*d:FizzBuzz"%(d,i)
    if F<>B:
      if F:     print "%*d:Fizz"%(d,i)
      if not F:  print "%*d:Buzz"%(d,i)

なでしこで素直に10行で。ワンライナーでもできるかもしれません。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
CNAKOモード="EXE"
Iで1から20まで繰り返す
  文字列右寄せ(I,2)&":"を継続表示
  もし(I%3=0&&I%5=0)なら
    "FizzBuzz"を表示。続ける
  もし(I%3=0)なら
    "Fizz"を表示。続ける
  もし(I%5=0)なら
    "Buzz"を表示。続ける
  "hoge"を表示

後になって考えると match with での分岐もありかな?と思いました。
題意としては else 無しでという方向みたいですし。

ifは全部試行するので条件6もみたしているはず。
1
2
3
4
5
6
7
8
9
BEGIN{
        for (x=1;x<=20;x++) str[x]=x ":hoge";
        for (x=1;x<=20;x++) {
         if (x%3==0) str[x]=x ":Fizz";
         if (x%5==0) str[x]=x ":Buzz";
         if (x%15==0) str[x]=x ":FizzBuzz";
        }
  for (x=1;x<=20;x++) { print str[x] }
}