okuzawatsの日記

モバイルアプリケーション開発の沼💀

Fizz Buzz

書いている人

モバイルアプリケーションアーキテクト


Fizz Buzzとは、以下のようなゲームです。

プレイヤーは円状に座る。最初のプレイヤーは「1」と数字を発言する。次のプレイヤーは直前のプレイヤーの発言した数字に1を足した数字を発言していく。ただし、3の倍数の場合は「Fizz」(Bizz Buzzの場合は「Bizz」)、5の倍数の場合は「Buzz」、3の倍数かつ5の倍数の場合(すなわち15の倍数の場合)は「Fizz Buzz」(Bizz Buzzの場合は「Bizz Buzz」)を数の代わりに発言しなければならない。発言を間違えた者や、ためらった者は脱落となる。(Wikipediaより引用)

このゲームから派生してプログラミングのテーマとなっていることもWikipediaのとおり。新しいプログラミング言語を学ぶ時、基本的な文法、ユニットテスト、CIサーバーでの実行などを手を動かして学ぶためにちょうど良いので、自分はプログラミング言語を学ぶ時にしばしばFizz Buzzを書いてます。

Swift

例えばSwiftの場合は以下のようなコードを書きました。この時はfor文で書いてます。実務ではこのようなコードを書くことはないでしょうが、Fizz Buzzとしては心地の良いコードです。

for i in 1...100 {
  var s = ""
  if i % 3 < 1 { s += "Fizz" }
  if i % 5 < 1 { s += "Buzz" }
  print(s != "" ? s : "\(i)")
}

以下のように実行できます。

% swift -v 
Apple Swift version 5.7.2 (swiftlang-5.7.2.135.5 clang-1400.0.29.51)
% swift fizzbuzz.swift

※ このコードは2023年2月に書かれた

Lua

次はLuaです。この時はFizz Buzzの判定処理を function に切り出してます。Swiftの時と同様の発想で書いてますが、Luaに独特の文法が楽しいです。

--- FizzBuzzを実行し、文字列を返す。
-- @param n 対象となる整数
-- @return nが3の倍数の場合はFizz、5の倍数の場合はBuzz、3と5の倍数の場合はFizzBuzz、それ以外の場合はnを文字列に変換したものを返す。
function fizzbuzz(n)
  s = ""
  if n % 3 < 1 then s = s.."Fizz" end
  if n % 5 < 1 then s = s.."Buzz" end
  return s ~= "" and s or tostring(n)
end

この function を main.lua に書いたループから呼び出します。この頃は、ドキュメントコメントを頑張って書くことにしていたらしいです。

require "src/fizzbuzz"

--- 1から100までの整数に対してFizzBuzzを実行し、その結果を標準出力する。
for i = 1, 100 do
  print(fizzbuzz(i))
end

※ このコードは2024年1月に書かれた

Dart

Dartも同様の発想です。この発想で書くのが好きらしいです。

/// 整数nに対するFizzBuzzを返す。
///
/// nが3の倍数の場合は"Fizz"、
/// 5の倍数の場合は"Buzz"、
/// 3の倍数かつ5の倍数の場合は"FizzBuzz"、
/// それ以外の場合はnの文字列表現を返す。
/// @param n FizzBuzzの元となる整数値
/// @returns nのFizzBuzz
String fizzBuzz(int n) {
   var s = '';
  if (n % 3 == 0) s += 'Fizz';
  if (n % 5 == 0) s += 'Buzz';
  return s.isNotEmpty ? s : '$n';
}

DartはStream処理を書きにくいところがあり、どちらかというと素朴なfor文がDartらしい書き方になる気がします。ここでは頑張ってStreamを作り、fizzBuzz を呼び出してます。map と listen は素直ではないが、健気にStream処理をしてます。

import 'src/fizzbuzz.dart';

void main() {
  Stream.fromIterable(
    List.generate(100, (i) => ++i)
  )
  .map(fizzBuzz)
  .listen(print);
}

※ このコードは2025年6月に書かれた

TypeScript

Bunは、JavaScriptにトランスパイルを経ず、TypeScriptを直接実行できることを思い出し、TypeScriptに興味を持った時のことです。途中でClaude Codeを使ってFizz Buzzを1行で書くことに興味が移った記憶があり、変わった書き方をしてます。

for (let i = 1; i <= 100; i++) console.log(((i % 3) ? "" : "Fizz") + ((i % 5) ? "" : "Buzz") || i)

GitHub ActionsでもBunを使って直接TypeScriptを実行してます。

name: FizzBuzz
on:
  pull_request:

jobs:
  fizzbuzz:
    runs-on: ubuntu-24.04
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
      - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6
      - run: bun fizzbuzz.ts

※ このコードは2026年5月に書かれた

Elixir

Elixirへの誘いでも触れているように、Elixirに興味を持ってました(ます)。defguardp などの技巧を凝らしてパターンマッチで書いてます。

defmodule FizzBuzz do
  @moduledoc "run FizzBuzz."

  # fizz/1 true if n is divisible by 3
  defguardp fizz(n) when rem(n, 3) == 0
  # buzz/1 true if n is divisible by 5
  defguardp buzz(n) when rem(n, 5) == 0

  @doc "returns FizzBuzz, Fizz, Buzz or the number in string."
  def run(n) when fizz(n) and buzz(n), do: "FizzBuzz"
  def run(n) when fizz(n), do: "Fizz"
  def run(n) when buzz(n), do: "Buzz"
  def run(n), do: "#{n}"
end

ユニットテストも書いてます。

Code.require_file("fizzbuzz.exs", __DIR__)

ExUnit.start()

defmodule FizzBuzzTest do
   use ExUnit.Case

   test "returns FizzBuzz when multiples of 15" do
     assert FizzBuzz.run(15) == "FizzBuzz"
     assert FizzBuzz.run(30) == "FizzBuzz"
   end

   test "returns Fizz when multiples of 3" do
    assert FizzBuzz.run(3) == "Fizz"
    assert FizzBuzz.run(6) == "Fizz"
  end

  test "returns Buzz when multiples of 5" do
    assert FizzBuzz.run(5) == "Buzz"
    assert FizzBuzz.run(10) == "Buzz"
  end

  test "returns the number in string when not multiples of 3 nor 5" do
    assert FizzBuzz.run(1) == "1"
    assert FizzBuzz.run(2) == "2"
  end
end

Elixirのパイプ演算子はやはり面白くて、繰り返し処理はここまで書いたどの言語よりもbeautifulです。

Code.require_file("fizzbuzz.exs", __DIR__)

1..100 |> Enum.each(fn n -> n |> FizzBuzz.run() |> IO.puts() end)

なお、mise使ってバージョン管理できます。以下は mise.toml の例。

[tools]
elixir = "1.20.0"

※ このコードは2026年6月に書かれた

こうしてふりかえると、毎年少なくとも1つはプログラミング言語を学んでおり、「達人プログラマー」の「1年に1つの言語」を愚直に守っているようです。まだまだ学ぶべきプログラミング言語は存在するので、学習を継続したいと思います。

毎年、少なくとも1つの言語を学習する。言語が異なれば、同じ問題に対して異なる解決方法が採用される。いくつかの異なったアプローチを学習することで思考に幅が生まれる。(Thomas & Hunt, 2020)

Reference

Related