黑白棋样例程序及注释解析(无决策算法)

// 黑白棋(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) //注意:这里调用一次move,x,y也相应移动了一步
 {
    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++)   // 这里遍历八个方向,每次搞一个方向 搞一圈下来把所有方向上面的夹住的对方的棋子保存在effectivePoints上
    {
        x = xPos;
        y = yPos;
        currCount = 0;
        while (1)
        {
            if (!MoveStep(x, y, dir))//朝着一个方向上移动判断是否超界,边界就break, 每while一次都会往dir方向前进一步
            {
                currCount = 0;
                break;
            }
            if (gridInfo[x][y] == -color)  //移动一下还是对方棋子那就对方棋子个数加1,把对方的个数和位置记下来保存到effectivePoints数组上
            {
                currCount++; //数字就加一
                effectivePoints[currCount][0] = x;
                effectivePoints[currCount][1] = y;
            }
            else if (gridInfo[x][y] == 0) //没有棋子
            {
                currCount = 0;
                break;
            }
            else     //这种情况指的是这个棋子是我方,那么计数器就不置0了,直接跳出,这时已经是我方棋子夹住了currCount多的敌方棋子
            {
                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) //如果这个地方是合法的坐标,那么下面就对这盘棋的黑白进行改变+1
    {
        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; //三维,保存n个回合双方的棋子坐标
    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++)  //以往回合的落子信息已经保存到全局变量gridInfo里面了
    {
        // 根据这些输入输出逐渐恢复状态到当前回合
        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;
        }

    // 做出决策(你只需修改以下部分)

    int resultX, resultY;
    if (posCount > 0)
    {
        srand(time(0));
        choice = rand() % posCount;
        resultX = possiblePos[choice][0];
        resultY = possiblePos[choice][1];
    }
    else
    {
        resultX = -1;
        resultY = -1;
    }

    // 决策结束,输出结果(你只需修改以上部分)

    Json::Value ret;
    ret["response"]["x"] = resultX;
    ret["response"]["y"] = resultY;
    Json::FastWriter writer;
    cout << writer.write(ret) << endl; //这是电脑上的决定
    return 0;
 }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值