#include <windows.h> #include <windowsx.h> #include <ShObjIdl.h> #include <cmath> #include <cstdlib> #include <ctime> #include <vector> #include <algorithm> #include <iostream> #include <cstdio> #define CELL_SIZE 50 #define BOARD_SIZE 15 using namespace std; // 定义一些常量 const int MARGIN = 5; // 棋盘边缘空隙 const int LINE_WIDTH = 5; const int SCORE_WIN = 30000000; // 赢得分数 const int SCORE_LIVE_FOUR = 700000; // 活四分数 const int SCORE_HALF_SLEEP_FOUR = 450000; // 半眠四分数 const int SCORE_SLEEP_FOUR = -1; // 眠四分数 const int SCORE_LIVE_THREE = 40000; // 活三分数 const int SCORE_HALF_SLEEP_THREE = 1; // 半眠三分数 const int SCORE_SLEEP_THREE = -5; // 眠三分数 const int SCORE_LIVE_TWO = 9000; // 活二分数 const int SCORE_HALF_SLEEP_TWO = 0; // 半眠二分数 const int SCORE_SLEEP_TWO = -5; // 眠二分数 const int SCORE_LIVE_ONE = 2000; // 活一分数 const int SCORE_HALF_SLEEP_ONE = -10; // 半眠一分数 const int SCORE_SLEEP_ONE = -10; // 眠一分数 // 定义一些枚举类型 enum Player {NONE, HUMAN, COMPUTER}; // 玩家类型,无、人类、机器 enum Direction {HORIZONTAL, VERTICAL, LEFT_DIAGONAL, RIGHT_DIAGONAL}; // 方向类型,水平、垂直、左斜、右斜 // 定义一个结构体,表示棋盘上的一个位置 struct Position { int x; // 横坐标 int y; // 纵坐标 Position(int x = -2, int y = -2) : x(x), y(y) {} // 构造函数,初始化为-1表示无效位置 }; // 定义一个全局变量,表示上一次落子的位置,初始为无效位置 Position lastPos(-2, -2); // 定义一个结构体,表示一个评分项,包括位置和分数 struct ScoreItem { Position pos; // 位置 int score; // 分数 ScoreItem(Position pos, int score) : pos(pos), score(score) {} // 构造函数,初始化位置和分数 }; HINSTANCE hInstance; Player board[BOARD_SIZE][BOARD_SIZE]; int currentPlayer = 1; //1 human //2 robot bool gameOver = false; Player starter[2] = {NONE,NONE}, winner = NONE; bool ended = false; int steps = 0; int ManhattanDistance(int x_1,int y_1,int x_2,int y_2){ return abs(x_1-x_2)+abs(y_1-y_2); } void ComputerMove(); int Evaluate(Position pos, Player player); LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { hInstance = hInst; WNDCLASS wc = {0}; wc.lpfnWndProc = WindowProc; wc.hInstance = hInst; wc.lpszClassName = "Gobang"; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); RegisterClass(&wc); HWND hwnd = CreateWindow("Gobang", "Gobang", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CELL_SIZE * BOARD_SIZE + 70, CELL_SIZE * BOARD_SIZE + 70, NULL, NULL, hInst, NULL); SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~WS_SIZEBOX & ~WS_MAXIMIZEBOX & ~WS_MINIMIZEBOX); DeleteMenu(GetSystemMenu(hwnd, FALSE), SC_SIZE, MF_BYCOMMAND); DeleteMenu(GetSystemMenu(hwnd, FALSE), SC_MAXIMIZE, MF_BYCOMMAND); DeleteMenu(GetSystemMenu(hwnd, FALSE), SC_MINIMIZE, MF_BYCOMMAND); DeleteMenu(GetSystemMenu(hwnd, FALSE), SC_RESTORE, MF_BYCOMMAND); SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); // 从任务管理器获取图标 HICON hIcon; ExtractIconEx("C:\\Windows\\System32\\taskmgr.exe", 0, NULL, &hIcon, 1); // 设置程序图标 SendMessage(GetActiveWindow(), WM_SETICON, ICON_BIG, (LPARAM)hIcon); SendMessage(GetActiveWindow(), WM_SETICON, ICON_SMALL, (LPARAM)hIcon); ShowWindow(hwnd, nCmdShow); UpdateWindow(hwnd); MSG msg; while(GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return 0; } LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch(uMsg) { case WM_CREATE: break; case WM_PAINT: { steps++; if(steps==1){ // if(rand()%2) //board[7][7]=COMPUTER, //starter[0]=COMPUTER,starter[1]=HUMAN; //else starter[0]=HUMAN,starter[1]=COMPUTER; } PAINTSTRUCT ps; HDC hdc = BeginPaint(hwnd, &ps); // 创建一个黄色的画刷 HBRUSH hBrush = CreateSolidBrush(RGB(255, 255, 0)); // 将画刷选入设备上下文 HBRUSH hOldBrush = (HBRUSH)SelectObject(hdc, hBrush); // 绘制一个正方形 Rectangle(hdc, (lastPos.x)*CELL_SIZE+5, (lastPos.y)*CELL_SIZE+5, (lastPos.x+1)*CELL_SIZE+5, (lastPos.y+1)*CELL_SIZE+5); // 恢复原来的画刷 SelectObject(hdc, hOldBrush); // 删除创建的画刷 DeleteObject(hBrush); for(int i = 1; i <= BOARD_SIZE + 1; i++) { MoveToEx(hdc, CELL_SIZE * (i - 1) + 5, 5, NULL); LineTo(hdc, CELL_SIZE * (i - 1) + 5, CELL_SIZE * BOARD_SIZE + 5); MoveToEx(hdc, 5, CELL_SIZE * (i - 1) + 5, NULL); LineTo(hdc, CELL_SIZE * BOARD_SIZE + 5, CELL_SIZE * (i - 1) + 5); } for(int i = 0; i < BOARD_SIZE; i++) { for(int j = 0; j < BOARD_SIZE; j++) { RECT cellRect = {i * CELL_SIZE, j * CELL_SIZE, (i + 1) * CELL_SIZE, (j + 1) * CELL_SIZE}; if(board[i][j] == 1) { Ellipse(hdc, cellRect.left + 15, cellRect.top + 15, cellRect.right - 5, cellRect.bottom - 5); } else if(board[i][j] == 2) { MoveToEx(hdc, cellRect.left + 15, cellRect.top + 15, NULL); LineTo(hdc, cellRect.right - 5, cellRect.bottom - 5); MoveToEx(hdc, cellRect.right - 5, cellRect.top + 15, NULL); LineTo(hdc, cellRect.left + 15, cellRect.bottom - 5); } } } EndPaint(hwnd, &ps); break; } case WM_LBUTTONDOWN: { if(gameOver){ ended = true; } if(ended) break; int x = GET_X_LPARAM(lParam) / CELL_SIZE; int y = GET_Y_LPARAM(lParam) / CELL_SIZE; if(board[x][y] == 0) { board[x][y] = HUMAN; lastPos=Position(x,y); InvalidateRect(hwnd, NULL, TRUE); gameOver = false; for(int i = 0; i < BOARD_SIZE; i++) for(int j = 0; j < BOARD_SIZE - 4; j++) if(board[i][j] == currentPlayer && board[i][j+1] == currentPlayer && board[i][j+2] == currentPlayer && board[i][j+3] == currentPlayer && board[i][j+4] == currentPlayer) gameOver = true; for(int i = 0; i < BOARD_SIZE - 4; i++) for(int j = 0; j < BOARD_SIZE; j++) if(board[i][j] == currentPlayer && board[i+1][j] == currentPlayer && board[i+2][j] == currentPlayer && board[i+3][j] == currentPlayer && board[i+4][j] == currentPlayer) gameOver = true; for(int i = 0; i < BOARD_SIZE - 4; i++) for(int j = 0; j < BOARD_SIZE - 4; j++) if(board[i][j] == currentPlayer && board[i+1][j+1] == currentPlayer && board[i+2][j+2] == currentPlayer && board[i+3][j+3] == currentPlayer && board[i+4][j+4] == currentPlayer) gameOver = true; for(int i = 0; i < BOARD_SIZE - 4; i++) for(int j = 4; j < BOARD_SIZE; j++) if(board[i][j] == currentPlayer && board[i+1][j-1] == currentPlayer && board[i+2][j-2] == currentPlayer && board[i+3][j-3] == currentPlayer && board[i+4][j-4] == currentPlayer) gameOver = true; if(gameOver == true){ MessageBox(hwnd, "Game over!", "Gobang", MB_OK); break; } currentPlayer = 2; ComputerMove(); InvalidateRect(hwnd, NULL, TRUE); gameOver = false; for(int i = 0; i < BOARD_SIZE; i++) for(int j = 0; j < BOARD_SIZE - 4; j++) if(board[i][j] == currentPlayer && board[i][j+1] == currentPlayer && board[i][j+2] == currentPlayer && board[i][j+3] == currentPlayer && board[i][j+4] == currentPlayer) gameOver = true; for(int i = 0; i < BOARD_SIZE - 4; i++) for(int j = 0; j < BOARD_SIZE; j++) if(board[i][j] == currentPlayer && board[i+1][j] == currentPlayer && board[i+2][j] == currentPlayer && board[i+3][j] == currentPlayer && board[i+4][j] == currentPlayer) gameOver = true; for(int i = 0; i < BOARD_SIZE - 4; i++) for(int j = 0; j < BOARD_SIZE - 4; j++) if(board[i][j] == currentPlayer && board[i+1][j+1] == currentPlayer && board[i+2][j+2] == currentPlayer && board[i+3][j+3] == currentPlayer && board[i+4][j+4] == currentPlayer) gameOver = true; for(int i = 0; i < BOARD_SIZE - 4; i++) for(int j = 4; j < BOARD_SIZE; j++) if(board[i][j] == currentPlayer && board[i+1][j-1] == currentPlayer && board[i+2][j-2] == currentPlayer && board[i+3][j-3] == currentPlayer && board[i+4][j-4] == currentPlayer) gameOver = true; if(gameOver == true){ MessageBox(hwnd, "Game over!", "Gobang", MB_OK); break; } currentPlayer = 1; } break; } case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hwnd, uMsg, wParam, lParam); } return 0; } // 机器落子函数 void ComputerMove() { // 定义一个评分项的向量,存储每个位置的评分 vector<ScoreItem> scores; // 遍历棋盘上的每个位置 for (int i = 0; i < BOARD_SIZE; i++) { for (int j = 0; j < BOARD_SIZE; j++) { // 如果当前位置没有棋子,则评估该位置的分数 if (board[i][j] == NONE) { // 定义一个位置结构体,存储当前位置 Position pos(i, j); // 定义两个变量,分别存储机器玩家和人类玩家在该位置的分数 int computerScore = Evaluate(pos, COMPUTER); int humanScore = Evaluate(pos, HUMAN); // 定义一个变量,存储该位置的综合分数,取机器玩家和人类玩家分数中的较大者 int score = computerScore + humanScore; // 在评分向量中压入该位置和分数的评分项 scores.push_back(ScoreItem(pos, score)); } } } // 如果评分向量为空,则表示棋盘已满,直接返回 if (scores.empty()) { return; } // 对评分向量进行排序,按照分数从大到小的顺序 sort(scores.begin(), scores.end(), [](const ScoreItem& a, const ScoreItem& b) { return a.score > b.score; }); // 定义一个变量,存储最佳位置,初始为评分向量中第一个位置(分数最高) Position bestPos = scores[0].pos; // 定义一个变量,存储最高分数 int maxScore = scores[0].score; // 定义一个整数向量,存储所有最高分数的位置的下标 vector<int> maxIndices; // 遍历评分向量,找出所有最高分数的位置的下标,并压入整数向量中 for (int i = 0; i < scores.size(); i++) { if (scores[i].score == maxScore) { maxIndices.push_back(i); } else { break; } } // 如果整数向量中有多个下标,则从中随机选择一个作为最佳位置的下标 if (maxIndices.size() > 1) { int index = rand() % maxIndices.size(); bestPos = scores[maxIndices[index]].pos; } // 在棋盘数组中记录机器玩家的棋子 board[bestPos.x][bestPos.y] = COMPUTER; lastPos=Position(bestPos.x,bestPos.y); } // 评估一个位置的分数函数,参数为位置和玩家类型,返回分数 int Evaluate(Position pos, Player player) { int totalScore = 0; // 定义一个变量,存储总分数,初始为0 // 定义一个数组,存储四个方向上的偏移量 int offset[4][2] = {{-1, 0}, {0, -1}, {-1, -1}, {-1, 1}}; // 遍历四个方向 for (int k = 0; k < 4; k++) { // 定义两个变量,表示当前方向上的偏移量 int dx = offset[k][0]; int dy = offset[k][1]; // 定义两个变量,表示当前位置的坐标 int x = pos.x; int y = pos.y; // 定义两个变量,分别表示该方向上的活/眠状态和连子数,初始为活和1(包括自己) int live = 0; int count = 1; int empty = 0; // 沿着当前方向前进,直到遇到边界或不同颜色的棋子,累加连子数,判断活/眠状态 while (true) { x += dx; y += dy; if (x < 0 || x >= BOARD_SIZE || y < 0 || y >= BOARD_SIZE || (board[x][y] != player)) { if (board[x][y] != NONE) { live ++; // 如果遇到边界或对手的棋子,则为眠 } break; } count++; } // 沿着当前方向后退,直到遇到边界或不同颜色的棋子,累加连子数,判断活/眠状态 x = pos.x; y = pos.y; while (true) { x -= dx; y -= dy; if (x < 0 || x >= BOARD_SIZE || y < 0 || y >= BOARD_SIZE || board[x][y] != player) { if (board[x][y] != NONE) { live ++; // 如果遇到边界或对手的棋子,则为眠 } break; } count++; } if(count>=5) live = 0; // 根据活/眠状态和连子数,给该方向上的分数赋值 int score = 0; if (count >= 5) { // 如果连子数大于等于5,则为必胜分数 score = SCORE_WIN; if(player == COMPUTER) score*=4; } else if (live==0) { // 如果是活的 switch (count) { // 根据连子数分别赋值 case 4: score = SCORE_LIVE_FOUR; if(player == COMPUTER) score*=2; break; case 3: score = SCORE_LIVE_THREE; break; case 2: score = SCORE_LIVE_TWO; break; case 1: score = SCORE_LIVE_ONE; break; default: break; } } else if(live == 1){ // 如果是眠的 switch (count) { // 根据连子数分别赋值 case 4: score = SCORE_HALF_SLEEP_FOUR; if(player == COMPUTER) score*=3/2; break; case 3: score = SCORE_HALF_SLEEP_THREE; break; case 2: score = SCORE_HALF_SLEEP_TWO; break; case 1: score = SCORE_HALF_SLEEP_ONE; break; default: break; } } else { // 如果是眠的 switch (count) { // 根据连子数分别赋值 case 4: score = SCORE_SLEEP_FOUR; break; case 3: score = SCORE_SLEEP_THREE; break; case 2: score = SCORE_SLEEP_TWO; break; case 1: score = SCORE_SLEEP_ONE; break; default: break; } } // 累加该方向上的分数到总分数 totalScore += score; } // 返回总分数 return totalScore; }标签:分数,int,五子棋,SCORE,break,对战,score,人机,SIZE From: https://www.cnblogs.com/cytxzgbp/p/17512294.html