Ankiで英作文の組み立て(整序問題)を実装する

# はじめに
暗記のための自由/オープンソースソフトウェアである「[Anki](https://apps.ankiweb.net/)」を知りました。これを使用すれば、エビングハウスの忘却曲線に基づいて暗記することが出来るようになります。
OpenAIの音声認識Whisperで問題文の文字起こしがきっかけで、Ankiをいろいろ調べるようになりました。

https://qiita.com/yaju/items/ac31775616cbfb682f4e

Ankiをいろいろ調べていくうちに、JavaScriptを使用して機能を拡張出来ることを知ります、例えば、下記サイトではJavaScriptを使用して選択肢をランダム表示させることが出来ます。

https://zenn.dev/shivase/articles/002-anki-random-question

Pythonを使用したAdd-onでも出来るようですが、こちらはまだ試していません。

https://ankiweb.net/shared/info/1280092568

[Cocone](https://www.cocone.co.jp/)が販売しているiPhoneの英語文法アプリ「[英語組み立てTOWN](https://apps.apple.com/jp/app/%E8%8B%B1%E8%AA%9E%E7%B5%84%E3%81%BF%E7%AB%8B%E3%81%A6town/id446358732)」があるのですが、英作文がパズル感覚で楽しめます。しかし、問題文を一通りやってしまうと覚えてしまうので問題文を自作出来ればいいなと常々思っていました。
この英文法の並び替えというのは、「整序問題」に近いのかな。

【2023/01/11追記】
自分がのんびりしている間に、GUI版を作った方がいるので紹介します。
いずれ自分でもGUI版を作る予定ですが、それまではこれを Mac や Kindle Fire に入れて動かしています。
文字が小さいと見難いので、CSSのフォントだけ12ptから24ptに変更してますね。

https://rubyu.hatenablog.com/entry/2023/01/03/144635

# Ankiについて
英語学習者や医学生の方に人気です。

https://rs.luminousspice.com/how-to-anki/

* [YouTubeのAnkiハッシュタグ](https://www.youtube.com/hashtag/anki)
* [QiitaのAnkiタグ](https://qiita.com/tags/anki)
* [Ankiを始める/紹介する時に必要な情報を集めたページ](https://ei-raku.com/2018/06/learning-anki/) 
* [Ch.01 Ankiが捗る3つのコツ](https://note.com/satoken990/n/nd072256f6fda)
* [スケジューリングアルゴリズムについて](https://fumito.info/ankiのスケジューリングアルゴリズムについて/)

# Ankiのカードについて
## 環境
今回は、Mac版で確認しています。

## ノートとカードの基礎
Ankiでは、暗記カードのデータを「ノート」と呼ばれる形式で保持していて、それを実際の暗記カードにしたものを「カード」と呼んでいます。
このカードは、HTMLとCSSとJavaScriptを使ってそこそこ自由にカスタマイズすることができます。

各ノートはkey-value型のデータ形式で、このkeyのことを「フィールド」と呼んでいます。
通常は、「表面」と「裏面」の2つのフィールドからなっています。

## ノートタイプの追加
メニューのツールにある「ノートタイプを管理」をクリックします。
追加ボタンでノートの「整序問題」を作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14053/abb25f25-2a70-5cad-3e02-10f1afffaf4d.png)

次に「追加:基本」を選択してOKボタンをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14053/f7b77c05-9be7-ca72-2831-18a93c98633c.png)
今回は名前を「整序問題」にしてOKボタンをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14053/38b3673a-e54d-db01-9b99-cd11ae6196a6.png)

## カードの編集
「整序問題」を選択して「カード」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14053/e80b9a10-e2f4-6a8e-9bad-7b2b2b152ae8.png)

# 整序問題の実装
カードは、HTMLとCSSとJavaScriptを使用して自由にカスタマイズできるので、整序問題用にこの中身を実装していきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14053/0083c696-6619-1db4-f91b-9fa34ed53452.png)

## 整序問題の仕様
表面では、日本語とその下に英文が表示されます。
英文は単語ごとランダムにスラッシュ区切りで表示します。
※クエスチョンマークとビックリマークとカンマも区切られます。
※ピリオドは除外しています。

自分の場合、手入力で回答するようにしています。

## 表面のテンプレート
`b`タグに囲まれた裏面フィールドの英文をスペース区切りにして単語または記号単位にランダムに表示します。

1.クエスチョンマークとビックリマークとカンマも区切られるように1文字前にスペースを追加して置換
2.複数空白があっても1つの空白になるように置換
3.スペースで区切る
4.配列内の空文字のみ除外
5.末尾ピリオドを除外
6.配列内をランダムにシャフル
７.スラッシュ区切りで文字列結合してセット

`{{type:裏面}}`として、裏面フィールドの英文を手入力するようにしています。

```html
<script>
(() => {
  const shuffle = ([...array]) => {
    for (let i = array.length - 1; i >= 0; i--) {
      const j = Math.floor(Math.random() * (i + 1));
      [array[i], array[j]] = [array[j], array[i]];
    }
    return array;
  }

  let elm = $('.question b');
  let content = elm.text();
  content = content.replace(/([\?\!,])/g," $1");
  content = content.replace(/\s+/g," ");
  let result = content.split(" ");
  result = result.filter(item => item !== "");
  for (let item in result) {
    result[item] = result[item].replace(/\.$/, "");
  }
  let arr = shuffle(result);
  elm.text(arr.join(' / '));
})()
</script>

<div class="question">
{{表面}}<br>
<b>{{裏面}}</b>
</div>

{{type:裏面}}
```

## 裏面のテンプレート
`{{FrontSide}}`で問題文を表示します。
※気にならないと思いますが、ランダム値が記憶出来ないため、英単語の順番が問題時の一致しません。

`{{tts en_US:裏面}}`として、英文の音声が回答と同時に出るようにしています。
ttsとは、Text to Speechの略で合成音声でテキストを読み上げる機能が最近のOS標準でついています。
これを使用すれば音声ファイルが無くても、英文の音声が聞けます。
速度や声の種類などもオプションにあります。詳細は下記のマニュアルを参照してください。
https://docs.ankiweb.net/templates/fields.html?highlight=tts#text-to-speech

```html
{{FrontSide}}

<hr id=answer>
{{tts en_US:裏面}}
```

【2023/01/11追記】
何故か自分のMac環境では、`en_US`を使うと声が枯れたようになってしまいました。
`en_US`から`en_GB`に変更しています。`en_GB`とは、`British English`です。

Chromeのサポートには連絡しましたが、自分の環境だけかも知れませんけど。

## 書式
デフォルトのままです。

```css
.card {
    font-family: arial;
    font-size: 20px;
    text-align: center;
    color: black;
    background-color: white;
}
```

## デッキの作成
瞬間英作文のデッキを作成しました。
デッキ名の中に"::"を入れれば、"::"の左に付けられた名前でデッキをグループ化できます。
瞬間英作文::整序
瞬間英作文::通常

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14053/cf4137c3-320e-1a9a-19f4-69f5115392fe.png)

[暗記ソフトAnkiで、デッキを階層化させる方法](https://akamist.com/blog/archives/1674)

## ノートタイプ
ノートタイプを「整序問題」にして作成して下さい。
表面に「日本語」、裏面に「英文」を入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14053/d28c4187-f3f1-ca7f-9f97-859c34cf4bbb.png)

## 問題文のインポート
自分は有名な瞬間英作文の中学2年生分の問題文をExcelで入力しました。もともと瞬間英作文の本を持っているので各ページをiPhoneで写真を撮って「[一太郎Pad](https://www.justsystems.com/jp/products/ichitaropad/)」でテキスト化していたので、Excelで編集し直した感じです。
Anki データをインポートするには2列(A列に日本語、B列に英語)のデータにする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14053/14323ecb-fbc2-3ae2-ecc9-89528b76e3d1.png)
英文にカンマが含まれているのでタブ区切りのテキストで保存しました。
このままだと文字コードが「Shift-JIS」で保存されていて、Ankiにインポートが出来ないのでサクラエディタで文字コードを「UTF-8(BOMなし)」で保存し直しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14053/eae5f2c8-1c43-47b9-606c-65a7d6d4368a.png)

デッキの「整序」を選択している状態で、「ファイルを読み込む」をクリックします。
ファイルダイアログ画面が表示されるので、先程作成したタブ区切りのテキストファイルを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14053/cf4137c3-320e-1a9a-19f4-69f5115392fe.png)

## オプション設定
オプションの設定がいろいろありますので、幾つか設定を変更します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14053/c969500e-c44a-f898-1c65-f6f43b630473.png)
導入する順序は「追加順」と「ランダム」の2パターンがあります。今回は「ランダム」にしています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14053/1b654522-a5a8-346e-8e13-08be72c6a92f.png)
タイマーやオーディオなども好みで設定してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14053/931ccda5-5449-b0aa-c96b-5ceb3de20f3a.png)

# 整序問題の開始
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14053/cec2e974-108b-14ab-d345-2e7bec11737c.png)

## 正解の場合 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14053/4e98af1e-4e0c-e314-1398-3db8c0b1a1e0.png)

## 不正解の場合 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14053/27368b23-da1b-b8e2-0c83-7b72be66580b.png)

# 最後に
今回は回答を手入力形式にしたのですが、出来れば「英語組み立てTOWN」のように文字をクリック(タップ)するなりして、入力出来るようにすればPCではなくモバイルにしたとしても使いやすくなると思うんですよね。
もう少し研究すれば、JavaScriptとCSSの組み合わせで何とかなる気がします。

# 参照 
* [[Anki] カードを表示するhtml全体のソース](https://akamist.com/blog/archives/5262)
* [Ankiで早押しクイズ](https://qiita.com/WaTTson496/items/66f6052be1a16905805a)
* [Ankiにカウントダウンタイマー(プログレスバーあり)を付ける方法](https://ameblo.jp/macgyverisms/entry-12685344351.html)
* [Anki で JavaScript を使う](https://laboradian.com/using-javascript-in-anki/)
* [ankiで選択肢をランダム表示にする](https://zenn.dev/shivase/articles/002-anki-random-question)