裁判
来自Botzone Wiki
Administrator(讨论 | 贡献)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;
}