Reversi
来自Botzone Wiki
作者
裁判程序 & 播放器:zhouhy
游戏规则
这里的黑白棋游戏与国际通行的黑白棋规则基本一致。
黑白棋是一种二人棋盘游戏,黑白双方交替在8x8的棋盘上落子。
玩家每次落子的位置是有限的,能落子的位置有如下特点:
- 没有子。
- 记当前位置为A,从A开始,在八个方向上至少有一个方向有一个自己的棋子B,A和B这两个棋子之间没有空位,所夹的全是对方的棋子。
每次落子后,所有方向上所有被夹住的对方棋子必须全部翻转为自己的棋子。
若没有上述这种位置则己方跳过回合。双方均无子可下的时候游戏结束,数出双方棋子数,棋多者胜。
棋盘初始状态为
○ | ● | ||||||
● | ○ | ||||||
黑方为先手。
游戏交互方式
本游戏与Botzone上其他游戏一样,使用相同的交互方式:Bot#交互
具体交互内容
每回合Bot收到的request不是字符串,而是一个JSON对象,表示对方落子位置。格式如下:
{
"x": Number, // 横坐标
"y": Number // 纵坐标
}
Bot所需要输出的response也是格式相同的JSON对象,表示自己要落子的位置。
如果request是{"x": -1, "y": -1},则有如下两种情况:
- 这是黑方的第一回合
- 对方无子可下,跳过回合
同样地,如果Bot无子可下,需要给出的response也是{"x": -1, "y": -1}。
游戏样例程序
以下是C++编写的黑白棋样例程序。落子策略采用随机方式。
本地编译的方式请查看 JSONCPP。
// 黑白棋(Reversi)样例程序
// 随机策略
// 作者:zhouhy
// 游戏信息:http://www.botzone.org/games#Reversi
#include <iostream>
#include <string>
#include <cstdlib>
#include <ctime>
#include "jsoncpp/json.h" // C++编译时默认包含此库
using namespace std;
int currBotColor; // 我所执子颜色(1为黑,-1为白,棋盘状态亦同)
int gridInfo[8][8] = { 0 }; // 先x后y,记录棋盘状态
int blackPieceCount = 2, whitePieceCount = 2;
// 向Direction方向改动坐标,并返回是否越界
inline 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)
{
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;
}
// 检查color方有无合法棋步
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()
{
int x, y;
// 初始化棋盘
gridInfo[3][4] = gridInfo[4][3] = 1; //|白|黑|
gridInfo[3][3] = gridInfo[4][4] = -1; //|黑|白|
// 读入JSON
string str;
getline(cin, str);
Json::Reader reader;
Json::Value input;
reader.parse(str, input);
// 分析自己收到的输入和自己过往的输出,并恢复状态
int turnID = input["responses"].size();
currBotColor = input["requests"][(Json::Value::UInt) 0]["x"].asInt() < 0 ? 1 : -1; // 第一回合收到坐标是-1, -1,说明我是黑方
for (int i = 0; i < turnID; i++)
{
// 根据这些输入输出逐渐恢复状态到当前回合
x = input["requests"][i]["x"].asInt();
y = input["requests"][i]["y"].asInt();
if (x >= 0)
ProcStep(x, y, -currBotColor); // 模拟对方落子
x = input["responses"][i]["x"].asInt();
y = input["responses"][i]["y"].asInt();
if (x >= 0)
ProcStep(x, y, currBotColor); // 模拟己方落子
}
// 看看自己本回合输入
x = input["requests"][turnID]["x"].asInt();
y = input["requests"][turnID]["y"].asInt();
if (x >= 0)
ProcStep(x, y, -currBotColor); // 模拟对方落子
// 找出合法落子点
int possiblePos[64][2], posCount = 0, choice;
for (y = 0; y < 8; y++)
for (x = 0; x < 8; x++)
if (ProcStep(x, y, currBotColor, true))
{
possiblePos[posCount][0] = x;
possiblePos[posCount++][1] = y;
}
// 做出决策并输出决策JSON
Json::Value ret;
if (posCount > 0)
{
srand(time(0));
choice = rand() % posCount;
ret["response"]["x"] = possiblePos[choice][0];
ret["response"]["y"] = possiblePos[choice][1];
}
else
{
ret["response"]["x"] = -1;
ret["response"]["y"] = -1;
}
Json::FastWriter writer;
cout << writer.write(ret) << endl;
return 0;
}