裁判

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

裁判是Botzone进行对局评测的后台程序,同时也是每个游戏必不可少的部分。

裁判与Bot一样可以用各种语言编写,主要作用是通过控制器接收各个玩家的输入并根据规则进行判断,然后给出下一回合的指令。

交互

裁判每回合开始时会被运行一次,每次生命周期均为一次输入、一次输出,每次输入会包括裁判和所有玩家以往跟平台的所有交互内容。交互格式为单行JSON

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

  • 启动程序
  • 从平台获取以往的交互内容和上回合玩家输出的response
  • 根据获得的交互内容(自己以前发出的request + 玩家输出的response)进行计算
    • 恢复局面到最新状态
    • 根据玩家的上回合response演算下一局面
      • 如果游戏结束,给出玩家分数
      • 如果游戏继续,则确定哪些玩家应当进行动作,并给这些玩家发送request(只有被发送request的玩家才会启动)
  • 关闭程序

资源限制

Bot#资源限制

交互格式

裁判得到的输入

{
	"log": [
		{
			"memory": 2,
			"output": {
				"command": "request",
				"content": ...,
				"display": ...
			}, // 这里是裁判输出的request的主体
			"time": 2,
			"verdict": "OK"
		}, // 第0、2、4、...项,表示裁判第1、2、3...回合的输出
		{
			"0": {
				"memory": 2,
				"time": 9,
				"verdict": "OK",
				"response": ... // 这里是玩家输出的response的主体
			}
		}, // 第1、3、5、...项,表示玩家们第1、2、3...回合的输出
		...
	],
	"initdata": "" // 初始化数据
}

裁判应该给出的输出

如果游戏继续:

{
	"command": "request",
	"content": {
		"0": ... // 要运行的玩家和给它的request
	},
	"display": ... // 给播放器的信息,可以是JSON对象
}

如果游戏结束:

{
	"command": "finish",
	"content": {
		"0": 1, // 每个玩家的分数
		"1": 2
	},
	"display": ... // 给播放器的信息,可以是JSON对象
}

样例程序

以下给出C++的JSON裁判样例程序:

本地编译的方式请查看 JSONCPP

#include <iostream>
#include <sstream>
#include <string>
#include "jsoncpp/json.h"
using namespace std;


// 注意黑方为0号玩家
int currBotColor; // 正在等待输出结果的BOT
int gridInfo[8][8] = { 0 }; // 先x后y
int blackPieceCount = 2, whitePieceCount = 2;
string blackName = "", whiteName = "";

static bool MoveStep(int &x, int &y, int Direction)
{
	if (Direction == 0 || Direction == 6 || Direction == 7)
		x++;
	if (Direction == 0 || Direction == 1 || Direction == 2)
		y++;
	if (Direction == 2 || Direction == 3 || Direction == 4)
		x--;
	if (Direction == 4 || Direction == 5 || Direction == 6)
		y--;
	if (x < 0 || x > 7 || y < 0 || y > 7)
		return false;
	return true;
}

bool ProcStep(int xPos, int yPos, int color, bool checkOnly = false)
{
	if (xPos == -1)
		return true;
	if (xPos < 0 || xPos > 7 || yPos < 0 || yPos > 7)
		return false;
	int effectivePoints[8][2];
	int dir, x, y, currCount;
	bool isValidMove = false;
	if (gridInfo[xPos][yPos] != 0)
		return false;
	for (dir = 0; dir < 8; dir++)
	{
		x = xPos;
		y = yPos;
		currCount = 0;
		while (1)
		{
			if (!MoveStep(x, y, dir))
			{
				currCount = 0;
				break;
			}
			if (gridInfo[x][y] == -color)
			{
				currCount++;
				effectivePoints[currCount][0] = x;
				effectivePoints[currCount][1] = y;
			}
			else if (gridInfo[x][y] == 0)
			{
				currCount = 0;
				break;
			}
			else
			{
				break;
			}
		}
		if (currCount != 0)
		{
			isValidMove = true;
			if (checkOnly)
				return true;
			if (color == 1)
			{
				blackPieceCount += currCount;
				whitePieceCount -= currCount;
			}
			else
			{
				whitePieceCount += currCount;
				blackPieceCount -= currCount;
			}
			while (currCount > 0)
			{
				x = effectivePoints[currCount][0];
				y = effectivePoints[currCount][1];
				gridInfo[x][y] *= -1;
				currCount--;
			}
		}
	}
	if (isValidMove)
	{
		gridInfo[xPos][yPos] = color;
		if (color == 1)
			blackPieceCount++;
		else
			whitePieceCount++;
		return true;
	}
	else
		return false;
}

bool CheckIfHasValidMove(int color)
{
	int x, y;
	for (y = 0; y < 8; y++)
		for (x = 0; x < 8; x++)
			if (ProcStep(x, y, color, true))
				return true;
	return false;
}

int main()
{
	string str;
	getline(cin, str);
	Json::Reader reader;
	Json::Value input, output;
	reader.parse(str, input);
	input = input["log"];


	gridInfo[3][4] = gridInfo[4][3] = 1;  //|白|黑|
	gridInfo[3][3] = gridInfo[4][4] = -1; //|黑|白|
	currBotColor = 1; // 先手为黑
	if (input.size() == 0)
	{
		output["display"] = "";
		output["command"] = "request";
		output["content"]["0"]["x"] = -1;
		output["content"]["0"]["y"] = -1;
	}
	else
	{
		for (int i = 1; i < input.size(); i += 2)
		{
			bool isLast = i == input.size() - 1;
			Json::Value content;
			Json::Value display;
			if (currBotColor == 1) // 0号玩家 / 黑方
			{
				Json::Value answer = input[i]["0"]["response"].isNull() ? input[i]["0"]["content"] : input[i]["0"]["response"];
				if (((answer.isString() &&
					reader.parse(answer.asString(), content)) ||
					(answer.isObject() &&
						(content = answer, true))) &&
					content["x"].isInt() && content["y"].isInt()) // 保证输入格式正确
				{
					int currX = content["x"].asInt();
					int currY = content["y"].asInt();
					if (currX == -1 && isLast) // bot选择PASS
					{
						if (!CheckIfHasValidMove(currBotColor)) // 他应该PASS
						{
							output["display"]["x"] = -1;
							output["display"]["y"] = -1;
							output["command"] = "request";
							output["content"]["1"]["x"] = -1;
							output["content"]["1"]["y"] = -1;
						}
						else // 他不应该PASS
						{
							// Todo: Bug here--
							output["display"]["err"] = "HE_THOUGHT_THAT_HE_COULDNOT_MOVE_BUT_IN_FACT_HE_CAN";
							output["display"]["winner"] = 1;
							output["command"] = "finish"; // 判输
							output["content"]["0"] = 0;
							output["content"]["1"] = 2;
						}
					}
					else if (!ProcStep(currX, currY, currBotColor) && isLast) // 不合法棋步!
					{
						output["display"]["err"] = "INVALIDMOVE";
						output["display"]["winner"] = 1;
						output["command"] = "finish"; // 判输
						output["content"]["0"] = 0;
						output["content"]["1"] = 2;
					}
					else if (isLast) // 正常棋步
					{
						output["display"]["x"] = currX;
						output["display"]["y"] = currY;
						if (!CheckIfHasValidMove(currBotColor) && !CheckIfHasValidMove(-currBotColor)) // 游戏结束
						{
							if (blackPieceCount > whitePieceCount)
							{
								output["display"]["winner"] = 0;
								output["command"] = "finish";
								output["content"]["0"] = 2;
								output["content"]["1"] = 0;
							}
							else if (blackPieceCount < whitePieceCount)
							{
								output["display"]["winner"] = 1;
								output["command"] = "finish";
								output["content"]["0"] = 0;
								output["content"]["1"] = 2;
							}
							else
							{
								output["command"] = "finish";
								output["content"]["0"] = 1;
								output["content"]["1"] = 1;
							}
						}
						else
						{

							output["display"]["x"] = currX;
							output["display"]["y"] = currY;
							output["command"] = "request";
							output["content"]["1"]["x"] = currX;
							output["content"]["1"]["y"] = currY;
						}
					}
				}
				else if (isLast)
				{
					output["display"]["err"] = "INVALIDMOVE";
					output["display"]["winner"] = 1;
					output["command"] = "finish"; // 判输
					output["content"]["0"] = 0;
					output["content"]["1"] = 2;
				}
			}
			else
			{
				Json::Value answer = input[i]["1"]["response"].isNull() ? input[i]["1"]["content"] : input[i]["1"]["response"];
				if (((answer.isString() &&
					reader.parse(answer.asString(), content)) ||
					(answer.isObject() &&
						(content = answer, true))) &&
					content["x"].isInt() && content["y"].isInt()) // 保证输入格式正确
				{
					int currX = content["x"].asInt();
					int currY = content["y"].asInt();
					if (currX == -1 && isLast) // bot选择PASS
					{
						if (!CheckIfHasValidMove(currBotColor)) // 他应该PASS
						{
							output["display"]["x"] = -1;
							output["display"]["y"] = -1;
							output["command"] = "request";
							output["content"]["0"]["x"] = -1;
							output["content"]["0"]["y"] = -1;
						}
						else // 他不应该PASS
						{
							output["display"]["err"] = "HE_THOUGHT_THAT_HE_COULDNOT_MOVE_BUT_IN_FACT_HE_CAN";
							output["display"]["winner"] = 0;
							output["command"] = "finish"; // 判输
							output["content"]["0"] = 2;
							output["content"]["1"] = 0;
						}
					}
					else if (!ProcStep(currX, currY, currBotColor) && isLast) // 不合法棋步!
					{
						output["display"]["err"] = "INVALIDMOVE";
						output["display"]["winner"] = 0;
						output["command"] = "finish"; // 判输
						output["content"]["0"] = 2;
						output["content"]["1"] = 0;
					}
					else if (isLast) // 正常棋步
					{
						output["display"]["x"] = currX;
						output["display"]["y"] = currY;
						if (!CheckIfHasValidMove(currBotColor) && !CheckIfHasValidMove(-currBotColor)) // 游戏结束
						{
							if (blackPieceCount > whitePieceCount)
							{
								output["display"]["winner"] = 0;
								output["command"] = "finish";
								output["content"]["0"] = 2;
								output["content"]["1"] = 0;
							}
							else if (blackPieceCount < whitePieceCount)
							{
								output["display"]["winner"] = 1;
								output["command"] = "finish";
								output["content"]["0"] = 0;
								output["content"]["1"] = 2;
							}
							else
							{
								output["command"] = "finish";
								output["content"]["0"] = 1;
								output["content"]["1"] = 1;
							}
						}
						else
						{
							output["command"] = "request";
							output["content"]["0"]["x"] = currX;
							output["content"]["0"]["y"] = currY;
						}
					}
				}
				else if (isLast)
				{
					output["display"]["err"] = "INVALIDMOVE";
					output["display"]["winner"] = 0;
					output["command"] = "finish"; // 判输
					output["content"]["0"] = 2;
					output["content"]["1"] = 0;
				}
			}
			currBotColor *= -1;
		}
	}
	Json::FastWriter writer;
	cout << writer.write(output) << endl;
}