WindBotをコマンドラインから起動

今日は半日 「WindBot」のソースを読んで、半日「WindBot」の起動に苦しんだ。

WindBotの概要

C#

開発言語はC#

どこからインクルードしてきた関数かわかりにくい点(これはもうC共通だが。。。)を除けば、非常に読みやすい言語。

ただちょっと過剰に継承・委譲し過ぎな感じはする

ADSとの関係性

UDPで双方向通信をしていて(よく読んだらTCPだったけど、本体はUDPだった気がするしもうわからん)、パケット情報をもとにお互い(ADSとWindBot)のプロセスが内部でデュエルの処理(カードの移動、LPの増減etc...)を行っている。

エントリポイント

Program.cs
そんなに大きなプロジェクトでもないので読みたいところから読んでも追えると思う。

大まかな仕組み

予めExecutorにアクション(summon, activate, etc...)とその発動条件(bool関数)を登録してコンパイルしておく。

受け取ったパケット情報をもとにPhaseやChainを進め、そのたびにExecutors(Listオブジェクト)をiterateして、発動条件が真を返したらその処理が行い、パケットを送信する。

WindBotの起動

起動に必要な引数たち

ADS/gframe/windbot.cppより(リポジトリ

namespace ygo {

#if defined(_WIN32) || defined(__ANDROID__)
bool WindBot::Launch(int port, const std::wstring& pass, bool chat, int hand) const {
#else
pid_t WindBot::Launch(int port, const std::wstring& pass, bool chat, int hand) const {
#endif
#ifdef _WIN32
	auto args = fmt::format(
		L"./WindBot/WindBot.exe HostInfo=\"{}\" Deck=\"{}\" Port={} Version={} name=\"[AI] {}\" Chat={} {}",
		pass,
		deck,
		port,
		version,
		name,
		chat,
		hand ? fmt::format(L"Hand={}", hand) : L"");

	STARTUPINFO si = {};
	PROCESS_INFORMATION pi = {};
	si.cb = sizeof(si);
	si.dwFlags = STARTF_USESHOWWINDOW;
	si.wShowWindow = SW_HIDE;
	if (CreateProcess(NULL, (TCHAR*)Utils::ToPathString(args).data(), NULL, NULL, FALSE, 0, NULL, executablePath.data(), &si, &pi)) {
		CloseHandle(pi.hProcess);
		CloseHandle(pi.hThread);
		return true;
	}
	return false;
...

ADS自身がコマンドでコールしているので使えそう。

引数がわからない

HostInfoVersionがわからな~い。

からADSをデバッグして引数を抜き取る。

なぜか上手くいかないビルド

過去の自分にすがってもなかなか上手くいかない。

最終的にリポジトリからクローンするところからやり直した。
ついでに記事も編集した。

無駄な数時間

VS2019でデバッグすればいいのにprintf()で出力しようとして、しかも文字化けして上手くいかない落とし穴。

デバッグ実行

例として、オルターガイストを起動するには

  • HostInfo="" (まさかの空文字列)
  • Deck="Altergeist"
  • Port=7911
  • Version=590188
  • Name="AI"
  • Chat=False
  • Hand=0

の引数でWindBotを起動すればよい。

無事ホスト側のADSに「ピンポーン」とAIが入ってきて、めでたしめでたし。

Versionの謎

windbot.cppのどこを探してもversionが見当たらない。
ヘッダを見るとどうやらWindBotクラスのインスタンス変数だったので、VSCodebot.versionを検索したら見事ヒット。

// gframe/game.cpp line 2017
bot.version = CLIENT_VERSION;

マクロの展開先を調べることで無事Versionを得られたとさ。めでたしめでたし。

WindBotの活用法

遊戯王システムのプログラミングをしなければならないと思い、個人の限界を感じてプロジェクトをなかったことにしようと思った所、以前途中でやめたWindBotのソース解析を思い出した。

要は、各カードに対するbool判定を学習可能な関数で置き換えれば良いので、私の仕事はAIの脳みそを作るだけになった。やったね。

既存Botの問題点

変化しない条件分岐

状況が変わろうとも、何回対戦しようとも分岐条件が変わらない。

そりゃ人間が勝つに決まってる。

決まったカードしか扱えない

何度も対戦したらデッキ構成がバレて、駆け引きが減少する。

デッキの動的な変化にも対応できる汎用AIを作る予定。

おわりに

強化学習の基本は、

  • エージェント
  • 環境
  • アクション
  • 報酬

の4つ。

報酬を上手く設計すれば、学習するはず!

という感じで頑張って組み立てていきますよ。