クイズアプリ「みんはや」にたくさんの作った問題セットを(半)自動で追加させる

はじめまして。記事初投稿なのでよろしくお願いいたします。

# 背景

IOS,Andoridアプリ、「みんなで早押しクイズ」、略称「みんはや」では作問ができて自分で作成したクイズを遊ぶことができる。自分で作成したクイズを入れるのはいいが**手入力はめんどくさい、問題数が多すぎる**の対策として半自動入力を導入してみようと試みました。
作問の自動入力さえできればあとはプログラム実行して寝れば作成した中間試験、期末試験対策の問題はみんはや遊べます。

注意:このプログラムは完全ではありません。**極稀にバグ**を起こしますので最初はある程度監視してください。
# 作成・設計・実装
残念ながら自分はこのプログラムの内部まで探ることはできませんでした．したがって**半自動的にPCを操作する**ことで問題セットをアプリ上に追加していきます．
**2022/08/15追記：** みんはやのUIが大幅に変わってしまったみたいですが実装方法は特に変わらないみたいなのでこれでも問題ないです。
### 必要なもの
Pythonの基礎知識(実行、基本入出力、importがわかっていれば大丈夫です。)
PC(windows10でやっていますがmacでも大丈夫です．)
1.Python3
　　3.6を使ってますが3.7以降でも構いません
2.Bluestacks4
3.Pythonの実行環境
　　いつでも簡単に止めれるようにPyCharmの使用をおすすめします。

## 1. Bluestacks4の導入
BluestacksはAndoridエミュレーターであり、このエミュレーターでみんはやを実行します。
[Bluestacksのダウンロードはこちらから](https://www.bluestacks.com/ja/index.html)
インストール後、Google Play ストアに行ってみんはやをインストールします。

インストール後、みんはやを開きBluestacksをデスクトップ上で画面いっぱいに左側に設置するようにしてください。
(今後実行時の調整に役に立ちます。)

![bandicam 2020-04-06 15-37-40-911.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614546/27bbe7e2-d016-d6eb-3364-ebc50fcb77f3.jpeg)

## 2. 重要点の座標の把握
ここではみんはやのクリックしなければ行けないところを把握します。
画像の以下の点になります。
タイトル画面で作問ページに飛んだあと、
**1. 問題追加のボタン
2. 問題文枠
3. 回答枠
4. 保存ボタン
5. Bluestacks上での「戻る」のボタン
6. 問題決定後の画面消し**(aの枠ですが必要ではありません(あってもいい))

今回の場合は画像では次のようになります。
2,3,4,aの枠は大きいですがその中のどこかであればokです。

![hijdsjufdisjof.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614546/e3829c11-99fd-062b-996f-10ddfdf673df.png)


![tfyuiogyyuiogy.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614546/047a8f98-f695-7c9e-4ad9-56d21e52a8c9.png)

### 座標の把握方法
把握方法はクリックした座標を返すなどのプログラムを使います。
[こちらのソースコードは他サイトからの引用になります．](https://pynput.readthedocs.io/en/latest/mouse.html)

``` python:cursor.py
from pynput.mouse import Listener
def on_move(x, y):
    print(x, y)

def on_click(x, y, button, pressed):
    print(x, y, button, pressed)

def on_scroll(x, y, dx, dy):
    print(x, y, dx, dy)

with Listener(on_click=on_click) as listener:
    listener.join()
```

実行後1～6までクリックします。クリックしたときの座標が返されるのでメモしましょう。
把握した座標は自分では次のようになりました。

```txt
1.530 975　    問題追加ボタン
2.200 180      問題枠
3.250 300　    回答枠
4.165 450      保存
5.600 1020     戻る
6.(a)400 800   枠外クリック
```

このように画面縦最大化かつ左端に調整すれば次回実行時もこの手順が省略できるのでおすすめ

## 3.問題文の作成
問題文はCSVファイルでの作成を行います。excelだと作成しやすいのでそれを使います。
A列には問題文、B列には回答を記載します。↓のような感じに書きます。(**問題文、回答は日本語でも構いません!**)
![bandicam 2020-04-06 16-23-34-634.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614546/416d3421-84dd-4f5f-ac18-33547818ed9a.jpeg)
完成したらCSVで保存します。今回はspeng.csvで保存してます。

## 4. PythonでCSVを開く
python上で問題文と回答をぞれぞれ読み込みます。

```python:readcsv.py
import csv
with open('ここにCSVのファイル名.csv', 'r' ,encoding="utf_8") as f:
    reader = csv.reader(f)
    for row in reader:
      #ここに問題を追加する処理(後述)
```
これでrow[0]には問題文、row[1]には回答が入ります。
**注:**encoding="utf_8"は読み込んだファイルに日本語が書かれている場合文字化けor日本語が読めなくて問題発生を回避するためのものです。

## 5.さあクイズを入れよう!

1問作問する際の流れは次のようになります。

```
1.問題追加ボタンをクリック
2.問題文をCSVからコピー
3.問題枠をクリック
4.問題文をペースト
5.回答枠をクリック
6.回答をCSVからコピー&ペースト
7.保存ボタンクリック
8.枠外クリックor enterキー入力
9.戻るボタンクリック
```

ちなみにクイズ作成はpyAutoGUIという、カーソルやキーボードを自動的に操作するプログラムを使用します。
pyAutoGUIでは以下のものを使います。**(以下pyautoguiはpと書きます)**

- **p.click(x,y)** →座標x、yをクリックします
- **p.typewrite('ABC')**　→文字列ABCを入力します(キーボードから入力した感じになります)
- **p.hotkey('A','B')**　→A,Bのキーを同時押しします　(キーボードAを押したままBを押すみたいになります。)

[pyautoguiについては詳しくはこちらに書かれています。(外部サイト)](https://www.lisz-works.com/entry/pyautogui-key)


では順番に説明していきます。
### 1.問題追加ボタンをクリック
ここはp.click(x,y)を使って追加ボタンを押せば終わり…**ではありません**。
↓のようにクリックすると一定時間後に問題枠、回答枠が出るようになります。

![ezgif.com-video-to-gif.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614546/5719ced5-3684-1e1c-15a7-62cc60dfc686.gif)


pythonはクリックの処理が終わったら急いで次の行の処理を行います。ここで問題文のクリック、貼り付けが早すぎると意味がありません。
そこで**timeモジュールをimport**し、プログラムの実行を少し抑えます。time.sleep(1)を使えば次の行の処理を行うまで1秒待ってくれます。例えばですが、

```python:sleep.py
import time as t
print(1)
t.sleep(1) #ここで1秒待ってくれる。↓の処理はしない。
print(2) #1秒後に2が出力される。
```
なのでここでは問題追加をクリックしたあと、1秒待ってもらいましょう。1秒待ってもらう間に問題文をコピーできる暇があるのでコピ－しちゃいましょう。


### 2.問題文をCSVからコピー

問題文は手入力でもいいのですが日本語を打つ場合はローマ字入力がほぼ必須になってしまいます。
そこで**問題文、回答文をコピー&ペーストする**ことによって手間を省略します。
上記のp.hotkey('ctrl','v')でペーストができますがコピーはどこかからハイライトしたものでなければ使えません。そこで**pyperclip**のモジュールを使用し問題文、回答のコピーを行います。

```python:excample-of-copy-paste.py
import pyautogui as p
import pyperclip
pyperclip.copy(row[1]) #ここで回答をクリップボードにコピー
p.click(250,300) #回答枠クリック
p.hotkey('ctrl','v') #ここで回答を解答欄に貼り付け　
```
### 3.問題枠をクリック
問題枠のクリックは1と同じようにクリック処理を行えばokです。(今回はp.click(200,180))

### 4.問題文をペースト
問題文の貼り付けはp.hotkey('ctrl','v')を使えば貼り付けを行えます。
**重要**:Bluestacksの都合上かは不明ですが日本語入力のIMEを使用した状態で貼り付けを行うと「v」のみしか出てきません、画像のようにしようする入力は英字入力(ENG)にしてください

![bandicam 2020-04-06 18-14-34-921.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614546/e8c1fdca-6e44-690b-4996-7430ba205766.jpeg)

ここまでの流れは以下のようになります。

```python:step1~step4.py
p.click(510, 975)  # 問題追加クリック(step1)
pyperclip.copy(row[1])  # 問題文コピー(step2)
t.sleep(1) #1秒待ってもらう
p.click(200,180) #問題枠クリック　(step3)
p.hotkey('ctrl', 'v') #問題文貼り付け(step4)
t.sleep(0.5) #保険で0.5秒待ってもらう
```
### 5.回答枠をクリック
さあ後半戦。ここでも3と同じようにクリックして終わり。
p.click(250,300)のみで大丈夫です．
### 6.回答をCSVからコピー&ペースト
同じように回答文もコピー&ペーストを行います。しかしここで注意点。回答文の貼り付けが終わったら
　**enterキーを押し、3～5秒ほど待ってもらいます。**
理由として回答文の入力が終わったら自動で読みをみんはやアプリが打ってくれます。漢字であってもひらがなになってくれます。しかしその処理を行うのが焼く3秒～5秒ぐらいです。↓が例(**PCの速さによります**)　

![ezgif.com-crop.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614546/cdefa4cf-2a2b-4058-0289-786ae6ed0e51.gif)

とても遅い場合はなるべく他のプログラムは閉じておきましょう

ここまでは以下のようになります。

```python:step1~step6.py
p.click(510,975)
pyperclip.copy(row[1]) 
t.sleep(1)
p.click(200,180) 
p.hotkey('ctrl','v') 
t.sleep(0.5) 

# ここまでstep4

pyperclip.copy(''.join([row[0],'\n'])) #回答をコピー (step6)
p.click(250,300) #回答枠クリック(step5)
p.hotkey('ctrl', 'v') #回答文貼り付け(step6)
t.sleep(3)
```
### 7.保存ボタンクリック
3~5秒待ったら保存ボタンを押して保存されましたと出ます。出るのに0.5秒ほどかかるのでプログラムも1秒ほど待っておきましょう。
### 8.枠外クリックor enterキー入力
「クイズを更新しました」というメッセージが出るのでそれを消す方法としては**枠外をクリック**する、もしくは**enterキーを2回押す**の方法があります。

![bandicam-2020-04-06-19-20-15-653.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614546/a35144f8-cec1-5115-9ba8-f97f201625b5.gif)
もしも枠外をクリックして消した場合はp.clickを使用すれば問題ありません。
enterキーを使う場合、高速で連打されると認識されない可能性が高いです。そのため、enterキーを押す処理を行ったら0.5秒ほど待ってもらってもう一度押す処理を行います。

```python:exitsave.py
import pyautogui as p
p.click(165,450) #保存ボタンクリック
#枠外クリックによる解除
p.click(1250,700)
#enterキー2回による解除
p.typewrite('\n')
t.sleep(0.5)
p.typewrite('\n')
```

なお、保険として両方行うことは可能ですが、枠外クリック→enterキーでは問題文を改行させてしまいます。しかし今後問題文は更新ボタンを押すことがないので問題はありません。
### 9.戻るボタンクリック
最後にbluestacks上の戻るボタンを押します。戻るボタンの位置ですが**バージョンによって位置が変わってくるため**、大型アップデートで変わってないか注意しましょう。(戻るボタンが左下にあったバージョンもありました。)
p.click(600,1200)で十分です。

最後のステップが終わったらt.sleep()でプログラムを3秒ほど寝かせます。**もしも途中でやめたい場合はここでプログラムを終了させます。**

以上で問題の追加処理は終わりです。
## 全体の調整
問題文の作成を途中までやって再実行するときに1からはやりたくない、ってときのために最初に何問目から開始するかの入力を受け付けて起きます。それまでは何回問題文と回答を読み込み、何もしません。

```python:startnum.py
ct = 0 #何問読み込んだかのカウンター(0か1から始めるかは自由です)
start = int(input()) #何問目から開始するか
qnum=0 #今処理を初めて何問目?(タイムショック)
with open('speng.csv', 'r' ,encoding="utf_8") as f:
    reader = csv.reader(f)
    for row in reader:
        ct+=1
        print("r",ct)
        if row[1] != '0' and row[0] != '0' and ct >= start: #規定の問題数を読み込んだら問題を追加
            qnum+=1

```
## 完成!
お疲れ様!
これで好きなクイズセットが作れます!

# 現状の不具合
### アプリ上で貼り付けできない
稀だけどwindows上ではちゃんと問題文をコピーしてるにも関わらず、ずっと反映されない不具合があります。

1. 回答Aを貼り付け→A出力
2. 保存
3. 次の問題作成
4. 問題Bコピー→貼り付け
5. **何故かAが出力される**

以降ずっとどんなに貼り付けしてもAしか出ません。対策としてはbluestacksを再起動してください。
###ボタン押しても戻れない
作成の部分でステップ9の戻るボタンをクリックしたのにも関わらず、作問した問題一覧のページに以下ない不具合もあります。その結果、問題Aと問題Bが同じ1問で一緒になっちゃうときがあります。

これは直せないのでプログラム終了後この問題単体を削除してください。


# 終わりに
最後まで読んでいただきありがとうございました。
はじめて記事を書かせていただきました。誤字脱字などは多々あると思います。
このクイズを拡張できれば計算問題も作れるかも?
### これを見ているみんはや運営さんがいたら
csvファイルによる問題追加を簡単にできるようにしてほしいです。お願いします…