このドキュメントでは、プロトコルの実装について説明します。
ここで指すプロトコルとは、技術レイヤーのプロトコルではなく、人狼知能のエージェントとサーバ間のやり取りの際の文字列としてのプロトコルです。
また、従来の人狼知能対戦接続システムでは、エージェント側がサーバとして待ち受けするため、ゲームマスタ側をサーバと呼ばずに対戦接続システムと表記していましたが、WebSocketを使用したこのシステムでは、ゲームマスタ側がサーバとして待ち受けをするため、ゲームマスタ側をサーバ、エージェント側をクライアントと表記します。
サーバがエージェントに送るメッセージは、すべてJSON形式の文字列です。
それに対して、エージェントがサーバに送るメッセージは、すべて生の文字列です。
また、このドキュメントではサーバがエージェントに送るメッセージをリクエスト (パケット)、エージェントがサーバに送るメッセージをレスポンスと表記します。
- 名前リクエスト
NAME - ゲーム開始リクエスト
INITIALIZE - 昼開始リクエスト
DAILY_INITIALIZE - 囁きリクエスト
WHISPER - トークリクエスト
TALK - 昼終了リクエスト
DAILY_FINISH - 占いリクエスト
DIVINE - 護衛リクエスト
GUARD - 投票リクエスト
VOTE - 襲撃リクエスト
ATTACK - ゲーム終了リクエスト
FINISH - トークフェーズ開始リクエスト
TALK_PHASE_START(グループチャット方式のみ) - トークフェーズ終了リクエスト
TALK_PHASE_END(グループチャット方式のみ) - トークブロードキャストリクエスト
TALK_BROADCAST(グループチャット方式のみ) - 囁きフェーズ開始リクエスト
WHISPER_PHASE_START(グループチャット方式のみ) - 囁きフェーズ終了リクエスト
WHISPER_PHASE_END(グループチャット方式のみ) - 囁きブロードキャストリクエスト
WHISPER_BROADCAST(グループチャット方式のみ)
リクエストの種類によって、リクエストに含まれる情報が異なり、レスポンスを返す必要があるかどうかも異なります。
詳細な実装については、request.goとpacket.goを参照してください。
レスポンスは、トークや囁きリクエストに対してエージェントが発する自然言語を返す場合 (例: こんにちは) と、投票や占いリクエストなどに対して対象のエージェントの名前 (例: Agent[01]) を返す2種類があります。
パケットの構造体.
- request (Request): リクエストの種類.
- info (Info | None): ゲームの設定を示す情報.
- setting (Setting | None): ゲームの設定情報.
- talk_history (list[Talk] | None): トークの履歴を示す情報.
- whisper_history (list[Talk] | None): 囁きの履歴を示す情報.
- new_talk (Talk | None): グループチャット方式でブロードキャストされた新しいトーク. (リクエストの種類が TALK_BROADCAST の場合のみ).
- new_whisper (Talk | None): グループチャット方式でブロードキャストされた新しい囁き. (リクエストの種類が WHISPER_BROADCAST の場合のみ).
リクエストの種類ごとの詳細な説明を以下に示します。
名前リクエストは、エージェントがサーバに接続した際に送信されるリクエストです。
エージェントは、このリクエストを受信した際に、自身の名前を返す必要があります。
複数エージェントを接続する場合、後ろにユニークな数字をつける必要があります。
例えば、 kanolab という名前を返す場合、 kanolab1, kanolab2 などとします。
後ろの数字を除いた名前は、エージェントのチーム名として扱われます。
Important
ここで指す名前は、サーバ側でのマッチングに使用されるものであり、ゲーム内でのエージェントの名前とは異なります。
ゲーム開始リクエストは、ゲームが開始された際に送信されるリクエストです。
エージェントは、このリクエストを受信した際に、何も返す必要はありません。
昼開始リクエストは、昼が開始された際、つまり次の日が始まった際に送信されるリクエストです。
エージェントは、このリクエストを受信した際に、何も返す必要はありません。
囁きリクエストとトークリクエストは、それぞれ囁きとトークが要求された際に送信されるリクエストです。
囁きリクエストについては、人狼の役職が2人以上生存している場合に、人狼のみに送信されます。
エージェントは、このリクエストを受信した際に、囁きやトークの自然言語の文字列を返す必要があります。
サーバ側が送信する履歴は、前回のエージェントに対する送信の差分のみであり、全ての履歴を送信するわけではありません。
昼終了リクエストは、昼が終了された際、つまりその日の夜が始まった際に送信されるリクエストです。
エージェントは、このリクエストを受信した際に、何も返す必要はありません。
直前までの会話の履歴が送信されます。
ゲーム全体の人狼の役職が2人未満で囁きフェーズが存在しない場合においても、人狼の役職に対しては、囁きの履歴が送信されます。
占いリクエストは、占いが要求された際に送信されるリクエストです。
占い師のみに送信されます。
エージェントは、このリクエストを受信した際に、占いの対象となるエージェントの名前を返す必要があります。
護衛リクエストは、護衛が要求された際に送信されるリクエストです。
騎士のみに送信されます。
エージェントは、このリクエストを受信した際に、護衛の対象となるエージェントの名前を返す必要があります。
投票リクエストは、追放するエージェントを投票する際に送信されるリクエストです。
エージェントは、このリクエストを受信した際に、投票の対象となるエージェントの名前を返す必要があります。
襲撃リクエストは、襲撃するエージェントを投票する際に送信されるリクエストです。
人狼のみに送信されます。
エージェントは、このリクエストを受信した際に、襲撃の対象となるエージェントの名前を返す必要があります。
直前までの会話の履歴が送信されます。
ゲーム全体の人狼の役職が2人未満で囁きフェーズが存在しない場合においても、人狼の役職に対しては、囁きの履歴が送信されます。
ゲーム終了リクエストは、ゲームが終了された際に送信されるリクエストです。
エージェントは、このリクエストを受信した際に、何も返す必要はありません。
各キーについては、ゲーム開始リクエストと同様です。ゲーム開始リクエストとは異なり、 Setting は送信されません。
なお、Info の role_map は自分以外も含めたすべてのエージェントの役職が含まれます。
グループチャット方式でトークフェーズが開始された際に送信されるリクエストです。
エージェントは、このリクエストを受信した際に、何も返す必要はありません。
このリクエストを受信した後、エージェントはサーバからの要求を待つことなく、自由にトークを送信できます。
グループチャット方式でトークフェーズが終了した際に送信されるリクエストです。
エージェントは、このリクエストを受信した際に、何も返す必要はありません。
このリクエストを受信した後、エージェントはトークの送信を停止する必要があります。
グループチャット方式でエージェントがトークを送信した際に、すべての参加エージェントに対してブロードキャストされるリクエストです。
エージェントは、このリクエストを受信した際に、何も返す必要はありません。
パケットの new_talk フィールドに、新しく送信されたトークが含まれます。
グループチャット方式で囁きフェーズが開始された際に送信されるリクエストです。
トークフェーズ開始リクエストと同様の動作です。人狼エージェントのみに送信されます。
グループチャット方式で囁きフェーズが終了した際に送信されるリクエストです。
トークフェーズ終了リクエストと同様の動作です。人狼エージェントのみに送信されます。
グループチャット方式でエージェントが囁きを送信した際に、人狼エージェントに対してブロードキャストされるリクエストです。
エージェントは、このリクエストを受信した際に、何も返す必要はありません。
パケットの new_whisper フィールドに、新しく送信された囁きが含まれます。
パケット内のゲームの現状態を示す情報の構造体.
- game_id (str): ゲームの識別子.
- day (int): 現在の日数.
- agent (str): 自分のエージェントの名前.
- profile (str | None): 自分のエージェントのプロフィール. (リクエストの種類が INITIALIZE の場合のみ). 設定されない場合は None.
- medium_result (Judge | None): 霊能者の結果 (エージェントの役職が霊媒師であるかつ霊能結果が設定されている場合のみ).
- divine_result (Judge | None): 占い師の結果 (エージェントの役職が占い師であるかつ占い結果が設定されている場合のみ).
- executed_agent (str | None): 昨夜の追放結果 (エージェントが追放された場合のみ).
- attacked_agent (str | None): 昨夜の襲撃結果 (エージェントが襲撃された場合のみ).
- vote_list (list[Vote] | None): 投票の結果 (投票結果が公開されている場合のみ).
- attack_vote_list (list[Vote] | None): 襲撃の投票結果 (エージェントの役職が人狼かつ襲撃投票結果が公開されている場合のみ).
- status_map (dict[str, Status]): 各エージェントの生存状態を示すマップ.
- role_map (dict[str, Role]): 各エージェントの役職を示すマップ (自分以外のエージェントの役職は見えません).
- remain_count (int | None): 残りのトークもしくは囁きリクエストを受信する可能性のある最大の回数. (リクエストの種類が TALK | WHISPER の場合のみ).
- remain_length (int | None): 残りのトークもしくは囁きリクエストで消費することのできる文字数. 最低文字数を除く. (リクエストの種類が TALK | WHISPER の場合のみ). 制限がない場合は None.
- remain_skip (int | None): 残りのトークもしくは囁きリクエストでスキップすることのできる回数. (リクエストの種類が TALK | WHISPER の場合のみ).
占い結果や霊能結果などの判定結果を示す情報の構造体.
- day (int): 判定が出た日数.
- agent (str): 判定を出したエージェントの名前.
- target (str): 判定の対象となったエージェントの名前.
- result (Species): 判定結果.
種族を示す列挙型.
- HUMAN (str): 人間.
- WEREWOLF (str): 人狼.
投票の内容を示す情報の構造体.
- day (int): 投票が行われた日数.
- agent (str): 投票を行ったエージェントの名前.
- target (str): 投票の対象となったエージェントの名前.
エージェントの生存状態を示す列挙型.
- ALIVE (str): 生存している.
- DEAD (str): 死亡している.
役職を示す列挙型.
- WEREWOLF (str): 人狼.
- POSSESSED (str): 狂人.
- SEER (str): 占い師.
- BODYGUARD (str): 騎士.
- VILLAGER (str): 村人.
- MEDIUM (str): 霊媒師.
ゲームの設定を示す情報の構造体.
- agent_count (int): ゲームのプレイヤー数.
- max_day (int | None): ゲーム内の最大日数. 制限がない場合は None.
- role_num_map (dict[Role, int]): 各役職の人数を示すマップ.
- vote_visibility (bool): 投票の結果を公開するか.
- talk.max_count.per_agent (int): 1日あたりの1エージェントの最大発言回数.
- talk.max_count.per_day (int): 1日あたりの全体の発言回数.
- talk.max_length.count_in_word (bool | None): 単語数でカウントするか. 設定されない場合は None.
- talk.max_length.count_spaces (bool | None): 文字数カウントの際に空白を含めてカウントするか. 設定されない場合は None.
- talk.max_length.per_talk (int | None): 1回のトークあたりの最大文字数. 制限がない場合は None.
- talk.max_length.mention_length (int | None): 1回のトークあたりのメンションを含む場合の追加文字数. per_talk の制限がない場合は None.
- talk.max_length.per_agent (int | None): 1日あたりの1エージェントの最大文字数. 制限がない場合は None.
- talk.max_length.base_length (int | None): 1日あたりの1エージェントの最大文字数に含まない最低文字数. 制限がない場合は None.
- talk.duration (int | None): グループチャット方式のフェーズ全体の制限時間 (ミリ秒). 設定されていない場合は None.
- talk.max_skip (int): 1日あたりの1エージェントの最大スキップ回数.
- whisper.max_count.per_agent (int): 1日あたりの1エージェントの最大囁き回数.
- whisper.max_count.per_day (int): 1日あたりの全体の囁き回数.
- whisper.max_length.count_in_word (bool | None): 単語数でカウントするか. 設定されない場合は None.
- whisper.max_length.count_spaces (bool | None): 文字数カウントの際に空白を含めてカウントするか. 設定されない場合は None.
- whisper.max_length.per_talk (int | None): 1回のトークあたりの最大文字数. 制限がない場合は None.
- whisper.max_length.mention_length (int | None): 1回のトークあたりのメンションを含む場合の追加文字数. per_talk の制限がない場合は None.
- whisper.max_length.per_agent (int | None): 1日あたりの1エージェントの最大文字数. 制限がない場合は None.
- whisper.max_length.base_length (int | None): 1日あたりの1エージェントの最大文字数に含まない最低文字数. 制限がない場合は None.
- whisper.duration (int | None): グループチャット方式のフェーズ全体の制限時間 (ミリ秒). 設定されていない場合は None.
- whisper.max_skip (int): 1日あたりの1エージェントの最大スキップ回数.
- vote.max_count (int): 1位タイの場合の最大再投票回数.
- vote.allow_self_vote (bool): 自己投票を許可するか.
- attack_vote.max_count (int): 1位タイの場合の最大襲撃再投票回数.
- attack_vote.allow_self_vote (bool): 自己投票を許可するか.
- attack_vote.allow_no_target (bool): 襲撃なしの日を許可するか.
- timeout.action (int): エージェントのアクションのタイムアウト時間 (ミリ秒).
- timeout.response (int): エージェントの生存確認のタイムアウト時間 (ミリ秒).
会話の内容を示す情報の構造体.
- idx (int): 会話のインデックス.
- day (int): 会話が行われた日数.
- turn (int): 会話が行われたターン数.
- agent (str): 会話を行ったエージェントの名前.
- text (str): 会話の内容.
- skip (bool): 会話がスキップであるかどうか.
- over (bool): 会話がオーバーであるかどうか.
- time (int): 会話が行われた時刻 (Unixミリ秒).