PyAutoGuiとPyOCRで放置少女の育成を自動化

ハシカンがCMしていたからはじめた放置少女。

偶然ハシカンに出会っても「放置少女やってます」って話しかけられる。

僕と環奈を繋ぐたった一つの糸。放置少女。

そんな放置少女の育成は死ぬほどめんどくさい。

めんどくさいことは自動化しよう。

アンドロイドエミュレーターNoxとPyAutoGuiで画像認識させて自動化してみたので、必要な人は参考にして。

ディレクトリ構成

PyAutoGuiでこれらのボタンの位置を探してきて、クリックする

getParameter()の中で画像の位置を取得してます。下のコードではPC画面の右半分くらいを範囲として(region=(275, 1373, 276, 40))、指定の画像を探しています。PC画面全域から探させるのは処理が重くなるかなと思って、せめてもの優しさ?

pyautogui.click()の位置がずれるのはRetinaディスプレイの絡み。

pyautogui.locateOnScreen()で画像の位置情報を取ってこれるのですが、その座標をpyautogui.click()でクリックさせてもズレている…

これはMacのディスプレイの解像度がRetinaディスプレイで普通の2倍の解像度を持っているかららしい!

てことで、pyautogui.locateOnScreen()で取ってきた座標を÷2してあげれば、正しく画像の位置をクリックしてくれる!

like this way

pyautogui.click(btnLeftX / 2, btnLeftY / 2)

育成前後のステータスをスクショ撮って、PyOCRでどれだけステータスが上がったのか計算

getSS()で育成前と育成後のステータス部分のスクリーンショットを撮って、getText()の中でPyOCRを使ってステータスの画像認識をして数値を取得し、どのステータスがどれだけ上がったのかを計算しています。

トータル戦力が上がればいいかなってことで筋力×4、体力×3、敏捷・知力等倍の重みで計算してます。

total = strength * 4 + physical * 3 + agile + inte

今回は武将verですが、謀士弓将でこの計算式はいじります。

それぞれのステータスには重みがあるので、筋力や知力が1上がったとしても、総戦力の上がり方が違います(武将は筋力と体力をあげたい)

この重みを計算するための式を↓の記事で書いています。

サンプルコード

import getParameter as gp
import time


def main():
    print('main')

    # ボタンの場所などを確認
    gp.getParameter()

    # ウィンドウのアクティブ化
    gp.clickLeft()

    for i in range(500):
        print('---------------------------')

        # C級育成
        gp.clickLeft()

        gp.getSS()

        gp.getText()


main()
import pyautogui
import cv2
import pyocr
import pyocr.builders
from PIL import Image
import sys
import time


preParamImg = 'tempImg/preParamImg.png'
paramImg = 'tempImg/paramImg.png'
preStatusTop = 0
preStatusBottom = 0
statusTop = 0
statusBottom = 0
preTop = 0
height = 0

btnLeft = 0
btnRight = 0


def test():
    preStatusTop = pyautogui.screenshot(region=(275, 1373, 276, 40))
    preStatusTop.save('test.png')
    pyautogui.click(250, 400)
    pyautogui.click(250, 400)

    pyautogui.click(250, 400)


def getParameter():

    global preStatusTop
    global preStatusBottom
    global statusTop
    global statusBottom
    global preTop
    global height
    global btnLeft
    global btnRight

    preStatusTop = pyautogui.locateOnScreen(
        'refImg/preStatusTop.png', region=(0, 0, 1000, 1500), confidence=0.8)

    preStatusBottom = pyautogui.locateOnScreen(
        'refImg/preStatusBottom.png', region=(0, 0, 1500, 1500), confidence=0.8)

    statusTop = pyautogui.locateOnScreen(
        'refImg/statusTop.png', region=(0, 0, 1000, 1500), confidence=0.8)

    statusBottom = pyautogui.locateOnScreen(
        'refImg/statusBottom.png', region=(0, 0, 1500, 1500), confidence=0.8)

    preTop = preStatusTop.top + preStatusTop.height
    height = statusBottom.top - preTop

    btnLeft = pyautogui.locateOnScreen(
        'refImg/btnLeft.png', region=(0, 0, 1500, 3000), confidence=0.8)

    btnRight = pyautogui.locateOnScreen(
        'refImg/btnRight.png', region=(0, 0, 1500, 3000), confidence=0.8)


def clickLeft():
    btnLeftX, btnLeftY = pyautogui.center(btnLeft)
    pyautogui.click(btnLeftX / 2, btnLeftY / 2)  # retinaDesiplayは/2
    time.sleep(1)


def clickRight():
    btnRightX, btnRightY = pyautogui.center(btnRight)
    pyautogui.click(btnRightX/2, btnRightY/2)  # retinaDesiplayは/2
    time.sleep(1)


def getSS():
    preSc = pyautogui.screenshot(
        region=(preStatusTop.left, preTop, preStatusTop.width, height))
    sc = pyautogui.screenshot(
        region=(statusTop.left, preTop, statusTop.width, height))

    preSc.save(preParamImg)
    sc.save(paramImg)
    # time.sleep(1)


def getText():
    tools = pyocr.get_available_tools()
    tool = tools[0]
    langs = tool.get_available_languages()
    param = tool.image_to_string(
        Image.open(paramImg),
        lang='eng',
        builder=pyocr.builders.DigitBuilder()
    ).split()
    preParam = tool.image_to_string(
        Image.open(preParamImg),
        lang='eng',
        builder=pyocr.builders.DigitBuilder()
    ).split()

    while (len(param) != 4):
        time.sleep(0.3)
        print('成長後のステが取れなかったのでもう一度')
        getSS()
        param = tool.image_to_string(
            Image.open(paramImg),
            lang='eng',
            builder=pyocr.builders.DigitBuilder()
        ).split()

    print(preParam)
    print(param)

    strength = int(param[0]) - int(preParam[0])
    agile = int(param[1]) - int(preParam[1])
    inte = int(param[2]) - int(preParam[2])
    physical = int(param[3]) - int(preParam[3])
    total = strength * 4 + physical * 3 + agile + inte

    print(total)
    if (total >= 0):
        print(total)
        print('保存')
        clickRight()

        # 結果が表示される。邪魔なので3秒待つ。
        time.sleep(3)

    else:
        print(total)
        print('閉じる')
        clickLeft()