3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【Python】Seleniumでやさしい神経衰弱ゲームを最速攻略する🎮

Posted at

弊社mori_goqの作成したやさしい神経衰弱ゲームをやってみたところ、過去にワギャンランド🦖で鍛えたはずの記憶力の衰えを実感し、悔しくなったため技術力で攻略してやろうと思いました。
スクリーンショット 2023-01-29 18.28.37.png

攻略本を読む📕

リポジトリという名の攻略本が公開されているので読み解いていきます。

シャッフルの待機時間⏳

const SHUFFLE_COUNT = 3
const SHUFFLE_DURATION = 500

// シャッフル
for (let _ of [...new Array(SHUFFLE_COUNT)]) {
  cardList = arrayShuffle(cardList)
  // シャッフルの動作を待つ
  await new Promise(resolve => setTimeout(resolve, SHUFFLE_DURATION + 200))
}

ゲームスタートボタンをクリックして、シャッフルは700ms毎に3回行われるようなので、シャッフル後にカードの絵柄がクリックできるようになるのは2.1秒後ということになります。
ただし、実際に配置が決定するのは3周目でcardList = arrayShuffle(cardList)が行われたタイミングなので、1.4秒後に決定していることになるはず。
2.1秒後にカードの配置を調べていたら若干のタイムロスが発生するため、上記の1.4秒経過時点でカードがどこに設置されてるのか確認する処理を行なっておくことが、最速攻略のためには重要そうです🃏

カードの配置を調べる🕵️

<div class="box card-board">
  {#each cardList as card (card.id)}
    <div animate:flip="{{ duration: SHUFFLE_DURATION }}">
      <button
        type="button"
        class="mb-0 button card-button"
        data-is-front={card.isChecked || card.isMatch}
        disabled={isLockCard || card.isChecked || card.isMatch}
        on:click={() => handleClickCard(card.id)}
      >
        <img src={card.imageSrc} class="card-image" alt="#" />
        <img src={imageBack} class="card-image" alt="#" />
      </button>
    </div>
  {/each}
</div>

表側の絵柄は.card-board.card-button > img[1]のファイル名で判別することができます。
下記スクショのファイル名の頭2文字さえわかればOKです🙆
スクリーンショット 2023-01-29 18.29.15.png

攻略🥷

まずは結果をご覧ください。
画像が小さいので気になる方は後述のコードをお試しください
easy-memory-game.gif
🎉🎉🎉Congratulations🎉🎉🎉

処理にかかった時間:0.11477184295654297
クリックにかかった時間:0.29099583625793457
ページ開いてからの時間:2.433328866958618

コード⌨️

import re
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from webdriver_manager.chrome import ChromeDriverManager

driver = webdriver.Chrome(ChromeDriverManager().install())

# やさしい神経衰弱ゲームのページを開く
driver.get('https://easy-memory-game.vercel.app/')

# ページ開いてからの時間計測
all_start = time.time()

# ゲームスタート!
start_button = driver.find_element(By.XPATH, '//button[contains(@class, "is-primary")]')
start_button.click()

# 待機時間
WAIT_TIME = 2.1
FIRST_TIME = 1.4

# 1.4秒待ってカードの位置を調べる
time.sleep(FIRST_TIME)

# 処理前の時間
start = time.time()

# 左上からカードの絵柄を調べる
imgs = driver.find_elements(By.XPATH, '//button[contains(@class, "card-button")]/img[1]')
click_list = [{
    'index': i,
    'name': re.match('.*?(\d+-).*', card.get_attribute('src')).group(1)
} for i, card in enumerate(imgs)]

# ファイル名順にソートして、クリックする順番を決定
click_list = sorted(click_list, key=lambda x: x['name'])

# 処理後の時間
end = time.time()

# 処理時間にかかった時間を算出
diff = end - start
print(f'処理にかかった時間:{diff}')

# 残待機時間(0.7秒)から処理時間引いた分待機する
time.sleep(WAIT_TIME - FIRST_TIME - diff)

# クリックの処理の時間計測
start = time.time()

# クリックあるのみ
for item in click_list:
    driver.find_elements(By.XPATH, f'//button[contains(@class, "card-button")]')[item['index']].click()

end = time.time()

print(f'クリックにかかった時間:{end - start}')
print(f'ページ開いてからの時間:{end - all_start}')
一応、requirements.txtの中身も。
async-generator==1.10
attrs==22.2.0
certifi==2022.12.7
charset-normalizer==3.0.1
exceptiongroup==1.1.0
h11==0.14.0
idna==3.4
outcome==1.2.0
packaging==23.0
PySocks==1.7.1
python-dotenv==0.21.1
requests==2.28.2
selenium==4.8.0
sniffio==1.3.0
sortedcontainers==2.4.0
tqdm==4.64.1
trio==0.22.0
trio-websocket==0.9.2
urllib3==1.26.14
webdriver-manager==3.8.5
wsproto==1.2.0

解説🙏

大体は攻略本を読むに書いてる通りですが、絵柄を調べるところだけ解説しておきます。(大したことはしてないですが)

.card-buttonを1つずつ順番に調べていき、絵柄のファイル名(name)とindex値(index)を保持します。
全部書くと長いので、今回は3絵柄とします。(2絵柄だと逆にわかりにくいので)

click_list = [
    {
        'index': 0,
        'name': '03-'
    },
    {
        'index': 1,
        'name': '01-'
    },
    {
        'index': 2,
        'name': '03-'
    },
    {
        'index': 3,
        'name': '02-'
    },
    {
        'index': 4,
        'name': '02-'
    },
    {
        'index': 5,
        'name': '01-'
    }
]

そしてnameの値でソートをかけます。

click_list = [
    {
        'index': 1,
        'name': '01-'
    },
    {
        'index': 5,
        'name': '01-'
    },
    {
        'index': 3,
        'name': '02-'
    },
    {
        'index': 4,
        'name': '02-'
    },
    {
        'index': 0,
        'name': '03-'
    },
    {
        'index': 2,
        'name': '03-'
    }
]

こうすることで絵柄のペアごとにクリックする順番が確定できます。

上記の場合、こんな感じ。

  1. .card-button[1].click().card-button[5].click()で絵柄マッチ
  2. .card-button[3].click().card-button[4].click()で絵柄マッチ
  3. .card-button[0].click().card-button[2].click()で絵柄マッチ

まとめ🍰

まだ試していないことがいくつかあり、これが最速ではない気はしていますが、ぱっと見では0秒で終えてるのでひとまずはここまでとします。
また機会があれば改善していくつもりです。

最後に

GoQSystemでは一緒に働いてくれる仲間を募集中です!

ご興味がある方は以下リンクよりご確認ください。

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?