Bot

来自Botzone Wiki
跳转至: 导航搜索

何为Bot

Bot是Botzone上用户提交的程序,具有一定的人工智能,可以根据已有的游戏规则跟其他的Bot或人类玩家进行对抗。

支持的语言

Bot可以用以下语言编写:

  • C/C++(平台上编译时会定义 _BOTZONE_ONLINE 宏)
  • Java
  • JavaScript
  • C# (Mono)
  • python2
  • python3
  • Pascal

提供的运行库

交互

Bot的每次生命周期均为一次输入、一次输出,每次输入会包括该Bot以往跟平台的所有交互内容。交互格式为单行JSON简化交互

因此,Bot的程序运行流程应当是:

  • 启动程序
  • 从平台获取以往的交互内容和最新输入
  • 根据获得的交互内容(request + response)进行计算
    • 根据以往自己的输入(request)输出(response)恢复局面到最新状态
    • 根据本次输入(request)给出本次的决策输出
  • 输出结果以及保存信息
  • 关闭程序

资源限制

如果没有特别指出,每次运行,平台都要求程序在 1秒 内结束、使用的内存在 256 MB 内。

由于不同语言运行效率有别,我们对不同语言的时限也有不同的调整。

  • C/C++:1倍
  • Java:3倍
  • C#:6倍
  • JavaScript:2倍
  • python:3倍
  • Pascal:1倍

交互格式

为了照顾初学者,交互形式有两种:JSON交互和简化交互。

提示:为了限制对局 Log 的大小,data、globaldata 域作为对局的中间变量,在对局结束后将不会被存入 Log 中。

如果希望能进行调试,请使用 debug 域,该域会在对局结束后仍保留在 Log 中。

JSON交互

使用这种交互,可能需要在自己的程序中增加JSON处理相关的库,具体请参见下方样例程序的说明。

Bot 得到的输入

 {
 	"requests" : [
 		"Judge request in Turn 1", // 第 1 回合 Bot 从平台获取的信息(request),具体格式依游戏而定
 		"Judge request in Turn 2", // 第 2 回合 Bot 从平台获取的信息(request),具体格式依游戏而定
 		...
 	],
 	"responses" : [
 		"Bot response in Turn 1", // 第 1 回合 Bot 输出的信息(response),具体格式依游戏而定
 		"Bot response in Turn 2", // 第 2 回合 Bot 输出的信息(response),具体格式依游戏而定
 		...
 	],
 	"data" : "saved data", // 上回合 Bot 保存的信息,最大长度为100KB【注意不会保留在 Log 中】
 	"globaldata" : "globally saved data", // 来自上次对局的、Bot 全局保存的信息,最大长度为100KB【注意不会保留在 Log 中】
 	"time_limit" : "", // 时间限制
 	"memory_limit" : "" // 内存限制
 }

Bot 应该给出的输出

 {
 	"response" : "response msg", // Bot 此回合的输出信息(response)
 	"debug" : "debug info", // 调试信息,将被写入log,最大长度为1KB
 	"data" : "saved data" // Bot 此回合的保存信息,将在下回合输入【注意不会保留在 Log 中】
 	"globaldata" : "globally saved data" // Bot 的全局保存信息,将会在下回合输入,对局结束后也会保留,下次对局可以继续利用【注意不会保留在 Log 中】
 }

简化交互

使用这种交互,只需使用标准输入输出按行操作即可。

Bot 得到的输入

  1. 你的 Bot 首先会收到一行,其中只有一个数字 n,表示目前是第 n 回合(从 1 开始)。
  2. 接下来,是 2 * n - 1 条信息,这些信息由 Bot 从平台获取的信息(request)与 Bot 以前每个回合输出的信息(response)交替组成。
    • 从 1 开始计数,(1 <= i < n)
      • 第 2 * i - 1 条信息为第 i 回合 Bot 从平台获取的信息(request),共 n - 1 条
      • 第 2 * i 条信息为 Bot 在第 i 回合输出的信息(response),共 n - 1 条
      • 最后一条,即第 2 * n - 1 条信息,为当前回合 Bot 从平台获取的新信息(request)
    • 每条信息可能是 1 行,也可能是多行,具体格式依游戏而定。
    • 你的 Bot 需要根据以上信息,推演出当前局面,并给出当前局面下的最好决策。
  3. 接下来是data一行 Bot 上回合保存的信息,最大长度为100KB【注意不会保留在 Log 中】。
  4. 接下来是globaldata一行或多行 Bot 上回合或上次对局保存的全局信息,最大长度为100KB【注意不会保留在 Log 中】。
    • 可以认为 data 行之后的所有内容都是 globaldata,直到文件结尾。

样例输入

3
第一回合游戏信息(request),即 Bot 当时得到的输入
第一回合 Bot 的输出(response)
第二回合游戏信息
第二回合 Bot 的输出
第三回合游戏信息
Bot 上回合保存了这句话作为data!
Bot 上次运行程序保存了这句话作为globaldata!

Bot 应该给出的输出

你的 Bot 应当输出四段数据,以换行符隔开。

  1. 首先是本回合你的 Bot 做出的决策,请按照游戏要求输出。一定只占一行。
  2. 接下来是debug,一行用于回放时候进行调试的信息,最大长度为1KB【注意会保留在 Log 中】。
  3. 接下来是data,一行 Bot 本回合想保存的信息,将在下回合输入,最大长度为100KB【注意不会保留在 Log 中】。
  4. 接下来是globaldata,一行或多行 Bot 想保存的全局信息,将会在下回合输入,对局结束后也会保留,最大长度为100KB【注意不会保留在 Log 中】。

样例输出

本回合 Bot 的输出
Bot 这回合想保存这句话作为debug,到时候回放看!
Bot 这回合保存了这句话作为data,下回合想用!
Bot 这次运行程序保存了这句话作为globaldata,以后想用!

JSON交互的样例程序

以下给出C++、C#、Java和JavaScript的JSON交互样例程序:

C++

本地编译的方式请查看 JSONCPP

 #include <iostream>
 #include <string>
 #include <sstream>
 #include "jsoncpp/json.h" // C++编译时默认包含此库
 
 using namespace std;
 
 int main()
 {
 	// 读入JSON
 	string str;
 	getline(cin, str);
 	Json::Reader reader;
 	Json::Value input;
 	reader.parse(str, input);
 
 	// 分析自己收到的输入和自己过往的输出,并恢复状态
 	string data = input["data"].asString(); // 该对局中,以前该Bot运行时存储的信息
 	int turnID = input["responses"].size();
 	for (int i = 0; i < turnID; i++)
 	{
 		istringstream in(input["requests"][i].asString()),
 			out(input["responses"][i].asString());
 
 		// 根据这些输入输出逐渐恢复状态到当前回合
 	}
 
 	// 看看自己本回合输入
 	istringstream in(input["requests"][turnID].asString());
 
 	// 做出决策存为myAction
 
 	// 输出决策JSON
 	Json::Value ret;
 	ret["response"] = myAction;
 	ret["data"] = myData; // 可以存储一些前述的信息,在整个对局中使用
 	Json::FastWriter writer;
 	cout << writer.write(ret) << endl;
 	return 0;
 }

C#

本地编译的方式请查看 Newtonsoft.Json

using System;
using Newtonsoft.Json;
 
struct InputData
{
	public dynamic[] // 类型请根据具体游戏决定
		requests, // 从平台获取的信息集合
		responses; // 自己曾经输出的信息集合
	public string
		data, // 该对局中,上回合该Bot运行时存储的信息
		globaldata; // 来自上次对局的、Bot全局保存的信息
	public int time_limit, memory_limit;
}
 
struct OutputData
{
	public dynamic response; // 此回合的输出信息
	public string
		debug, // 调试信息,将被写入log
		data, // 此回合的保存信息,将在下回合输入
		globaldata; // Bot的全局保存信息,将会在下回合输入,对局结束后也会保留,下次对局可以继续利用
}
 
class Program
{
	static void Main(string[] args) // 请保证文件中只有一个类定义了Main方法
	{
		// 将输入解析为结构体
		var input = JsonConvert.DeserializeObject<InputData>(
			Console.ReadLine()
		);
 
		// 分析自己收到的输入和自己过往的输出,并恢复状态
		int turnID = input.responses.Length;
		for (int i = 0; i < turnID; i++)
		{
			dynamic inputOfThatTurn = input.requests[i], // 当时的输入
 				outputOfThatTurn = input.responses[i]; // 当时的输出
 
			// 根据这些输入输出逐渐恢复状态到当前回合
		}
 
		// 看看自己本回合输入
		dynamic inputOfCurrentTurn = input.requests[turnID];
 
		// 做出决策存为myAction
 
		// 输出决策JSON
		OutputData output = new OutputData();
		output.response = myAction;
		output.debug = "hhh";
		Console.WriteLine(
			JsonConvert.SerializeObject(output)
		);
	}
}

JavaScript

 // 初始化标准输入流
 process.stdin.resume();
 process.stdin.setEncoding('utf8');
 
 var fullInput = "";
 
 // 收到一个输入片段
 process.stdin.on('data', function (chunk) {
     fullInput += chunk;
 });
 
 // 输入全部结束
 process.stdin.on('end', function () {
 
     // 解析读入的JSON
     var input = JSON.parse(fullInput);
     var data = input.data; // 该对局中,以前该Bot运行时存储的信息
 
     // 分析自己收到的输入和自己过往的输出,并恢复状态
     for (var i = 0; i < input.responses.length; i++) {
         var myInput = input.requests[i], myOutput = input.responses[i];
         // 根据这些输入输出逐渐恢复状态到当前回合
     }
 
     // 看看自己本回合输入
     var currInput = input.requests[input.requests.length - 1];
 
     // 作出决策并输出
     console.log(JSON.stringify({
         response: myAction,
         data: myData // 可以存储一些前述的信息,在整个对局中使用
     }));
 });

Java

本地编译的方式请查看 JSON.simple

import java.util.*;
import org.json.simple.JSONValue; // Java 库中自动包含此库
 
class Main { // 注意!!类名""必须""为 Main,且不要有package语句,但上传的 java 代码文件名可以任意
	static class SomeClass {
		// 如果要定义类,请使用 static inner class
	}
	public static void main(String[] args) {
		String input = new Scanner(System.in).nextLine();
		Map<String, List> inputJSON = (Map) JSONValue.parse(input);
		// 下面的 TYPE 为单条 response / request 类型,有较大可能为 Map<String, Long> 或 String
		List<TYPE> requests = inputJSON.get("requests");
		List<TYPE> responses = inputJSON.get("responses");
		for (TYPE rec : requests) {
			// 处理一下
		}
		for (TYPE rec : responses) {
			// 再处理一下
		}
		// 这边运算得出一个 output,注意类型也为 TYPE
		Map<String, TYPE> outputJSON = new HashMap();
		outputJSON.put("response", output);
		System.out.print(JSONValue.toJSONString(outputJSON));
	}
}