Amazons
Amazons
简介 Amazons(亚马逊棋),是1988年由阿根廷人WalteZamkauska发明的双人棋类游戏,由国际象棋中后的走法衍生而来,属于两人零和完备信息博弈。目前亚马逊棋是ICGA国际机器博弈锦标赛和全国大学生计算机博弈大赛的比赛项目之一。
游戏规则
棋盘:由黑白相间的10*10的方格组成,黑方在棋盘上方,白方在棋盘下方(坐标从0开始,先x后y, 原点在左上角)
*————————————> X | | | | | | | | | Y
棋子:每方有4个棋子(4个Amazons),初始位置分别位于(0,3),(3,0),(6,0),(9,3)和(0,6),(3,9),(6,9),(9,6)
1.每个棋子都相当于国际象棋中的皇后,它们的行棋方法与皇后相同,可以在8个方向(上、下、左、右、左上、左下、右上、右下)上任意行走,但不能穿过阻碍
2.当轮到一方行棋时,此方只能而且必须移动4个Amazons中的一个,并在移动完成后,由当前移动的棋子释放一个障碍,障碍的释放方法与棋子的移动方法相同(8个方向,但不能穿过障碍),同样障碍的放置也是必须的
3.当某方完成某次移动后,对方4个棋子均不能再移动时,对方将输掉比赛
4.每次开局位于棋盘上方的玩家(黑方)先手;
5.整个比赛中双方均不能吃掉对方或己方的棋子或障碍
游戏交互方式
本游戏与Botzone上其他游戏一样,使用相同的交互方式:Bot#交互[1]
具体交互内容
每回合Bot收到的request不是字符串,而是一个JSON对象,表示对方落子位置。格式如下:
{ "x0": Number, // 起点横坐标 "y0": Number, // 起点纵坐标 "x1": Number, // 终点横坐标 "y1": Number, // 终点纵坐标 "x2": Number, // 释放的障碍横坐标 "y2": Number // 释放的障碍纵坐标 }
Bot所需要输出的response也是格式相同的JSON对象,表示自己选择移动的棋子的起点、终点和障碍的位置。
如果是黑方的第一回合,则 request 为 {"x0": -1, "y0": -1, "x1" : -1, "y1" : -1, "x2" : -1, "y2" : -1}。
游戏样例程序
C++:
本地编译方式请参看JSONCPP。
// 亚马逊棋(Amazons)样例程序
// 随机策略
// 作者:dgf123/syys
// 游戏信息:http://www.botzone.org/games#Amazons
#include <iostream>
#include <string>
#include <cstdlib>
#include <ctime>
#include "jsoncpp/json.h"
#define GRIDSIZE 10
#define OBSTACLE 2
#define judge_black 0
#define judge_white 1
#define grid_black 1
#define grid_white -1
using namespace std;
int currBotColor; // 我所执子颜色(1为黑,-1为白,棋盘状态亦同)
int gridInfo[GRIDSIZE][GRIDSIZE] = { 0 }; // 先x后y,记录棋盘状态
int dx[] = { -1,-1,-1,0,0,1,1,1 };
int dy[] = { -1,0,1,-1,1,-1,0,1 };
// 判断是否在地图内
inline bool inMap(int x, int y)
{
if (x < 0 || x >= GRIDSIZE || y < 0 || y >= GRIDSIZE)
return false;
return true;
}
// 在坐标处落子,检查是否合法或模拟落子
bool ProcStep(int x0, int y0, int x1, int y1, int x2, int y2, int color, bool check_only)
{
if ((!inMap(x0, y0)) || (!inMap(x1, y1)) || (!inMap(x2, y2)))
return false;
if (gridInfo[x0][y0] != color || gridInfo[x1][y1] != 0)
return false;
if ((gridInfo[x2][y2] != 0) && !(x2 == x0 && y2 == y0))
return false;
if (!check_only)
{
gridInfo[x0][y0] = 0;
gridInfo[x1][y1] = color;
gridInfo[x2][y2] = OBSTACLE;
}
return true;
}
int main()
{
int x0, y0, x1, y1, x2, y2;
// 初始化棋盘
gridInfo[0][3] = gridInfo[3][0] = gridInfo[6][0] = gridInfo[9][3] = grid_black;
gridInfo[0][6] = gridInfo[3][9] = gridInfo[6][9] = gridInfo[9][6] = grid_white;
// 读入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]["x0"].asInt() < 0 ? grid_black : grid_white; // 第一回合收到坐标是-1, -1,说明我是黑方
for (int i = 0; i < turnID; i++)
{
// 根据这些输入输出逐渐恢复状态到当前回合
x0 = input["requests"][i]["x0"].asInt();
y0 = input["requests"][i]["y0"].asInt();
x1 = input["requests"][i]["x1"].asInt();
y1 = input["requests"][i]["y1"].asInt();
x2 = input["requests"][i]["x2"].asInt();
y2 = input["requests"][i]["y2"].asInt();
if (x0 >= 0)
ProcStep(x0, y0, x1, y1, x2, y2, -currBotColor, false); // 模拟对方落子
x0 = input["responses"][i]["x0"].asInt();
y0 = input["responses"][i]["y0"].asInt();
x1 = input["responses"][i]["x1"].asInt();
y1 = input["responses"][i]["y1"].asInt();
x2 = input["responses"][i]["x2"].asInt();
y2 = input["responses"][i]["y2"].asInt();
if (x0 >= 0)
ProcStep(x0, y0, x1, y1, x2, y2, currBotColor, false); // 模拟己方落子
}
// 看看自己本回合输入
x0 = input["requests"][turnID]["x0"].asInt();
y0 = input["requests"][turnID]["y0"].asInt();
x1 = input["requests"][turnID]["x1"].asInt();
y1 = input["requests"][turnID]["y1"].asInt();
x2 = input["requests"][turnID]["x2"].asInt();
y2 = input["requests"][turnID]["y2"].asInt();
if (x0 >= 0)
ProcStep(x0, y0, x1, y1, x2, y2, -currBotColor, false); // 模拟对方落子
int beginPos[3000][2], possiblePos[3000][2], obstaclePos[3000][2];
int posCount = 0, choice;
for (int i = 0; i < GRIDSIZE; ++i) {
for (int j = 0; j < GRIDSIZE; ++j) {
for (int k = 0; k < 8; ++k) {
int xx = i + dx[k];
int yy = j + dy[k];
for (int l = 0; l < 8; ++l) {
int xxx = xx + dx[l];
int yyy = yy + dy[l];
if (ProcStep(i, j, xx, yy, xxx, yyy, currBotColor,true))
{
beginPos[posCount][0] = i;
beginPos[posCount][1] = j;
possiblePos[posCount][0] = xx;
possiblePos[posCount][1] = yy;
obstaclePos[posCount][0] = xxx;
obstaclePos[posCount++][1] = yyy;
}
}
}
}
}
// 做出决策(你只需修改以下部分)
int startX, startY, resultX, resultY, obstacleX, obstacleY;
if (posCount > 0)
{
srand(time(0));
choice = rand() % posCount;
startX = beginPos[choice][0];
startY = beginPos[choice][1];
resultX = possiblePos[choice][0];
resultY = possiblePos[choice][1];
obstacleX = obstaclePos[choice][0];
obstacleY = obstaclePos[choice][1];
}
else
{
startX = -1;
startY = -1;
resultX = -1;
resultY = -1;
obstacleX = -1;
obstacleY = -1;
}
// 决策结束,输出结果(你只需修改以上部分)
Json::Value ret;
ret["response"]["x0"] = startX;
ret["response"]["y0"] = startY;
ret["response"]["x1"] = resultX;
ret["response"]["y1"] = resultY;
ret["response"]["x2"] = obstacleX;
ret["response"]["y2"] = obstacleY;
Json::FastWriter writer;
cout << writer.write(ret) << endl;
return 0;
}