8
9

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 3 years have passed since last update.

クラッシュ・ロワイヤル API を使って Google スプレッドシートへクラン対戦の戦績を記録する

Last updated at Posted at 2019-01-05

はじめに

エンジニアの @Yasuhisa です。

私はスマホのゲームアプリでよく遊びます。

最近は主に Supercell 社の CLASH ROYALE(クラロワ)BRAWL STARS(ブロスタ) で遊んでいます。どちらもスマホゲームの手軽さがあり、ルールのシンプルさと競技性の高さを兼ね備えているため、飽きずに続いています。

この記事では CLASH ROYALE(クラロワ) の公開 API Clash Royale API からクラン対戦結果を取得して、Google スプレッドシートに戦績を記録する方法を紹介します。

注)この記事の執筆時点(2019/01/05)に動作確認をしたため、API のアップデート次第では動作しなくなる可能性があります。詳細は文末の API リファレンスを参考にしてください。

クラッシュ・ロワイヤルおよびクラン対戦について

クラッシュ・ロワイヤル(通称クラロワ)は 2016年 1月4日 に Supercell 社からリリースされ、2018年 4月25日 にクラン対戦が追加されました。2018年からはプロリーグも活発で、YouTuber による生放送なども頻繁に行われています。

クラロワ API をどう使うのか

本題の Clash Royale API の使い方については、クラッシュロワイアル(ClashRoyale)のAPIが解放されたらしいので試してみる(その①) - Qiita の記事でわかりやすく紹介されています。

今回のスクリプトを作ったきっかけは、クラン対戦の戦績の閲覧に不便さを感じたからです。クラン対戦の戦績はゲーム内の ソーシャル > クラン名 > 過去の対戦 の順にタップして見ることができます。しかしながら、**直近の5戦しか記録が確認できない(クラロワ API で 5 以上の Limit を指定しても見れない)**という問題があるため、私とクランメンバーの友人でスプレッドシートに戦績を記録するようになりました。

01.png

筆者は以前からクラロワ API が試してみたかったので、年末年始の暇な時間に自動化しようと考えていました。試してみた結果、クラロワ API は実行元の IP アドレスをあらかじめ登録しておく必要があったので、Google Apps Script の トリガー などで完結することができませんでした。そのため、Python スクリプトをローカル端末から実行する方法で現在は記録しています。

やりたいこと

手入力している Google スプレッドシートのクラン対戦戦績を Python スクリプトで一括登録します。

02.png

スプレッドシートへの煩わしい手入力やスマートフォン・タブレットでのクラン対戦戦績の照会数・記録ミスが減り、しっかりと記録しつつも遊べる時間が増えせます。

03.png

事前準備

後述の Python コードを実行するには以下の準備が必要です。

  • 集計対象スプレッドシートの作成
    • スプレッドシート ID
    • 集計・記録対象セルの作成
  • Clash Royale API キーの取得、およびグローバル変数 TOKEN へセット
  • Google Spreadsheet API の有効化
  • Google Spreadsheet API 認証情報を実行環境のルートディレクトリに配置
    • token.json
    • credentials.json

Python コード

Gist でも公開しています。

import requests
import json
from googleapiclient.discovery import build
from httplib2 import Http
from oauth2client import file, client, tools

TOKEN = '{Your Clash Royale API Key}' # クラロワ API キー
URL = 'https://api.clashroyale.com/v1'

SCOPES = 'https://www.googleapis.com/auth/spreadsheets' # read/write
SPREADSHEET_ID = '{Your Spreadsheet ID}' # スプレッドシートの ID
DEFAULT_RANGE = '{Your Spreadsheet target rect}' # セルの集計対象範囲(「:」前後の矩形選択)
LAST_LOGGED_CELL = '{Your Spreadsheet CreatedDate cell identity}' # 最終更新日時セル
VALUE_INPUT_OPTION = 'RAW' # RAW 固定

NAME_COL = 0 # スプレッドシート A 列
WIN_COL = 1 # スプレッドシート B 列
LOSE_COL = 2 # スプレッドシート C 列

sheet = None

def get_current_clan_battle_results():
    """クラロワ API クラン対戦データを取得

    実行するためには事前にクラロワ API の API キーを `TOKEN` にセットする必要があります。

    Returns:
        List -- クラン対戦結果

    See Also:
        My Keys -- https://developer.clashroyale.com/#/account
        GET /clans/{clanTag}/warlog -- https://developer.clashroyale.com/#/documentation
    """

    endpoint = URL + "/clans/{your_clan_tag(need '#' to encode URL string '%23'}/warlog"

    headers = {
        "content-type": "application/json; charset=utf-8",
        "cache-control": "max-age=60",
        "authorization": "Bearer %s" % TOKEN
    }

    response = requests.get(endpoint, headers=headers)
    results = response.json()

    return results

def get_spreadsheet():
    """Google スプレッドシートを取得

    実行するためには事前に実行環境のルートディレクトリに「token.json」、および「credentials.json」を配置する必要があります。

    Raises:
        Exception -- スプレッドシートが取得できない場合

    Returns:
        Spreadsheet -- https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets?hl=ja#Spreadsheet
    
    See Also:
        Python Quickstart -- https://developers.google.com/sheets/api/quickstart/python
    """

    store = file.Storage('token.json')
    creds = store.get()

    if not creds or creds.invalid:
        flow = client.flow_from_clientsecrets('credentials.json', SCOPES)
        creds = tools.run_flow(flow, store)
    
    service = build('sheets', 'v4', http=creds.authorize(Http()))
    sheet = service.spreadsheets()

    if not sheet:
        raise Exception('スプレッドシートが正常に取得できませんでした。')

    return sheet

def get_sheetvalues_by_range(range):
    """スプレッドシートの指定した範囲を取得

    Parameters:
        range {string} -- セルの取得範囲。指定のセル番号(ex, A1)もしくは、「:」区切りのセル範囲(ex, A1:B2、矩形選択)を指定する。

    Raises:
        ValueError -- range の指定がない場合

    Returns:
        spreadsheets.values -- https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets.values?hl=ja
    """

    if not range:
        raise ValueError('範囲を設定してください')
    
    return sheet.values().get(spreadsheetId=SPREADSHEET_ID, range=range).execute()

def update_area(batch_update_values_request):
    """スプレッドシートの範囲を更新する
    
    Arguments:
        batch_update_values_request {BatchUpdateValuesRequest} -- https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets.values/batchUpdate?hl=ja#request-body
    
    Raises:
        ValueError -- batch_update_values_request の指定がない場合
    
    See Also:
        POST spreadsheets.values.batchUpdate -- https://developers.google.com/sheets/guides/values?hl=ja#_8
    """

    if not batch_update_values_request:
        raise ValueError('batch_update_values_request を指定してください')

    body = {
        'valueInputOption': VALUE_INPUT_OPTION,
        'data': batch_update_values_request
    }

    sheet.values().batchUpdate(spreadsheetId=SPREADSHEET_ID, body=body).execute()

def update_battle_resutls():
    """
    クラロワ API のクラン対戦取得結果でスプレッドシートの最終更新日時より新しい記録があれば、スプレッドシートの戦績を更新する。
    """

    global sheet
    sheet = get_spreadsheet()

    # スプレッドシート情報を取得
    last_logged_cell = get_sheetvalues_by_range(range=LAST_LOGGED_CELL)
    # 最終記録時間を取得
    last_logged_date = last_logged_cell['values'][0][0]

    # クラン対戦結果を取得
    battle_results = get_current_clan_battle_results()
    items = battle_results['items']

    # クラン対戦結果を createdDate(対戦履歴)順に昇順ソート
    sorted_items = sorted(items, key=lambda items: items['createdDate'])

    for item in sorted_items:
        created_date = item['createdDate']

        # クラロワ API で取得した最終更新日時(createdDate)がスプレッドシートの記録以前のものであったら処理しない
        if created_date <= last_logged_date:
            continue

        # クラロワ API クラン対戦参加者情報
        participants = item['participants']
        # スプレッドシートセル情報
        values = get_sheetvalues_by_range(range=DEFAULT_RANGE)['values']

        for participant in participants:
            participant_name = participant['name']

            for value in values:
                cell_name = value[NAME_COL]

                # クラン対戦参加者名とスプレッドシートの名前列が一致するかどうか
                if participant_name == cell_name:
                    win_count = participant['wins']
                    # 対戦結果勝ち数を追加
                    value[WIN_COL] = str(int(value[WIN_COL]) + win_count)
                    # 対戦結果負け数を追加 (試合数 - 勝数)
                    value[LOSE_COL] = str(int(value[LOSE_COL]) + participant['battlesPlayed'] - win_count)

        # スプレッドシート API の `BatchUpdateValuesRequest` オブジェクト
        batch_update_values_request = [
            {
                'range': LAST_LOGGED_CELL,
                'values': [[created_date]]
            },
            {
                'range': DEFAULT_RANGE,
                'values': values
            },
        ]

        # LAST_LOGGED_CELL の最終更新日時(createdDate)、クラン対戦結果を更新
        update_area(batch_update_values_request)

if __name__ == '__main__':
    update_battle_resutls()

所属クランの宣伝

私の所属しているクランは少人数で、コアメンバーの高い勝率が特徴です。

クランのルールでは クラン対戦本戦でカードレベルが 11 以上(ウルトラレアは 10 以上)でなければ許可なく参加しない となっているため、対戦の参加人数が 10 人に満たないことが多々あります。

平均のカードレベルが 11 以上(理想は 12 以上)で、少数精鋭のクランに入ってみたいという方がいましたら、是非 ツワキノクラロワ部 へ加入申請をお願いします。

おわりに

クラロワのフレンド登録なども歓迎しますので、何か用があれば筆者の Twitter へ気軽に連絡をください。

またクラロワ API を使う機会があれば記事にしていきたいです。

参考にしたドキュメント・記事

8
9
1

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
8
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?