ファミコン
ファミコン……ああ懐かしい響きですね。そうです。任天堂のファミリーコンピュータです。実は先日、こんなブログ記事を発見してしまいました。
「ドット絵マリオクッキー - メロウマイマインド」
もう何かピコーンと閃いて、以下のような「実行プラン」が、天から降ってきました。
「ドット絵マリオクッキー - メロウマイマインド」 + 「ファミコンカラーパレット」 + 「XML」 + 「XSLT」 = (^^)
それでは、実際にやってみます。
データの持ち方
ドット絵のデータの持ち方ですが、とりあえずパレット4色を「0~3」に割り当てて、属性として持たせました。
■Mario.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
<?xml version="1.0" encoding="utf-8" ?> <root> <row value="00000000000000"></row> <row value="00001111100000"></row> <row value="00011111111100"></row> <row value="00022233230000"></row> <row value="00232333233300"></row> <row value="00232233323330"></row> <row value="00223333222200"></row> <row value="00003333333000"></row> <row value="00022122200000"></row> <row value="00222122122200"></row> <row value="02222122122220"></row> <row value="03321311312330"></row> <row value="03331111113330"></row> <row value="03311111111330"></row> <row value="00011100111000"></row> <row value="00011100111000"></row> <row value="00222000022200"></row> <row value="02222000022220"></row> <row value="00000000000000"></row> </root> |
なんだかうっすらとですが、ドット絵の内容が確認できますね。
XSLTファイルはこんな感じです。
■Mario.xslt
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 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
<?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="html" indent="yes"/>
<xsl:attribute-set name="cellsize"> <xsl:attribute name="width">20</xsl:attribute> <xsl:attribute name="height">20</xsl:attribute> </xsl:attribute-set> <xsl:attribute-set name="cell0" use-attribute-sets="cellsize"> <xsl:attribute name="style">background-color:#000000;</xsl:attribute> </xsl:attribute-set> <xsl:attribute-set name="cell1" use-attribute-sets="cellsize"> <xsl:attribute name="style">background-color:#DB2B00;</xsl:attribute> </xsl:attribute-set> <xsl:attribute-set name="cell2" use-attribute-sets="cellsize"> <xsl:attribute name="style">background-color:#8B7300;</xsl:attribute> </xsl:attribute-set> <xsl:attribute-set name="cell3" use-attribute-sets="cellsize"> <xsl:attribute name="style">background-color:#FF9B3B;</xsl:attribute> </xsl:attribute-set>
<xsl:template match="/root"> <table border="0" cellpadding="0" cellspacing="1"> <xsl:apply-templates select="row"> </xsl:apply-templates> </table> </xsl:template>
<xsl:template match="row"> <tr> <xsl:call-template name="countup"> <xsl:with-param name="prmcount" select="1" /> <xsl:with-param name="len" select="string-length(@value)" /> </xsl:call-template> </tr> </xsl:template>
<xsl:template name="countup"> <xsl:param name="prmcount"/> <xsl:param name="len"/> <xsl:choose> <xsl:when test="substring(@value,$prmcount,1) = '0'"> <td xsl:use-attribute-sets="cell0"></td> </xsl:when> <xsl:when test="substring(@value,$prmcount,1) = '1'"> <td xsl:use-attribute-sets="cell1"></td> </xsl:when> <xsl:when test="substring(@value,$prmcount,1) = '2'"> <td xsl:use-attribute-sets="cell2"></td> </xsl:when> <xsl:when test="substring(@value,$prmcount,1) = '3'"> <td xsl:use-attribute-sets="cell3"></td> </xsl:when> </xsl:choose> <xsl:if test="$prmcount != $len"> <xsl:call-template name="countup"> <xsl:with-param name="prmcount" select="$prmcount + 1" /> <xsl:with-param name="len" select="$len" /> </xsl:call-template> </xsl:if> </xsl:template>
</xsl:stylesheet> |
長いです。68行あります。長くなった理由は、「XSLTの限界」を突破するために必要だったからです。ではこれから、「XSLTの限界」の説明と、その「解決法」を順番に見てきます。
XSLTの変数は上書きできない
1つ目の限界は「XSLTの変数は上書きできない」ということです。つまり、定数(constの変数)として存在するので、変数の内容を後から上書きできません。この動かせない事実が、様々なところで問題になります。
例えば今回の例でいうと、ループ処理で問題になりました。ドット絵のデータは1行14ドットで、全部で19行あります。単純に考えると、19回のループ中に14回ループを入れて処理する必要があります。19×14=266回の変換です。C#やJavaScriptで処理を書くならば、ループ変数「i」と「j」などを定義して、現在処理している位置をループによってずらしていくのがパターンでしょうか。しかし、XSLTでは変数の上書きができないのです。
for-eachは属性値のループに使用できない
2つ目の限界は「for-eachは属性値のループに使用できない」ということです。もっと詳しく言うと、「for-each」はノードの集合に対して使用するものであるため、「00001111100000」という属性値を1文字ずつ処理することができません。
属性値のループができないなら、属性値のデータを1ドットずつばらしておけばいいのでは? ……確かにそれで解決です。しかし、それでは全然面白くないので、少々「あがいてみる」ことにしました。「何とか抜け道はないものだろうか?」と。
再帰処理を使う
答えは、再帰処理でした。実行プランはこうです。
- 「ループの回数」と「現在の値」を引数に持つテンプレートを用意する
- テンプレート内で「現在の値」を1ずつ変化させて自分自身を呼ぶ
- 「ループの回数」になるまで自分自身を呼び続ける
XSLTのファイル上では、具体的には42~65行目の処理になります。
再帰処理は、「処理の終了条件」を特に注意しないと、無限ループになる可能性があります。今回は、それほど複雑な処理は行っていないので、まったく問題ありません。
トランスフォーム
いよいよ実行します。F5!
PlayStation3の豪華なグラフィックには到底及びませんが、カクカクのドット絵もまた、味があっていいですね。