“裁判”的版本间的差异

来自Botzone Wiki
跳转至: 导航搜索
第2行: 第2行:
  
 
裁判与[[Bot]]一样可以用各种语言编写,主要作用是通过[[控制器]]接收各个玩家的输入并根据规则进行判断,然后给出下一回合的指令。
 
裁判与[[Bot]]一样可以用各种语言编写,主要作用是通过[[控制器]]接收各个玩家的输入并根据规则进行判断,然后给出下一回合的指令。
 +
 +
== 交互 ==
 +
 +
裁判每回合开始时会被运行一次,每次生命周期均为一次输入、一次输出,每次输入会包括裁判和所有玩家以往跟平台的所有交互内容。交互格式为'''单行[[JSON]]'''。
 +
 +
因此,裁判的程序运行流程应当是:
 +
*启动程序
 +
*从平台获取以往的交互内容和上回合玩家输出的response
 +
*根据获得的交互内容(自己以前发出的request + 玩家输出的response)进行计算
 +
**恢复局面到最新状态
 +
**根据玩家的上回合response演算下一局面
 +
***如果游戏结束,给出玩家分数
 +
***如果游戏继续,则确定哪些玩家应当进行动作,并给这些玩家发送request
 +
*关闭程序
 +
 +
===资源限制===
 +
 +
同[[Bot#.E8.B5.84.E6.BA.90.E9.99.90.E5.88.B6]]。
 +
 +
===交互格式===
 +
 +
===='''裁判得到的输入'''====
 +
<syntaxhighlight lang="javascript">
 +
{
 +
"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": "" // 初始化数据
 +
}
 +
</syntaxhighlight>
 +
 +
===='''裁判应该给出的输出'''====
 +
 +
如果游戏继续:
 +
<syntaxhighlight lang="javascript">
 +
{
 +
"command": "request",
 +
"content": {
 +
"0": ... // 要运行的玩家和给它的request
 +
},
 +
"display": ... // 给播放器的信息,可以是JSON对象
 +
}
 +
</syntaxhighlight>
 +
 +
如果游戏结束:
 +
<syntaxhighlight lang="javascript">
 +
{
 +
"command": "finish",
 +
"content": {
 +
"0": 1, // 每个玩家的分数
 +
"1": 2
 +
},
 +
"display": ... // 给播放器的信息,可以是JSON对象
 +
}
 +
</syntaxhighlight>
 +
 +
===样例程序===
 +
以下给出C++的[[JSON]]裁判样例程序:
 +
 +
本地编译的方式请查看 [[JSONCPP]]。
 +
 +
<syntaxhighlight lang="cpp">
 +
#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;
 +
}
 +
</syntaxhighlight>

2017年6月18日 (日) 17:09的版本

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

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

交互

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

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

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

资源限制

Bot#.E8.B5.84.E6.BA.90.E9.99.90.E5.88.B6

交互格式

裁判得到的输入

{
	"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;
}