梦归
发布于 2025-11-09 / 17 阅读
0
0

通过C++实现五子棋

源码(联机功能正在学习QwQ):

#include <graphics.h>
#include <conio.h>
#include <vector>
#include <iostream>
#include <cmath>
#include <windows.h>
#include <mmsystem.h>
#pragma comment(lib, "winmm.lib")

using namespace std;

// === 参数配置 ===
const int BOARD_SIZE = 15;
const int GRID = 35;
const int OFFSET = 30;
const int WIDTH = OFFSET * 2 + GRID * (BOARD_SIZE - 1);
const int HEIGHT = WIDTH;
const int MAX_WINS = 600;

// === 全局变量 ===
int board[BOARD_SIZE][BOARD_SIZE]; // 棋盘:0空 1玩家 2电脑
bool wins[BOARD_SIZE][BOARD_SIZE][MAX_WINS];
int myWin[MAX_WINS];
int computerWin[MAX_WINS];
int winCount = 0;

bool gameOver = false;
bool playerTurn = true;
bool playerIsWhite = false; // 记录玩家是否是白棋

// === 初始化赢法 ===
void initWins() 
{
    memset(wins, 0, sizeof(wins));
    winCount = 0;

    // 横向
    for (int i = 0; i < BOARD_SIZE; i++)
        for (int j = 0; j < BOARD_SIZE - 4; j++) 
        {
            for (int k = 0; k < 5; k++) wins[i][j + k][winCount] = true;
            winCount++;
        }
    // 纵向
    for (int i = 0; i < BOARD_SIZE; i++)
        for (int j = 0; j < BOARD_SIZE - 4; j++) 
        {
            for (int k = 0; k < 5; k++) wins[j + k][i][winCount] = true;
            winCount++;
        }
    // 正斜线 ↘
    for (int i = 0; i < BOARD_SIZE - 4; i++)
        for (int j = 0; j < BOARD_SIZE - 4; j++) 
        {
            for (int k = 0; k < 5; k++) wins[i + k][j + k][winCount] = true;
            winCount++;
        }
    // 反斜线 ↙
    for (int i = 0; i < BOARD_SIZE - 4; i++)
        for (int j = 4; j < BOARD_SIZE; j++)
        {
            for (int k = 0; k < 5; k++) wins[i + k][j - k][winCount] = true;
            winCount++;
        }

    memset(myWin, 0, sizeof(myWin));
    memset(computerWin, 0, sizeof(computerWin));
}

// === 更新统计 ===
void updateWinCounts()
{
    for (int k = 0; k < winCount; k++) 
    {
        myWin[k] = 0;
        computerWin[k] = 0;
    }
    for (int i = 0; i < BOARD_SIZE; i++)
        for (int j = 0; j < BOARD_SIZE; j++)
            if (board[i][j] != 0)
                for (int k = 0; k < winCount; k++)
                    if (wins[i][j][k]) 
                    {
                        if (board[i][j] == 1) myWin[k]++;
                        else if (board[i][j] == 2) computerWin[k]++;
                    }
}

// === 绘制棋盘 ===
void drawBoard() 
{
    setlinecolor(BLACK);
    for (int i = 0; i < BOARD_SIZE; i++) 
    {
        line(OFFSET, OFFSET + i * GRID, OFFSET + (BOARD_SIZE - 1) * GRID, OFFSET + i * GRID);
        line(OFFSET + i * GRID, OFFSET, OFFSET + i * GRID, OFFSET + (BOARD_SIZE - 1) * GRID);
    }
    setfillcolor(WHITE);
    fillcircle(OFFSET + 7 * GRID, OFFSET + 7 * GRID, 4);
    fillcircle(OFFSET + 3 * GRID, OFFSET + 3 * GRID, 4);
    fillcircle(OFFSET + 3 * GRID, OFFSET + 11 * GRID, 4);
    fillcircle(OFFSET + 11 * GRID, OFFSET + 3 * GRID, 4);
    fillcircle(OFFSET + 11 * GRID, OFFSET + 11 * GRID, 4);
}

// === 绘制棋子 ===
void drawPiece(int i, int j, int role) 
{
    int x = OFFSET + i * GRID;
    int y = OFFSET + j * GRID;
    if (role == 1) setfillcolor(BLACK);
    else setfillcolor(WHITE);
    solidcircle(x, y, 13);
}

// === 胜负判断 ===
void checkWin(int x, int y, int role) 
{
    int dx[4] = { 1, 0, 1, 1 };
    int dy[4] = { 0, 1, 1, -1 };
    for (int dir = 0; dir < 4; dir++)
    {
        int count = 1;
        for (int step = 1; step < 5; step++)
        {
            int nx = x + dx[dir] * step, ny = y + dy[dir] * step;
            if (nx < 0 || nx >= BOARD_SIZE || ny < 0 || ny >= BOARD_SIZE) break;
            if (board[nx][ny] == role) count++; else break;
        }
        for (int step = 1; step < 5; step++)
        {
            int nx = x - dx[dir] * step, ny = y - dy[dir] * step;
            if (nx < 0 || nx >= BOARD_SIZE || ny < 0 || ny >= BOARD_SIZE) break;
            if (board[nx][ny] == role) count++; else break;
        }
        if (count >= 5) 
        {
            // 发现五连,直接处理胜利提示和音效
            gameOver = true;
            settextstyle(25, 0, L"幼圆");
            if (role == 1) 
            {
                // role==1 黑棋
                outtextxy(WIDTH / 2 - 100, HEIGHT / 2 - 40, L"黑棋胜利! 游戏结束");
                // 如果玩家是白棋(playerIsWhite==true),那么对方,播放失败音
                if (playerIsWhite == true)
                {
                    PlaySound(L"failed.wav", NULL, SND_FILENAME | SND_ASYNC);
                }
            }
            else 
            {
                outtextxy(WIDTH / 2 - 100, HEIGHT / 2 - 40, L"白棋胜利! 游戏结束");
                if (playerIsWhite == false) 
                {
                    PlaySound(L"failed.wav", NULL, SND_FILENAME | SND_ASYNC);
                }
            }
            return; // 找到一条五连就结束检测
        }
    }
}

// === putPiece:统一落子逻辑 ===
void putPiece(int x, int y, int role) 
{
    board[x][y] = role;
    drawPiece(x, y, role);
    updateWinCounts();

    PlaySound(L"kun.wav", NULL, SND_FILENAME | SND_ASYNC);

    // 由 checkWin 内部处理胜利提示与 gameOver
    checkWin(x, y, role);
}

// === 玩家下棋:返回坐标 ===
void getPlayerMove(int &i,int &j) 
{
    MOUSEMSG msg;
    while (true) 
    {
        msg = GetMouseMsg();
        if (msg.uMsg == WM_LBUTTONDOWN) 
        {
            i = (msg.x - OFFSET + GRID / 2) / GRID;
            j = (msg.y - OFFSET + GRID / 2) / GRID;
            if (i >= 0 && i < BOARD_SIZE && j >= 0 && j < BOARD_SIZE && board[i][j] == 0)
                return ;
        }
    }
}

// === 电脑AI计算落子坐标 ===
void getComputerMove(int &bestX,int &bestY)
{
    int myScore[BOARD_SIZE][BOARD_SIZE] = { 0 };
    int computerScore[BOARD_SIZE][BOARD_SIZE] = { 0 };
    int maxScore = 0;
    bestX = 7;
    bestY = 7;
    for (int i = 0; i < BOARD_SIZE; i++)
        for (int j = 0; j < BOARD_SIZE; j++)
            if (board[i][j] == 0)
                for (int k = 0; k < winCount; k++)
                    if (wins[i][j][k]) {
                        if (myWin[k] == 1) myScore[i][j] += 200;
                        else if (myWin[k] == 2) myScore[i][j] += 400;
                        else if (myWin[k] == 3) myScore[i][j] += 2000;
                        else if (myWin[k] == 4) myScore[i][j] += 10000;

                        if (computerWin[k] == 1) computerScore[i][j] += 220;
                        else if (computerWin[k] == 2) computerScore[i][j] += 420;
                        else if (computerWin[k] == 3) computerScore[i][j] += 2100;
                        else if (computerWin[k] == 4) computerScore[i][j] += 20000;

                        int score = max(myScore[i][j], computerScore[i][j]);
                        if (score > maxScore) 
                        {
                            maxScore = score;
                            bestX = i; bestY = j;
                        }
                    }
    return ;
}

// === 掷骰子决定先手 ===
void diceToDecideFirst() 
{
    srand((unsigned)time(NULL));

    cleardevice();
    settextcolor(GREEN);
    outtextxy(WIDTH / 2 - 60, HEIGHT / 2 - 40, L"掷骰子决定先手中...");
    Sleep(1000);

    // 模拟掷骰子动画
    for (int i = 0; i < 10; i++) 
    {
        int playerDice = rand() % 6 + 1;
        int computerDice = rand() % 6 + 1;
        cleardevice();
        wchar_t info[64];
        swprintf(info, 64, L"玩家1:%d    玩家2:%d", playerDice, computerDice);
        settextstyle(30, 0, L"幼圆");
        outtextxy(WIDTH / 2 - 80, 60, L"默认先手是白棋");
        settextcolor(GREEN);
        outtextxy(WIDTH / 2 - 80, HEIGHT / 2 - 20, info);
        Sleep(200);
    }

    // 最终结果
    int playerDice = rand() % 6 + 1;
    int computerDice = rand() % 6 + 1;
    cleardevice();
    settextstyle(20, 0, L"幼圆");
    bool playerFirst;
    if (playerDice > computerDice) 
    {
        outtextxy(20, 10, L"你赢了骰子,你先手!");
        playerFirst = true;
    }
    else if (playerDice < computerDice) 
    {
        outtextxy(20, 10, L"对方赢了骰子,对方先手!");
        playerFirst = false;
    }
    else 
    {
        // 平局时默认玩家先手(你也可以重掷或其它规则)
        outtextxy(20, 10, L"平局,默认玩家先手!");
        playerFirst = true;
    }

    // 将结果写回全局变量:先手为白棋
    playerTurn = playerFirst;
    playerIsWhite = playerTurn; // 先手总是白棋

    Sleep(1500);
}


// === 联机初始化 ===
void initGame_pair()
{
    initgraph(WIDTH, HEIGHT);
    setbkcolor(RGB(255, 228, 189));
    cleardevice();
    for (int i = 0; i < BOARD_SIZE; i++)
        for (int j = 0; j < BOARD_SIZE; j++)
            board[i][j] = 0;

    // 掷骰子决定先手(该函数内部设置 playerTurn / playerIsWhite)
    diceToDecideFirst();

    gameOver = false;

    initWins();
    updateWinCounts();
    drawBoard();
    // 如果电脑先手(playerTurn==false),让电脑下第一步
    if (!playerTurn) 
    {
        int x, y;
        getComputerMove(x, y);
        putPiece(x, y, 2);
        playerTurn = true;
    }
}
// === 人机初始化 ===
void initGame()
{
    initgraph(WIDTH, HEIGHT);
    setbkcolor(RGB(255, 228, 189));
    cleardevice();
    for (int i = 0; i < BOARD_SIZE; i++)
        for (int j = 0; j < BOARD_SIZE; j++)
            board[i][j] = 0;

    // 掷骰子决定先手(该函数内部设置 playerTurn / playerIsWhite)
    diceToDecideFirst();

    gameOver = false;

    initWins();
    updateWinCounts();
    drawBoard();
    // 如果电脑先手(playerTurn==false),让电脑下第一步
    if (!playerTurn) 
    {
        int x, y;
        getComputerMove(x, y);
        putPiece(x, y, 2);
        playerTurn = true;
    }
}

void restartGame() 
{
    cleardevice();
    memset(board, 0, sizeof(board));
    initWins();
    updateWinCounts();
    drawBoard();
    gameOver = false;
}

// 选择游戏模式
int chooseGameMode() 
{
    initgraph(WIDTH, HEIGHT);
    setbkcolor(RGB(255, 228, 189));
    setfillcolor(RGB(255, 228, 189));
    cleardevice();
    fillrectangle(WIDTH / 2 - 100, HEIGHT / 2 - 60, WIDTH / 2 + 100, HEIGHT / 2 - 10); // 人机
    fillrectangle(WIDTH / 2 - 100, HEIGHT / 2 + 10, WIDTH / 2 + 100, HEIGHT / 2 + 60); // 联机

    settextcolor(GREEN);
    settextstyle(30, 0, L"幼圆");
    outtextxy(WIDTH / 2 - 80, 60, L"请选择模式");
    settextcolor(RED);
    outtextxy(WIDTH / 2 - 60, HEIGHT / 2 - 50, L"人机对战");
    outtextxy(WIDTH / 2 - 60, HEIGHT / 2 + 20, L"联机对战");

    while (1) 
    {
        if (MouseHit()) 
        {
            MOUSEMSG msg = GetMouseMsg();
            if (msg.uMsg == WM_LBUTTONDOWN) 
            {
                // 人机按钮
                if (msg.x >= WIDTH / 2 - 100 && msg.x <= WIDTH / 2 + 100 &&
                    msg.y >= HEIGHT / 2 - 60 && msg.y <= HEIGHT / 2 - 10) 
                {
                    closegraph();
                    return 1;
                }
                // 联机按钮
                if (msg.x >= WIDTH / 2 - 100 && msg.x <= WIDTH / 2 + 100 &&
                    msg.y >= HEIGHT / 2 + 10 && msg.y <= HEIGHT / 2 + 60) 
                {
                    closegraph();
                    return 2;
                }
            }
        }
        Sleep(10);
    }
}

// === 联机主循环 ===
void gameLoop_pair()
{

}

// === 人机主循环 ===
void gameLoop() 
{
    while (!gameOver) 
    {
        int x, y;
        if (playerTurn) 
        {
            getPlayerMove(x, y);
            putPiece(x, y, playerIsWhite ? 2 : 1);
            playerTurn = false;
        }
        else 
        {
            getComputerMove(x, y);
            putPiece(x, y, playerIsWhite ? 1 : 2);
            playerTurn = true;
        }
    }


    settextcolor(RED);
    outtextxy(10, HEIGHT - 30, L"点击鼠标左键重新开始,或关闭窗口退出。");

    while (true) 
    {
        if (MouseHit()) 
        {
            MOUSEMSG msg = GetMouseMsg();
            if (msg.uMsg == WM_LBUTTONDOWN) 
            {
                restartGame();     // 重开一局
                switch (chooseGameMode())
                {
                case 1:
                {
                    initGame();
                    gameLoop();
                    break;
                }
                case 2:
                {
                    initGame_pair();
                    gameLoop_pair();
                    break;
                }
                }
                  // 重新进入循环
                return;
            }
        }
        if (!IsWindow(GetHWnd())) 
        {
            break;  // 用户关闭窗口时退出
        }

    }
}



// === 程序入口 ===
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE, LPSTR, int) 
{
    switch (chooseGameMode())
    {
    case 1:
    {
        initGame();
        gameLoop();
        break;
    }
    case 2:
    {
        initGame_pair();
        gameLoop_pair();
        break;
    }
    }
}


评论