NabeAzzテンプレート問題パート2・解答例1

昨日NabeAzzテンプレート問題パート2を出題しましたが、テンプレートの組み方はいろいろ考えられます。
mixiのコミュニティで何人かの方がテンプレートを作られていましたが、それぞれやり方が違って、面白かったです。

私も何通りか解答例を作ってみました。
今日はその中で、比較的読みやすそうなものを紹介します。

1.テンプレート

テンプレートのうち、HTMLのヘッダー等を除いて、問題の部分を出力するところだけを抜き出すと、以下のようになります。

<MTIgnore>xは出力する数値</MTIgnore>
<MTSetVar name="x" value="1">

<table>
<MTIgnore>二重ループ</MTIgnore>
<MTFor var="r" from="1" to="20">
  <tr>
  <MTFor var="c" from="1" to="10">

    <MTIgnore>市松模様の判断</MTIgnore>
    <MTSetVar name="f" value="0">
    <MTIf var="r" op="%" value="2" eq="0">
      <MTIf var="c" op="%" value="2" eq="1">
        <MTSetVar name="f" value="1">
      </MTIf>
    <MTElse>
      <MTIf var="c" op="%" value="2" eq="0">
        <MTSetVar name="f" value="1">
      </MTIf>
    </MTIf>
    <td<MTIf name="f" value="1"> class="reverse"</MTIf>>

      <MTIgnore>開始タグの出力</MTIgnore>
      <MTIf name="x" op="%" value="3" eq="0">
        <b>
      </MTIf>
      <MTIf name="x" like="3">
        <u>
      </MTIf>
      <MTIf name="x" op="%" value="5" eq="0">
        <i>
      </MTIf>
      <MTIf name="x" like="5">
        <s>
      </MTIf>

      <MTIgnore>数値の出力</MTIgnore>
      <MTGetVar name="x">

      <MTIgnore>終了タグの出力</MTIgnore>
      <MTIf name="x" like="5">
        </s>
      </MTIf>
      <MTIf name="x" op="%" value="5" eq="0">
        </i>
      </MTIf>
      <MTIf name="x" like="3">
        </u>
      </MTIf>
      <MTIf name="x" op="%" value="3" eq="0">
        </b>
      </MTIf>
    </td>

    <MTIgnore>xを1増やす</MTIgnore>
    <MTSetVar name="x" op="++">
  </MTFor>
  </tr>
</MTFor>
</table>

2.二重ループ

HTMLでは、表の各行をtr要素で表し、行内の個々のセルをtd要素で表します。
この問題では、1~200の数値を1行あたり10列の表で出力するので、以下のような二重の繰り返しを行うことになります。

  • 表全体で、行(<tr>~</tr>)を20回出力
  • 1つの行につき、セル(<td>~</td>)を10回出力

そこで、MTForタグの中にさらにMTForタグを入れて、二重ループの構造をとりました。
外側の<MTFor var="r" from="1" to="20">の繰り返しは、行を20回出力するための繰り返しです。
そして、内側の<MTFor var="c" from="1" to="10">の繰り返しは、各行にセルを10回ずつ出力するための繰り返しです。

また、出力する数値は、変数xで別途管理するようにし、セルを1個出力するごとにxを1つずつ増やすようにしました。
なお、「数値=(行番号ー1)×10+列番号)」で計算する方法も考えられますが、それだと処理が長くなりますので、この方法は取りませんでした。

3.市松模様の判断

表の個々のセルには、背景に色を付けて、市松模様にします。
表の行/列の番号と市松模様の関係は、以下のようになります。

 
1 2 3 4 5 6 7 8 9 10
1                    
2                    
3                    
4                    
... ...

この表を見ると、濃い色がついているセルは、行/列の番号が以下のどちらかの条件を満たしています。

  • 行番号が偶数で、かつ列番号が奇数
  • 行番号が奇数で、かつ列番号が偶数

また、奇数か偶数かの判断は、「2で割ったときの余りが1(0)かどうか」で行うことができます。
そこで、以下のような考え方で、濃い色を付けるセルとそうでないセルを分けます。

「色を付ける」ことを表すための変数を0に初期化
if (行番号を2で割った余りが0(=行番号が偶数)) 
}
else { /* 行番号が偶数でない場合にここにくるので、ここでは行番号は奇数 */
   if (列番号を2で割った余りが0(=列番号が偶数) {
     「色を付ける」の変数に1を代入
  }
}

この流れを実際にMTタグに表すと、テンプレートの「市松模様の判断」の部分のようになります。
テンプレートでは、「『色を付ける』ことを表すための変数」として、「f」という変数を使っています。
また、行/列の番号は、MTForタグでそれぞれ変数r/cに代入していますので、これらの変数を2で割った余りを条件判断しています。

4.数値をタグで囲んで出力

最後に、以下の条件で、数値をタグで囲みつつ出力します。

  • 3で割り切れる数(例:6)は、bタグで囲みます。
  • 3を含む数(例:13)は、uタグで囲みます。
  • 5で割り切れる数(例:10)は、iタグで囲みます。
  • 5を含む数(例:52)は、sタグで囲みます。

「○○で割り切れる」という条件は、「○○で割ったときの余りが0」と言い換えることができます。
そこで、数値を出力する前と後で、出力する数を3や5で割ったときの余りが0かどうかを判断します。
そして、余りが0であれば、数値の前に<b>や<u>のタグを出力し、後に</b>や</u>のタグを出力します。

また、「○○を含む」は、MTIfタグでは「like="○○"」で表現することができます。
これを使って、数値の前後にタグを出力します。

なお、開始タグと終了タグは正しく対になっている必要があります。
そのため、「3で割り切れる」等の条件を判断する順番は、開始タグと終了タグとで逆になります。

5.課題点

今回の例では、開始タグと終了タグを出力する際に、同じ条件を2回ずつ判断していて、効率が良くありません。
そこで、条件判断を1回にまとめる例を、明日紹介します。