Pythonで自作したイントロクイズを改善してみる

[以前PythonとVLCを用いて作ったイントロクイズ](https://qiita.com/KjumanEnobikto/items/0a87d45a3eb9c2d387a8)ですが、これを試しにDiscordで友人と通話をつないでやってみたら予想以上にウケが良かったです。
みんな楽しんでくれた一方で、実際にプレイしてみての不満を頂いたりもしたので、そのような点を改善してみました。
改善前のコードのGistは[こちら](https://gist.github.com/Qman11010101/cd328dd99e2b9c2e0ffd5005dd2efa4d)
改善後のコードのGistは[こちら](https://gist.github.com/Qman11010101/ec771a34bab5cb815ebd83c1bd203df9)

## 環境
以前のものと同じです。
Python: 3.8.2
python-vlc: 3.0.7110
VLC Media Player: 3.0.8 Vetinari

## 不満ポイント
実際に指摘されたり、プレイしてみて不便だなと思った点を挙げていきます。
あとで問題点と比較して改善点を述べるため、便宜上番号をつけています。

### 1. リプレイができない
クイズをやっていると「もう一回再生して」という要望が時々ありましたが、実装していなかったためできませんでした。

### 2. 大文字・小文字が厳密に区別される
例えば、「Nirv lucE」という楽曲があります。この曲が正解のとき、「nirv luce」や「NirvlucE」などは不正解と判定されてしまいます。改善前のプログラムでもパーフェクト(完全一致)と正解(部分一致)を分けてはいましたが、大文字小文字の違いで完全不正解扱いされてしまうのはいくらなんでもないなと思いました。

### 3. 正解表示後すぐに次の曲が始まってしまう
このプログラムはもともと一人で遊ぶために作っていたので問題はなかったのですが、皆で遊んでみると正解を出すかギブアップしてしまった後に正解を見て喜んだり悔しがったりするという時間がほしくなりました。

### 4. イントロの無音区間が長い曲がある
イントロで音楽が始まらないまま答えの入力画面に移ってしまうことが稀にありました。

### 5. 何度もやると皆覚えてしまう
決まった時間、決まった部分が流れるので、だんだん覚えてきてしまい、つまらなくなっていくという問題がありました。

### 6. 一部判定バグが存在していた
曲名のうち1文字だけ入力して正解にしてしまうことを防ごうと、最低でも3文字以上入力させるようにしていたのですが、(説明には対応していると書いているにもかかわらず)2文字以下の曲名を正しく入力しても「入力文字数が少なすぎる」という判定を食らうようになってしまっていました。

### 7. 少しだけ入力して正解になってしまう例があった
問題6とは逆なのですが、長い曲名(例えば「私の中の幻想的世界観及びその顕現を想起させたある現実での出来事に関する一考察」)であっても「私の中」「世界観」「出来事」と入力してしまえば正解扱いにされるというような抜け穴が存在しました。非常に長い曲名を持つ曲はそう多くはないものの、このような抜け穴が残ってしまうのは嫌でした。

## 改善
上で挙げた7つの問題を解決していきます。

### 1. コマンドシステムを実装する
問題点1を解決するついでにヒント機能を実装するため、曲名入力画面でコマンドを打つことができるようにしました。
`_`で始まっている文字列はコマンドとして扱うということにしました。
prefixとしてアンダーバーを選んだのは、単にアンダーバーで始まる曲名がなさそうだと思ったからです(`!`だと「!!!カオスタイム!!!」などが存在しているので)。
このコマンドシステムにギブアップ機能やヒント機能を組み込みました。
以下に実際に実装したコマンドの一覧を載せます。
- `_giveup`: ギブアップ機能。答えがわからないときに入力する。
- `_replay`: リプレイ機能。もう一度再生する。
- `_length`: 曲名の長さを表示する。
- `_letter`: 曲名の最初の1文字を表示する。

この画像では実際にコマンド機能を利用しています。5曲目のところで使っています。
![スクリーンショット 2020-09-07 14.31.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/310556/a4293599-4d54-25cc-963f-ab3e5548704f.png)

コマンドは自由に追加できるような構造にしているので、ヒントをさらに充実させることも可能です。

### 2. 文字を小文字に統一し、スペースをなくす
問題点2を解決するため、入力されたアルファベットを小文字に変換するようにしました。
これにはPythonに備わっている`lower()`メソッドを用いました。
ただし、パーフェクト判定のためにもともとの正しい曲名も残すようにしています。
詳しくはGistにアップしたコードを見ていただきたいのですが、

1. 入力された文字列ともともとの曲名を比較してパーフェクト判定をする
2. 1がFalseだった場合入力された文字列を`lower()`したものともともとの曲名を`lower()`したものを比較して正解判定をする
3. 2でもFalseだった場合不正解と判定する

という手順で判定しています。

### 3. 次の曲までの間にインターバルを設ける
これは単純に`input()`を入れて、次の曲に行くにはEnterを押さなければいけないようにしました。
最初は`time.sleep()`を使おうかとも考えていましたが、別にここの時間を固定長にする必要はないと気づいてこのような実装になりました。

### 4/5. 再生部分・時間をランダムにした
問題点4と5をまとめて解決するため、楽曲をイントロではなく途中のランダムな点から再生されるようにしました。また、再生時間も3秒から7秒の間でランダムに選ばれるようにして、高い難易度と低い難易度をバランス良く混ぜることができるようにしました。

### 6/7. 正解文字数に対する割合で判定するようにした
問題点6と7はまとめて解説します。
以下に該当部分のコードを貼ります。

```python
# 長さ判定部
if len(answer) >= min(len(music_name)//3, len(music_name_lower)):
    # 正解判定部
    if answer == music_name:
        print("パーフェクト！すごいね！")
        break
    elif answer_lower in music_name_lower:
        print("正解！おめでとう！")
        break
    else:
        print("残念！不正解！")
else:
    print("入力文字数が少なすぎるよ！")
```

2行目で分かる通り、条件を『3文字以上』から『曲名の1/3以上』に変更しました(問題点7の解決)。
また、こうすることで曲名が1文字であっても正常に動作するようになりました(問題点6の解決)。

## 改善・修正できなかったこと/したいこと
### 時々エラーが発生する
![スクリーンショット 2020-09-07 14.31.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/310556/9676780f-b5b3-2af0-73b1-c7528de3e23c.png)
たまに、曲が再生されずにこういったエラーが発生してしまいますが、原因がわからず今の所放置してしまっています。

### Discordと連携したい
今はこの音楽クイズをDiscordで友達と遊ぶことが多いので、友達が入力した答えをそのままプログラムに流し込んで判定をもう少し楽にしたいです。現時点では私が自力で皆の答えをコピペする必要があります。

### 上限回数を設定したい
最初に何曲分遊ぶかを設定したり、解答できる上限を設定したりしたいです。

### ファイル名ではなく曲名を直接取ってきたい
「TiamaT:F minor」という曲があるのですが、`:`はファイル名に使えない文字なので`TiamaT-F minor`や`TiamaTF minor`というような表記に置き換わってしまっています。
ファイルそのものに設定された曲名は正しいので、そちらを判定に用いるようにしたいです。

## まとめ
結局イントロクイズではなく音楽クイズになってしまいましたが、より退屈することも減ったので満足しています。またCDを購入して曲のバリエーションを増やして遊びたいと思います。