プログラミング教材を作ろう！Playground Book概論

この記事は、[フラー株式会社のカレンダー | Advent Calendar 2023 - Qiita](https://qiita.com/advent-calendar/2023/fuller-inc) の 22 日目の記事です。

21 日目は [@devKyousuke](https://zenn.dev/ansuke) さんで [TShockを用いてAWSでTerrariaのサーバーをたてよう](https://zenn.dev/ansuke/articles/8056022806016f) でした。

# はじめに
> 学習指導要領の改訂に伴い、プログラミング教育は2020年度から小学校で必修化され、翌年には中学校でも必修化されました。
そして、AppleからSwift Playground Bookを使った中学校向けの教材もリリースされています。

> プログラミング教育にフォーカスが当たり始めた今、我々も若きエンジニアを育てるために何かできることはないでしょうか？
> Swift Playground Bookなら、若い世代にプログラミングの楽しさを知ってもらうための教材作りがSwiftでできるのです。

> 本セッションではXcodeでPlayground Bookを作る方法からデバッグ方法、リリースの方法までを実際にコードを見ながら説明していきます。
> アプリ開発とは全く異なるXcodeプロジェクトの構造から始まり、特殊な文章表現・単語説明機能などPlayground Bookならではの内容について解説します。

…と、これが私がiOSDC Japan2023に投稿し、見事不通過となったプロポーザルです。

本日はこの投稿で語ろうとしていた、Swift Playground Bookの作り方（の一部）についてお話しようと思います。

なお、Playgournd Bookの作り方については[Appleの公式ドキュメント](https://developer.apple.com/documentation/swift-playgrounds/playground-books)があるので、ぜひそちらもご覧ください。

# Swift Playground Bookとは

### Playgroundsの種類
Swift Playgroundsには2種類の形式が存在します。
1つめがアプリ開発中に使う方も多いであろう（？）、Playgroundファイルです。
Swiftコードをインタラクティブに実行でき、主に簡単なコードの動作確認などに使われるものです。
![スクリーンショット 2023-12-20 21.36.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13042/094f1aab-340c-a50d-58cf-d719c53431d8.png)

そして2つめが今回ご紹介する、Playground Bookファイル（以下PBファイル）です。
主に教材として使われることを想定した、教科書のような構造のファイルです。
独自の説明文表示やヒントの表示など、Playgroundファイルには無い、より教育的な側面をもった様々な機能を有しています。

# どうやって作るの？
さて、そもそもどうやってPBファイルを作り始めれば良いのでしょうか？

答えは簡単、[Appleのダウンロードページ](https://developer.apple.com/download/all/?q=swift%20playgrounds)からXcodeテンプレートファイルをダウンロードし、それを編集していくのです。
Xcodeから新規プロジェクト作成、みたいなことはできないんですね。
ちなみに2023/12/21現在、最新のテンプレートはXcode14.1用となっています。が、このテンプレートはXcode15.1でも使用できるのでご安心ください。

![スクリーンショット 2023-12-20 22.16.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13042/a36fb9d0-f114-d57f-cc51-f5e9d3d0f019.png)

ダウンロードして展開すると、以下のようなディレクトリ構成になっています。
![スクリーンショット 2023-12-21 21.21.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13042/f56d2ee9-b3ca-6671-5846-7e364b909c8b.png)

この中の`PlaygroundBook.xcodeproj`を開き、Xcode上で編集していきましょう。
以下、このプロジェクトを便宜上「PBプロジェクト」と呼びます。

# PBプロジェクトの構造（概要編）
さて、ここからはPBプロジェクトがどのような構造になっているか、大枠をご紹介します。

ダウンロードしてきたテンプレートファイルを開くと、下図のようなプロジェクト構造になっています。
まずは`Manifest`ファイルです。こちらがPBプロジェクトの要であり、ブックの名前や章立てなどの情報をここに記述します。
![スクリーンショット 2023-12-20 21.37.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13042/cf8c84d3-2a96-bc4d-cce2-751118a4ef93.png)

次に`Modules`と`UserModules`ディレクトリです。
- Modules
    - ブック全体で使用するファイル郡を配備します。この中に配備したコードはビルドして実際に使用する際にユーザには見えません。裏で少し凝ったことをしたいけど、教材自体はできるだけシンプルに留めて学習範囲を絞りたい、といったときに使えそうですね。
- UserModules
    - ここも`Modules`と同じくブック全体で使用するファイル郡を配備します。`Modules`との違いとしては、こちらに配備したコードはユーザに見えるようになることです（見え方については後述します）。応用的な内容として、このコードをいじってみよう！みたいな形で使えそうですね。
![スクリーンショット 2023-12-20 21.37.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13042/69ad6214-b824-69ba-acb7-9d32375462d0.png)

次は`Chapter`と`Page`です。
- Chapter
    - 教科書や書籍の「章」にあたる部分です。1つ以上の`Page`や`Cutscene`（後述）から成ります。
- Page
    - 章の構成要素となる、PBファイルの最小構成要素です。
![スクリーンショット 2023-12-20 21.38.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13042/d747055b-b538-f183-37a7-9474609eee08.png)

# PBファイルの構造（詳細編）
### BookのManifestファイル
まずは全体の構成を司る、Book全体の`Manifest`ファイルを見てみましょう。
中身は以下のようになっています。
![スクリーンショット 2023-12-21 21.46.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13042/d41bddb5-d2a3-4cd4-ed82-71ef9c69d37b.png)

`Chapters`キーの配列に`.playgroundchapter`の名前をそれぞれ入力する必要があります。

$(PLAYGROUND_BOOK_DISPLAY_NAME)などの変数は、`Config Files`ディレクトリ内の`BuildSettings`ファイルで設定できます。

### Chapter
次に`Chapter`の構造を見ていきましょう。
1つの`Chapter`は`playgroundchapter`ディレクトリから成り、その中には`Manifest`ファイル、`Pages`ディレクトリが存在します（`Pages`の構成は後述）。
- Manifestファイル
    - チャプター名と、そのチャプターが持つpageの一覧を保持しています。
- Pagesディレクトリ
    - 後述のPageディレクトリの一覧を保持しています。

![スクリーンショット 2023-12-20 21.39.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13042/588e46cc-fb05-de3e-d71c-8b32b5aaa94a.png)

Manifestファイルは、例えば`Page`が3つ存在する`Chapter`の場合、以下のような構造になります。
![スクリーンショット 2023-12-21 21.06.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13042/12a593a7-5acb-a706-8651-49e8fe3b434a.png)

### Page
次に`Page`です。
1つの`Page`は`playgroundpage`ディレクトリで構成され、その中には`LiveView.swift`と`main.swift`の2つのSwiftファイルが存在します。やっとSwiftファイルが出てきましたね！
`LiveView.swif`と`main.swift`はそれぞれ、教材1ページの右側と左側のビューを表現しています。
![スクリーンショット 2023-12-20 21.39.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13042/d5ca2428-70c1-1038-5641-88958acc7c2e.png)

こちらはプロジェクトをビルドして、PBファイルとして開いたときのビューを見ながらの方が理解しやすいのでその画像をお見せします。

![スクリーンショット 2023-12-20 21.41.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13042/44a3b645-34ff-80b8-52df-52d736ceb3e5.png)

上記のように、`main.swift`に記載した内容は主に教材として、説明文と実際にユーザにコードを記述してもらう箇所になります。
`LiveView.swift`は、`main.swift`に記述したコードの実行する前の状態を表現する画面です。
デフォルトの`LiveView`は中央に`Live View`と書かれているだけのシンプルな画面ですが、ここを任意の`ViewController`に差し替えることにより、Appleが出しているPBファイル（上記画像）のように、プログラム実行前の画面を良い感じに変更することができます。

↓テンプレートのままビルドして実行するとこんな感じになります。味気ない…
![スクリーンショット 2023-12-20 22.59.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13042/328960de-6cb9-118b-3ab5-e5baac8000e6.png)

なお、LiveViewの領域は画面下部の「コードを実行」ボタンを押下するとその実行結果が表示されます。
例えば`main.swift`を以下のように記述してPBファイル上で実行すると…

```swift:main.swift
import MapKit
import PlaygroundSupport

let mapView = MKMapView()
mapView.preferredConfiguration = MKStandardMapConfiguration()

let location = CLLocationCoordinate2D(
    latitude: 35.8948967197249,
    longitude: 139.9518645086708
 )

let annotation = MKPointAnnotation()
annotation.coordinate = location

mapView.addAnnotation(annotation)

let span = MKCoordinateSpan(latitudeDelta: 0.45, longitudeDelta: 0.45)
let region = MKCoordinateRegion(center: location, span: span)
mapView.setRegion(region, animated: true)

PlaygroundPage.current.liveView = mapView
```

こんな感じで、画面右に地図が表示されます。
![スクリーンショット 2023-12-21 20.32.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13042/6d952001-9df1-aac3-f824-5d78d5a391c2.png)

### Modules, UserModules
`Modules`と`UserModules`の構成は非常にシンプルで、それぞれ内部に`Sources`ディレクトリを作成し、その中にソースファイルを配備するだけです。

以下のように作成した`Modules`と`UserModules`をPBファイルで開くと…
![スクリーンショット 2023-12-21 20.42.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13042/fd4357d7-3391-8d06-d3c4-9c8203ae4bdd.png)

下図のように表示されます。
`Modules`の中身はユーザに見えていないことがわかりますね。
![スクリーンショット 2023-12-21 20.41.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13042/3549816c-310b-dcca-9885-5335dacfeae8.png)

# どうやってデバッグするの？
PBファイルのプロジェクトは`.xcodeproj`形式になっているので、そのファイルを開いてXcode上で編集を行います。
デバッグを行う場合、Xcode上で`Run`を実行するとPBファイルが開く…というわけではありません。
ビルドディレクトリを開き、`Build` > `Products` > `Debug-iphonesimulator`（ここは実行時に選択したシミュレータによって異なります）内に、`{Book名}.playgroundbook`というファイルが生成されています。
これをダブルクリックすることで、PCにインストールしたSwift Playgroundアプリ上でPBファイルが開けます。

iPadで実機確認したいときはどうすればいいかって？
先程の`.playgroundbook`をAirDropでiPadに送るだけです！とっても簡単ですね！（もうちょっとやり方なかったの？）
ちなみにAirDropの不具合なのか、ファイル名を日本語にするとAirDropで送信できません。
デバッグ時はファイル名をアルファベット表記にしておきましょう。

# 教材っぽくしたい！
### Prose（散文）
通常のコメントではなく以下の形式でコメントを記述すると、編集可能な文章を教材に入れることが可能です。
そのページで何を学ぶのか等の説明文に使用すると、より教材っぽくなります。
```swift
/*: ~ :/
```
例えば、以下のように散文を入れると…
![スクリーンショット 2023-12-21 21.11.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13042/eeaf17c5-efd5-167b-3cdc-b042220e48f4.png)

PBファイル上ではこのように表示されます。教材っぽくなりましたね！
![スクリーンショット 2023-12-21 21.11.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13042/d23369d4-728f-4f25-0fb5-b5ea9b1f7a3e.png)

### 入力範囲の限定
以下のような書き方をすると、`Page`の中でその箇所のみが編集可能エリアになります。
想定外の部分をいじって上手く動かなくなってしまった、などの事象を防ぎ、学習してほしい箇所に集中させるのに使えそうです。
```swift
/*#-editable-code Hoge*//*#-end-editable-code*/
```

例えば以下のように、`latitide`部分にこの書き方をすると…
![スクリーンショット 2023-12-21 21.18.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13042/bbea7259-5429-c9b4-d3ff-3f59a84d8817.png)

PBファイル上で`latitude`の値のみが編集できるようになりました。
「この部分を変更するとどうなるか、試してみましょう！」みたいな使い方ができそうですね。
![スクリーンショット 2023-12-21 21.15.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13042/c76c7810-dc7e-38e1-a38c-a1991cde8545.png)

他にも独自の用語集なども作成できるので、ぜひ[公式ドキュメント](https://developer.apple.com/documentation/swift-playgrounds/adding-a-glossary-to-a-playground-book)を見てみてください。

# おわりに
本記事ではSwift Playground Bookの内容や作り方、できることなどを簡単にご説明しました。
おそらく開発人口が非常に少ない領域な気がしていますが、本記事で少しでも「意外と作れるのでは？」と思ってもらえたら幸いです！

フラーアドベントカレンダー、23日目は[@9rotama](https://qiita.com/9rotama)さんです。お楽しみに！