Developer's Blog

SVG で FizzBuzz

Fenrir Advent Calendar 2015

こんにちは。Picky-Pics 担当の本岡です。

「2015 年にグッときたコレ」というテーマのもとに進んでおります Fenrir Advent Calendar 2015 ですが、6日目となる本日、私からは FizzBuzz を紹介したいと思います。

FizzBuzz と言えば基本的なプログラミングの問題として有名で、基本的には1から順に整数を出力していくのですが、3の倍数は「Fizz」に、5の倍数は「Buzz」に、15 の倍数は「FizzBuzz」に、それぞれ置き換えて出力する、というものです。詳しくは Wikipedia の記事 をご覧ください。

数年前に大流行したということもあって非常に多くのプログラミング言語で実装例がありますが、未開の地も存在します。そう、その一つが SVG なのです。では、プログラミング言語ではなく画像である SVG で、どのように FizzBuzz の処理をさせるのでしょうか?

SVG とは?

SVG とは Scalable Vector Graphics の略で、XML を書くことでベクター形式の画像を表現するものです。規格は W3C にて定められて公開されています。いくつかのバージョンがありますが、現在では 1.1 Second Edition に基いた画像が多く使われているのではないかと思います。近い将来には SVG 2 が主流になってくるかもしれません。フェンリルが運営しているオンラインデザインツール Picky-Pics も内部で SVG を利用しています。

まずは完成品のご紹介

20151206_1
これは Sleipnir 6 for Windows で描画した結果を PNG 画像に変換したものです。数字が一桁のときの十の位の値を消すことができていないだとか、0始まりになっているだとか、字詰めが適当であるだとか、いくつか問題を抱えてはいるものの FizzBuzz として機能していることが伺えます。

基本方針

上記の画像は、以下の方針で構築されています。

  • 連番を描画する
  • 連番のレイヤの手前のレイヤで、{3|5|15} の倍数のところだけ後ろのレイヤの描画結果を隠蔽しつつ {Fizz|Buzz|FizzBuzz} に置き換える

こうやって分解して考えると、JavaScript のお世話にならなくても簡単にできそうな気がしてきましたね! それではそれぞれのレイヤの描画方法をご紹介しましょう。

連番を描画する

ここでは pattern 要素を使って各桁を1文字ずつ丁寧に描いていく手法を選択しました。pattern 要素の詳しい使い方は W3C の文書 をご覧ください。他には素直に全部描く方法、上位の桁が下位の桁を内包する形で pattern 要素を使う方法、などが考えられます。

連番を描画する その1:一の位

<defs>
	<pattern id="onesPlacePattern" patternUnits="userSpaceOnUse" x="0" y="0" width="20" height="200" viewBox="0 0 20 200">
		<text x="0" y="20" text-anchor="start">
			<tspan x="0" dy="0">0</tspan>
			<tspan x="0" dy="20">1</tspan>
			<tspan x="0" dy="20">2</tspan>
			<tspan x="0" dy="20">3</tspan>
			<tspan x="0" dy="20">4</tspan>
			<tspan x="0" dy="20">5</tspan>
			<tspan x="0" dy="20">6</tspan>
			<tspan x="0" dy="20">7</tspan>
			<tspan x="0" dy="20">8</tspan>
			<tspan x="0" dy="20">9</tspan>
		</text>
	</pattern>
</defs>
<rect fill="url(#onesPlacePattern)" x="40" y="0" width="20" height="2000" />

このようなパターンを描いて、最後の行の rect 要素のように fill 属性としてパターンを指定すれば、縦に連なる一桁の数字を描くことができます。

連番を描画する その2:十の位

それでは、十の位はどうしましょうか?

周期は 100 ですので、単純に考えれば 100 個の text あるいは tspan 要素を使って1周期を描く方法が思い浮かびますが、それでは長過ぎるソースになってしまいます。今回は十の位の各数字が 10 回ずつ登場することを利用して、pattern の中に pattern を入れ子させる方法を使用しました。ソースも紹介したいところですが、 100 行には到達しないものの少し長いので、この記事の末尾に掲載してあるソース全文の中から該当しそうな箇所をご覧ください。

連番を描画する その3:百の位

百の位は、十の位と同じ方針で描画することができます。しかしながら、一部のブラウザでは pattern の周期が大き過ぎると描画されなくなったり、粗い描画になったりすることがあります。試される場合はご注意ください。

3 の倍数、5 の倍数、15 の倍数の処理

数字が描画できたので、次は Fizz | Buzz | FizzBuzz の描画です。

既にお気付きのように、Fizz, Buzz, FizzBuzz は 15 回周期で登場します。これまで連番を描画する中で利用してきた pattern 要素が活躍する格好の事例であることは想像に難くありません。それではソースを見てみましょう。

<defs>
	<pattern id="fizzbuzzPattern" patternUnits="userSpaceOnUse" x="0" y="0" width="100" height="300" viewBox="0 0 100 300">
		<g text-anchor="start">
			<rect x="0" y="40" width="100" height="20" fill="#e0ffe0"/>
			<text x="0" y="60">Fizz</text>
			<rect x="0" y="80" width="100" height="20" fill="#e0ffe0"/>
			<text x="0" y="100">Buzz</text>
			<rect x="0" y="100" width="100" height="20" fill="#e0ffe0"/>
			<text x="0" y="120">Fizz</text>
			<rect x="0" y="160" width="100" height="20" fill="#e0ffe0"/>
			<text x="0" y="180">Fizz</text>
			<rect x="0" y="180" width="100" height="20" fill="#e0ffe0"/>
			<text x="0" y="200">Buzz</text>
			<rect x="0" y="220" width="100" height="20" fill="#e0ffe0"/>
			<text x="0" y="240">Fizz</text>
			<rect x="0" y="280" width="100" height="20" fill="#e0ffe0"/>
			<text x="0" y="300">FizzBuzz</text>
		</g>
	</pattern>
</defs>
<rect fill="url(#fizzbuzzPattern)" x="0" y="0" width="100" height="2000" transform="translate(20,20)"/>

簡潔な表現ですね!

SVG のソース 全文

全体で 91 行の SVG になります。ブログ記事としては長過ぎるので隠しています。展開して閲覧するには ここをクリック or タップ してください。

この SVG 画像を表示させるには、内容をコピーしてファイルに保存(拡張子は .svg)し、SVG を表示できるアプリケーション(例えばウェブブラウザ)で開いてください。

何がグッときたのか?

そういえば、「2015 年にグッときたコレ」というテーマで Advent Calendar が進行しているのですが、ここまでの内容の中には 2015 年固有の話題が一つも見当たらないことにお気付きの読者の方もおられるかと思います。技術的にはその通りです。

話は変わって、フェンリルの社内ではチャットツールが稼動しておりまして、そこでは技術的な情報交換も行われます。当然ながら一般的なプログラミングの問題について話されることもありまして、その中でスタッフの一人から「SVG で FizzBuzz やってほしい」ということを依頼されました。これが今年の夏頃の話です。時間は開いてしまいましたが、その無茶振りを受けて本記事を執筆しました。

という訳で、かなり長い前置きになってしまいましたが、私個人にとって「2015 年にグッときたコレ」は、楽しい無茶振りをしてくれるフェンリルの技術スタッフ です。皆さんも SVG を書くために 無茶振りをするために 素晴らしい製品を作るために フェンリルに join しませんか?? 募集要項はこちら

フェンリルのオフィシャル Twitter アカウントでは、フェンリルプロダクトの最新情報などをつぶやいています。よろしければフォローしてください!

追記@2015年12月16日

SVG Advent Calendar 2015 の 16 日目の記事として、 SVGでFizzBuzz(XSLT版) – 週刊SVG が投稿されました。XSLT と SVG の組み合わせも良いですね。皆さんも SVG で FizzBuzz を実現するために色んな手法をお試し下さい!

Copyright © 2019 Fenrir Inc. All rights reserved.