はじめに
エンジニアの @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 を指定しても見れない)**という問題があるため、私とクランメンバーの友人でスプレッドシートに戦績を記録するようになりました。
筆者は以前からクラロワ API が試してみたかったので、年末年始の暇な時間に自動化しようと考えていました。試してみた結果、クラロワ API は実行元の IP アドレスをあらかじめ登録しておく必要があったので、Google Apps Script の トリガー などで完結することができませんでした。そのため、Python スクリプトをローカル端末から実行する方法で現在は記録しています。
やりたいこと
手入力している Google スプレッドシートのクラン対戦戦績を Python スクリプトで一括登録します。
スプレッドシートへの煩わしい手入力やスマートフォン・タブレットでのクラン対戦戦績の照会数・記録ミスが減り、しっかりと記録しつつも遊べる時間が増えせます。
事前準備
後述の 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 を使う機会があれば記事にしていきたいです。