Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <iostream>
- #include <unistd.h>
- #include <chrono>
- #include <ctime>
- #include "Point.h"
- #include "Strategy.h"
- #include <cmath>
- #include "Judge.h"
- using namespace std;
- /*
- 策略函数接口,该函数被对抗平台调用,每次传入当前状态,要求输出你的落子点,该落子点必须是一个符合游戏规则的落子点,不然对抗平台会直接认为你的程序有误
- input:
- 为了防止对对抗平台维护的数据造成更改,所有传入的参数均为const属性
- M, N : 棋盘大小 M - 行数 N - 列数 均从0开始计, 左上角为坐标原点,行用x标记,列用y标记
- top : 当前棋盘每一列列顶的实际位置. e.g. 第i列为空,则_top[i] == M, 第i列已满,则_top[i] == 0
- _board : 棋盘的一维数组表示, 为了方便使用,在该函数刚开始处,我们已经将其转化为了二维数组board
- 你只需直接使用board即可,左上角为坐标原点,数组从[0][0]开始计(不是[1][1])
- board[x][y]表示第x行、第y列的点(从0开始计)
- board[x][y] == 0/1/2 分别对应(x,y)处 无落子/有用户的子/有程序的子,不可落子点处的值也为0
- lastX, lastY : 对方上一次落子的位置, 你可能不需要该参数,也可能需要的不仅仅是对方一步的
- 落子位置,这时你可以在自己的程序中记录对方连续多步的落子位置,这完全取决于你自己的策略
- noX, noY : 棋盘上的不可落子点(注:涫嫡饫锔?龅膖op已经替你处理了不可落子点,也就是说如果某一步
- 所落的子的上面恰是不可落子点,那么UI工程中的代码就已经将该列的top值又进行了一次减一操作,
- 所以在你的代码中也可以根本不使用noX和noY这两个参数,完全认为top数组就是当前每列的顶部即可,
- 当然如果你想使用lastX,lastY参数,有可能就要同时考虑noX和noY了)
- 以上参数实际上包含了当前状态(M N _top _board)以及历史信息(lastX lastY),你要做的就是在这些信息下给出尽可能明智的落子点
- output:
- 你的落子点Point
- */
- int **myBoard;
- int *myTop;
- int numTop;
- int boardM;
- int boardN;
- bool myTurn;
- std::clock_t startTime;
- class MonteCarloNode {
- public:
- MonteCarloNode *bestChild();
- MonteCarloNode() {
- accessTime = 0;
- winTime = 0;
- numChildren = 0;
- parent = nullptr;
- point = Point(-1, -1);
- }
- MonteCarloNode(int numChildren, bool userTurn): numChildren(numChildren), userTurn(userTurn) {}
- ~MonteCarloNode() { }
- void expand();
- void merge();
- int search_for_optimal();
- int accessTime = 0;
- int winTime = 0;
- int numChildren = 0;
- bool userTurn = false;
- bool isLeaf = false;
- bool win = false;
- MonteCarloNode *children[12] = {};
- MonteCarloNode *parent = nullptr;
- Point point = Point(-1, -1);
- double value();
- void update(bool win);
- void updateAll(bool win);
- };
- MonteCarloNode *root;
- extern "C" Point *getPoint(const int M, const int N, const int *top, const int *_board,
- const int lastX, const int lastY, const int noX, const int noY)
- {
- /*
- 不要更改这段代码
- */
- startTime = std::clock();
- int x = -1, y = -1; //最终将你的落子点存到x,y中
- int **board = new int *[M];
- for (int i = 0; i < M; i++)
- {
- board[i] = new int[N];
- for (int j = 0; j < N; j++)
- {
- board[i][j] = _board[i * N + j];
- }
- }
- /*
- 根据你自己的策略来返回落子点,也就是根据你的策略完成对x,y的赋值
- 该部分对参数使用没有限制,为了方便实现,你可以定义自己新的类、.h文件、.cpp文件
- */
- //Add your own code below
- //a naive example
- // for (int i = N-1; i >= 0; i--) {
- // if (top[i] > 0) {
- // x = top[i] - 1;
- // y = i;
- // break;
- // }
- // }
- boardM = M;
- boardN = N;
- myBoard = new int *[M];
- for (int i = 0; i < M; i++) {
- myBoard[i] = new int[N];
- }
- myTop = new int[N];
- build(board, top);
- // root->show(0, 1);
- x = root->bestChild()->point.x;
- y = root->bestChild()->point.y;
- // delete root;
- /*
- 不要更改这段代码
- */
- clearArray(M, N, board);
- return new Point(x, y);
- }
- /*
- getPoint函数返回的Point指针是在本so模块中声明的,为避免产生堆错误,应在外部调用本so中的
- 函数来释放空间,而不应该在外部直接delete
- */
- extern "C" void clearPoint(Point *p)
- {
- delete p;
- return;
- }
- /*
- 清除top和board数组
- */
- void clearArray(int M, int N, int **board)
- {
- for (int i = 0; i < M; i++)
- {
- delete[] board[i];
- }
- delete[] board;
- }
- /*
- 添加你自己的辅助函数,你可以声明自己的类、函数,添加新的.h .cpp文件来辅助实现你的想法
- */
- double MonteCarloNode::value() {
- int coef = userTurn ? 1 : -1;
- return coef * winTime / double(accessTime + 1) + VALUEC * sqrt(log(parent->accessTime) / (accessTime + 1));
- }
- MonteCarloNode *MonteCarloNode::bestChild() {
- int bestIndex = 0;
- double bestValue = -2;
- for(int i = 0; i < numChildren; i++) {
- if (children[i] && children[i]->value() > bestValue) {
- bestValue = children[i]->value();
- bestIndex = i;
- }
- if (!children[i]) {
- return children[i];
- }
- }
- return children[bestIndex];
- }
- void step(int x, int y) {
- myBoard[x][y] = CHESS(myTurn);
- myTop[y]--;
- if (myTop[y] == 0) {
- numTop--;
- }
- myTurn = !myTurn;
- }
- int topOfN(int n) {
- int ret = -1;
- for (int j = 0; j < boardN; j++) {
- if (myTop[j] > 0) {
- if (n == 0) {
- ret = j;
- }
- n--;
- }
- }
- return ret;
- }
- int check(int x, int y) {
- if (!myTurn) {
- if (userWin(x, y, boardM, boardN, myBoard)) {
- return 1; // user win
- }
- }
- else {
- if (machineWin(x, y, boardM, boardN, myBoard)) {
- return 2; // machine win
- }
- }
- if (isTie(boardN, myTop)) {
- return 3; // tie
- }
- return 0; // continue
- }
- int randomPick() {
- int i = rand() % numTop;
- int order = topOfN(i);
- step(myTop[order]-1, order);
- return check(myTop[order], order);
- }
- bool randomPlay() {
- int result;
- while (!(result = randomPick()));
- if (result == 1) {
- return true;
- }
- else {
- return false;
- }
- }
- void resetMyBoard(const int *const *board) {
- for (int i = 0; i < boardM; i++)
- {
- for (int j = 0; j < boardN; j++)
- {
- myBoard[i][j] = board[i][j];
- }
- }
- }
- void resetMyTop(const int *top) {
- int n = 0;
- for (int i = 0; i < boardN; i++) {
- myTop[i] = top[i];
- if (top[i] > 0) {
- n++;
- }
- }
- numTop = n;
- }
- int numPath(const int *top) {
- int ret = 0;
- for (int i = 0; i < boardN; i++) {
- if (top[i] > 0)
- ret++;
- }
- return ret;
- }
- void MonteCarloNode::update(bool win) {
- accessTime++;
- if (win) {
- winTime++;
- }
- }
- void MonteCarloNode::updateAll(bool win) {
- MonteCarloNode *node = this;
- while(node) {
- node->update(win);
- node = node->parent;
- }
- }
- void MonteCarloNode::expand() {
- int order = 0;
- while (order < numChildren) {
- if (!children[order]) {
- break;
- }
- order++;
- }
- int y = topOfN(order);
- int x = myTop[y] - 1;
- step(x, y);
- children[order] = new MonteCarloNode(numTop, myTurn);
- children[order]->point = Point(x, y);
- children[order]->parent = this;
- int result = check(x, y);
- if (result) {
- updateAll(result == 1);
- return;
- }
- bool win = randomPlay();
- updateAll(win);
- if (numTop == 0) {
- children[order]->isLeaf = true;
- }
- }
- void MonteCarloNode::merge() {
- int numWin = 0;
- int numLeaf = 0;
- for (int i = 0; i < numChildren; i++) {
- if (children[i] && children[i]->isLeaf) {
- numLeaf++;
- if (children[i]->win) {
- numWin++;
- }
- }
- }
- if (numLeaf == numChildren && numWin == numChildren) {
- win = true;
- isLeaf = true;
- }
- else if (numLeaf == numChildren && numWin == 0) {
- win = false;
- isLeaf = true;
- }
- }
- void build(const int *const *board, const int *top) {
- int numChildrenOfRoot = numPath(top);
- root = new MonteCarloNode(numChildrenOfRoot, myTurn);
- MonteCarloNode *node;
- while (true) {
- std::clock_t now = std::clock();
- if ((now - startTime) > 2.8 * CLOCKS_PER_SEC) {
- break;
- }
- resetMyBoard(board);
- resetMyTop(top);
- node = root;
- while (node->bestChild() && !node->isLeaf) {
- node = node->bestChild();
- if (node->point.x > 0 && node->point.y > 0) {
- step(node->point.x, node->point.y);
- }
- }
- if (node->isLeaf) {
- node->updateAll(node->win);
- }
- else {
- node->expand();
- node->merge();
- }
- }
- }
Add Comment
Please, Sign In to add comment