パソコン甲子園の基礎問題をJasmine Teaで解いてみた

この記事は、 [Jasmine Tea アドベントカレンダー 2023](https://qiita.com/advent-calendar/2023/jasminetea) の第20日目です。

## パソコン甲子園

私は毎年会津大学で行われるパソコン甲子園（正式名称: 全国高等学校パソコンコンクール）の審査員を務めています。このパソコン甲子園は、プログラミング部門、モバイル部門、CG部門の3部門で構成されております。このうちのプログラミング部門はいわゆる競技プログラミングとなります。

私は、毎年、この競技プログラミングの本戦を見ていますが、高校生向けと侮ることのできない高度な問題も出題されており、全国予選を勝ち抜いた精鋭ジュニアプログラマーたちが競う姿は、圧巻です。

[パソコン甲子園　プログラミング部門](https://pckoshien.u-aizu.ac.jp/programming/)

## Jasmine Teaで解いてみる

[Jasmine Tea (ジャスミンティー)](https://jasminetea.app/) は、プログラミングの楽しさを多くの人に知ってもらうために作られたプログラミング言語です。初心者が学びやすい仕組みで、実際に社会で使われている多くのプログラミング言語に応用できる基礎が身に付きます。

今回はこのJasmine Teaで[パソコン甲子園のプログラミング部門の過去問](https://pckoshien.u-aizu.ac.jp/programming/)を解いてみましょう。

## パソコン甲子園2023 問題1 穴あきワッフル

本年の問題は13問あり、最初の2問が基礎的な問題です。その中の第1問目をまず今回は見てみましょう。問題および解説はパソコン甲子園のサイトでPDFで公開されていますので、そこから引用します。

### 問題
穴あきワッフルは、生地が格子状になっている。生地の線が縦に𝑁本、横に𝑁本あるワッフルを、レベル𝑁の穴あきワッフルと呼ぶ。線の太さは１ｃｍであり、同方向の線は1ｃｍ間隔で並んでいる。また、生地の線とその交点以外の部分は穴であり、ワッフル全体の四隅は穴である。たとえば、レベル３の穴あきワッフルは、生地を黒色、穴を白色で表すと、次のように描ける。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33915/8fe7736c-d634-994e-e4ca-0c375a52808a.png)

#### 課題
与えられたレベルの穴あきワッフルを描くプログラムを作成せよ。 

#### 入力
入力は以下の形式で与えられる。 

```
N
```
１行に穴あきワッフルのレベル𝑁(1≤𝑁≤100)が与えられる。

#### 出力
1ｃｍ×1ｃｍの領域を1文字とし、生地には「#」、穴には「.」を使い、レベル𝑁の穴あきワッフルを出力する。 

#### 入出力例
<table>
  <thead>
    <tr>
      <th>入力例1</th> <th>出力例1</th>
    </tr>
  </thead>
  <tr>
    <td>3</td> <td><code>
    .#.#.#.<br/> #######<br/>.#.#.#.<br/>#######<br/>.#.#.#.<br/>####### <br/>.#.#.#. </code>
    </td>
  </tr>
    <tr>
      <th>入力例2</th> <th>出力例2</th>
    </tr>
  </thead>
  <tr>
    <td>1</td> <td><code>.#.<br/>###<br/>.#.</code>
    </td>
  </tr>
</table>

#### 解答例
パソコン甲子園の解説ではC++での解答例が示されています。

```cpp
int N;
cin >> N;
int M = (2*N)+1;
for (int i = 1; i<= M; i++) {
  for (int j = 1; j <= M; j++) { 
    if ((i%2 == 1) && (j%2 == 1)) {
      cout << '.';
    } else {
      cout << '#';
    } 
  }
  cout << endl; 
}
```

ここでは解答例としてのソースコードを引用するだけにしますが、パソコン甲子園の解説では考え方（アルゴリズムの導き方）も書かれていますので、興味ある方は是非そちらもご覧ください。

### Jasmine Teaで書いてみる
Jasmine Teaでこの問題を解くと次のようになります。

```vb
input N
M = (2*N)+1
for i = 1 to M
  for j = 1 to M
    if i%2 = 1 and j%2 = 1 then
      print ".";
    else
      print "#";
    end if
  next
  print
next
```

アルゴリズムを素直にプログラミングしたものとなっています。自画自賛になりますが、C++よりもわかりやすいのではないかと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33915/2ae26435-f272-7981-de9d-b59ef515e20a.png)


### グラフィカルな出力にしてみる
これで解答としては終わりなのですが、これだけではつまらないので、問題への解答からは脱線しますが、ワッフルをJasmine Teaのグラフィック機能で出力してみましょう。

Jasmine Teaのグラフィック機能には、四角の描画機能があるので、これを用いて、正方形のマスでワッフルを描くようにしてみましょう。プログラムは次のようになります。

```vb
input N
M = (2*N)+1
side = round(400/(M+2),0)
h_box_start = round((640/side-M)/2,0)*side
v_box_start = round((400/side-M)/2,0)*side
for i = 1 to M
  for j = 1 to M
    if i%2 = 1 and j%2 = 1 then
      box (h_box_start+side*(j-1),v_box_start)-(h_box_start+side*j,v_box_start+side),0,0
    else
      box (h_box_start+side*(j-1),v_box_start)-(h_box_start+side*j,v_box_start+side),7,7
    end if
  next
  v_box_start = v_box_start+side
next
```

Jasmine Teaの実行結果画面の座標は640×400となっていますので、これを元にワッフルを描画するために最大の正方形のマスの1辺を計算し、ワッフルを画面の真ん中に配置するようにしています。実際に使っているのは、```box``` 命令です。```box```命令では、始点と終点、四角の枠線と塗りつぶしの色を指定しています。ここでは、枠線と塗りつぶしともに白にしています。先のワッフルを文字で描画していたのを忠実に再現するために、「.（ピリオド）」は黒を枠線と塗りつぶしにした四角で描画していますが、背景色が黒なので、これは無くても構いません。

この実行結果は次のようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33915/6fe01742-ac28-66f8-94ce-4444ce55e6f1.png)

これだけでも良いのですが、Jasmine Teaには背景に任意のドット絵を配置できますので、それを使ってみましょう。

エディター画面の[背景]ボタンを押し、テンプレートから背景を選びます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33915/096b6b88-58ba-5ddc-e5c0-5adb7a098961.png)

次に、プログラムの中で```background```命令を使い、その背景を指定します。今回はワッフルの空白部分を黒の正方形で埋める必要はありませんので、不要な行はコメントとします。また、せっかくなのでワッフルっぽい色にしました。結果、次のようなプログラムになりました。

```vb
background 0
input N
M = (2*N)+1
side = round(400/(M+2),0)
h_box_start = round((640/side-M)/2,0)*side
v_box_start = round((400/side-M)/2,0)*side
for i = 1 to M
  for j = 1 to M
    if i%2 = 1 and j%2 = 1 then
      //box (h_box_start+side*(j-1),v_box_start)-(h_box_start+side*j,v_box_start+side),0,0
    else
      box (h_box_start+side*(j-1),v_box_start)-(h_box_start+side*j,v_box_start+side),35,35
    end if
  next
  v_box_start = v_box_start+side
next
```

大草原の中でワッフルを食べているような感覚に陥りますね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33915/b2774dd6-7e0f-684e-937d-4eafea99513b.png)

競技プログラミングではまったく不要なことをしていますが、プログラミングの学習にはこのように少しでも自分なりの工夫をしてみるのも良いのではないでしょうか。

## 最後に
今回はパソコン甲子園の問題の中でも基礎中の基礎を取り上げました。実は、今年の第2問や昨年の同じく基礎問題も解いてみたのですが、あまりにも地味だったので、ここで取り上げることは控えました。

パソコン甲子園の問題の多くは、もっと難易度の高いもので、職業プログラマーであっても悩んでしまうようなものが多くあります。機会があったら、それらもJasmine Teaで解答例を作ってみたいと思います。

もし、皆さんが高校生であったら、この記事をきっかけに競技プログラミングやパソコン甲子園などに興味を持ってもらえたら嬉しいなと思います。高校生の保護者の方ならば、是非お子さんにパソコン甲子園を勧めてみて頂ければと思います。熱い戦いは甲子園球場だけでなく、会津大学の校内でも行なえます！