LoginSignup
2
3

More than 5 years have passed since last update.

PythonにBrain Warsをプレイさせてみた3

Last updated at Posted at 2018-09-23

はじめに

PythonにBrain Warsの Make10 をプレイさせてみた

Make10 のルール

数字の合計が10になるカードの組み合わせを見つけてタップする

Demo

demo.gif

環境

  • OS: Ubuntu 18.04.1 LTS
  • Python version: 3.6.5
  • スマホ: Huawei P10 Lite

VysorというChromeの拡張プラグインを使って、Ubuntuからスマホを操作している

コード

import mss
import numpy as np
import time
import cv2
import pyautogui as pag
import itertools
from sklearn.neighbors import KNeighborsClassifier


def grab_screen(bbox):
    """Capture the specified area on the screen"""
    with mss.mss() as sct:
        left, top, width, height = bbox
        grab_area = {'left': left, 'top': top, 'width': width, 'height': height}
        img = sct.grab(grab_area)
        return np.array(img)[:, :, :3]


def process_img(img):
    """Extract numbers from each card"""
    img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    _, img_bin = cv2.threshold(img_gray, 210, 255, cv2.THRESH_BINARY)
    _, cnts, _ = cv2.findContours(img_bin, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    cnts = list(filter(lambda x: 30 < cv2.boundingRect(x)[-1] < 70, cnts))
    cnts = sorted(cnts, key=lambda x: (cv2.boundingRect(x)[1] // 10, cv2.boundingRect(x)[0]))
    rois = []
    locs = []
    for cnt in cnts:
        x, y, w, h = cv2.boundingRect(cnt)
        locs.append([int(x + w/2), int(y + h/2)])
        cv2.rectangle(img, (x, y), (x + w, y + h), (0, 0, 255), 2)
        roi = cv2.resize(img_bin[y:y+h, x:x+w], (10, 10)).reshape(1, 100)
        rois.append(roi)
    cv2.imwrite('detection_result.jpg', img)
    locs = np.array(locs)
    rois = np.array(rois).squeeze()
    return rois, locs


def build_knn():
    """Create and train knn classifier"""
    samples = np.loadtxt('train_samples.data', np.uint8)
    labels = np.loadtxt('train_labels.data', np.float32)
    knn = KNeighborsClassifier(n_neighbors=3)
    knn.fit(samples, labels)
    return knn


def find_combination(nums):
    """Find a combination which sums to 10"""
    result = [seq for i in range(len(nums), 0, -1) for seq in itertools.combinations(nums, i) if sum(seq) == 10]
    return result


def main():
    grab_bbox = (104, 385, 467, 300)
    knn = build_knn()
    while True:    
        img = grab_screen(grab_bbox)
        rois, locs = process_img(img.copy())
        if len(rois) > 12 or len(rois) < 9:
            print('Done')
            break
        nums = knn.predict(rois).astype(int)  # classify numbers
        while len(locs) > 0:
            idx = (np.abs(locs[:, 1] - locs[-1, 1]) < 5)  # index of cards at the bottom row
            locs_ = locs[idx].tolist()
            nums_ = nums[idx].tolist()
            comb = find_combination(nums_)
            print('Cards to click:', comb[0])
            for num in comb[0]:
                idx_click = nums_.index(num)  # index of card to tap
                x, y = (locs_.pop(idx_click))
                nums_.pop(idx_click)
                pag.click(grab_bbox[0] + x, grab_bbox[1] + grab_bbox[3] - 50)  # tap card
            locs = locs[~idx]  # remove cards at the bottom row
            nums = nums[~idx]  
            if len(locs) > 0:
                time.sleep(0.085)
        time.sleep(0.36)


if __name__ == '__main__':
    main()

結果

Python便利

2
3
3

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
2
3