简单的爱心效果

五子棋人机对战

#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;
}
posted @ 2023-07-16 22:45  Light-Chaser  阅读(28)  评论(0编辑  收藏  举报
简单的爱心效果