自動化コンテストに向けてスクリプトを作成して感じたこと

# はじめに
皆様、はじめまして。
AIQVE ONE Advent Calendar 15日目を担当します、@hi-endoです。
本記事は、昨年の12月から今年の2月にかけて行われた社内の自動化コンテストに参加した際、スクリプトを作成して感じたことを記載したものになります。
自動化コンテストについては、[AIQVE ONE Advent Calendar 9日目の記事](https://qiita.com/mi_373/items/85132416af540e63d9bd)に詳しく記載されておりますので是非、ご覧ください！

# スクリプト作成に使用したツール
スクリプト作成には、私が所属するAIQVE ONE株式会社で開発している[Garbo](https://www.aiqveone.co.jp/news/2022/491/)を使用しました。
ツールの詳細は、上記リンク先のページにてご確認いただきたいのですが、簡単に説明すると、プログラミング未経験者にも簡単にプログラムが組めて、テストを自動化できるようにしたツールがGarboです。

# 何を作成したか
某人気野球ゲームアプリのバッティング操作を自動化しました。
自動化するに思い当たった理由は、

「ファールを打ち続けて永遠に打席に立ち続ける最強のカットマンを作れたら面白そうだな」

と思ったからです。

最終的には、80kmのストレートをストライクとボールを見極めながら打ち返すだけのスクリプトになりましたが、基本の形はできたと思うのでカットマンの作成はできそうだなと感じてます。

# スクリプト作成から何を感じたか
バッティング操作をするためには、
・ストライクゾーンやバットを振る位置、投げられた球のコースを把握する
・ボールが打者の手元に来るまで待機する
・ストライクだったらバットを振る
の主に3つの処理を行う必要があるのですが、これらを実行するために与えられた時間は7秒ほどしかありません。
時間をオーバーすると、コースを取得できなかったり、バットを振るタイミングが合わなかったりとまともに動作しなくなるので、<strong>スクリプト実行を高速化する</strong>という考え方はとても重要でした。

上記の考えからいろいろと試した結果、ちょっとした工夫でスクリプト実行を高速＆効率化することができることが分かりましたので、その工夫をこの場をお借りして紹介させていただきたいと思っています。

# 本題
ここからはスクリプト実行を高速＆効率化する工夫について紹介させていただきます。

### ■ スクリプトでよく使用する画像は定数化しておく
スクリプトでよく使用する画像（ボタンなど）はスクリプトの初めの方でexistsコマンドを使用して定数化しておくと後々便利です。

existsコマンドとは、引数に指定した画像が画面上に存在するかを確認するコマンドです。
画面上に存在しなければ"False"、<strong>存在すれば合致する部分の座標値を戻り値として返します</strong>。

上記の仕様から、existsコマンドで取得した座標値を定数化して使用するというのがこの節の話になります。
例えばGoogle Chromeのアプリアイコンを3回押下するスクリプトを作成する場合、以下2つのスクリプトは両方とも仕様を満たすスクリプトになります。
![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2969819/61a0329e-48cc-6eb0-05ae-640a6023426a.png)
（左がtouchコマンドで3回記述したもの、右がexistsコマンドで取得した座標値を参照して記述したもの）

結果が同じならどちらでもいいと思うかもしれませんが右のスクリプトの方が多くのメリットがあります。

まず、何と言っても<strong>スクリプトの実行速度が上がる</strong>というメリットがあります。
Garboには、レポートという機能があり、スクリプトの各行で行った処理の内容や処理にかかった時間を把握することができます。
この機能を用いて2つのスクリプトの実行時間を比較した画像が以下になります。
![図2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2969819/bb0eb825-d75a-037e-2678-3c324f2b4ecd.png)
（左がtouchコマンドで3回で実行したレポート、右がexistsコマンドで取得した座標値を参照して実行したレポート）

結果、右のスクリプトの方が、<strong>約1秒早く実行できる</strong>ことがわかります。
この単純なスクリプトでさえこれだけの差が生まれるので、複雑なスクリプトであればより短縮することが見込めます。

なぜ差が生まれるのかというと、画像検索の回数が異なるためです。
左側のスクリプトは一見、existsコマンドを使用していないので画像検索をしていないように見受けられますが、実は<strong>コマンドの引数に画像を指定するとその画像を検索してからコマンドを実行する</strong>仕様となっており、Touchコマンドを実行する度に画像検索を行っていました。
一方、右側のスクリプトは、Touchコマンドの引数に座標値を指定しているため画像検索は最初の1回で済みます！
右側のスクリプトより左側のスクリプトの方が画像検索を多く実行するため、実行時間に差が生まれたというわけです。
リアルタイム性が求められるアプリは、処理に時間をかけすぎるとサンプリングが間に合わないといったことが多発するので、こういった小さな工夫で処理時間を短縮していくことがスクリプトの安定に繋がると感じています。

他にも、<strong>メンテナンスがしやすい</strong>というメリットもあります。
Google Chromeのアプリアイコンを別のアイコンに変更することになった場合、左側のスクリプトは3行変更しなければならないのに対し、右側のスクリプトは1行で済みます！
今回は3行しかないので大した手間じゃないと考えるかもしれませんが、スクリプト内に同じ処理が50、100行あったとしたら圧倒的に右側のスクリプトの方がメンテナンスがしやすいです。
また、変更箇所が少なくなるので、更新漏れを防ぐことにも繋がります！
ただ、変数だとぱっと見で<strong>何の画像を参照してるのかがわかりづらくなる</strong>というデメリットがありますが...。

注意点として、<strong>位置が変わるアイコンやボタンなどは定数化しないほうがいい</strong>ことが挙げられます。
existsコマンドは、実行した時の座標値を返すので時間経過で位置が変わるアイコンやボタン（音ゲーのノーツなど）には適しません。せっかく取得した座標値が使い物にならなくなりますからね...

## まとめ
本記事で紹介したいことをまとめますと以下3点になります。
* タイミング重視のアプリを自動化する場合は、スクリプトの実行時間に注意する
* existsコマンドは、引数に指定した画像と合致する部分の座標値を返す
* 座標値は変数に格納して使用したほうが、スクリプト実行の高速化とメンテナンスが容易になるなどのメリットがある。（スクリプトの可読性が下がるというデメリットは念頭に置いておく）

本記事の内容が少しでも業務のお役に立てれば幸いです。
最後まで読んでいただきありがとうございました。