c++实现五子棋(通过easyx库实现),包括绘制棋盘,下棋,判断输赢及悔棋功能

本文详细描述了一个使用C++和easyx库实现的五子棋游戏,涉及棋盘初始化、下棋操作、黑白棋区分、悔棋机制及输赢判断。通过二维数组和容器管理棋子位置,以及WindowsAPI进行图形渲染。
摘要由CSDN通过智能技术生成

一、easyx库的安装

二、该代码所使用的头文件

#include <iostream>
#include <string.h>
#include <vector>//容器头文件
#include <Windows.h>
#include<graphics.h>//图形头文件

三、需要使用的数据类型

int board[18][18] = { 0 };//棋盘数组
int flag = 0;//计数器,判断黑棋执步或白棋执步
vector <int> a_v;
vector <int> b_v;//利用容器记录悔棋位置,a,b分别为x,y坐标

三、棋盘绘制(利用easyx绘制棋盘)

//初始化游戏界面
void InitGame()
{
    //绘图
    initgraph(700, 600);//把图界面输出
    setbkcolor(BROWN);//棕色
    cleardevice();//刷新
    //画线 绘制棋盘
    setlinecolor(BLACK);//把线设置成黑色
    for (int i = 70; i <= 500; i += 25)
    {
        line(5, i, 430, i);//画横着的线
        line(i - 65, 70, i - 65, 495);//画垂直的线
    }
    line(431, 70, 431, 495);//加粗
    line(5, 69, 430, 69);
    //输出玩家信息
    outtextxy(480, 80, "玩家1  白棋");
    outtextxy(480, 180, "玩家2  黑棋");
    outtextxy(580, 180, "点击悔棋");
}

绘制成功后即可得到棋盘初始界面

四、基本操作下棋的实现

对于下棋过程,我们可以将棋盘视为二维数组(包括x轴与y轴)int board[18][18] = { 0 };//棋盘数组 (本想用bool类型来记录下棋情况,但由于单个单位会有三种情况黑棋、白棋、无棋,所以使用int类型记录)下棋过程中我们还需要让计算机知道黑棋执步还是白棋执步,因此我加入了int flag = 0;//计数器,判断黑棋执步或白棋执步来记录flag为偶数则黑棋执步,奇数为白棋执步,由于数据只有两种情况,我们可以使用bool类型记录,但是不能记录步数用于悔棋所以废除使用;鉴于五子棋规则,我们需要在下棋后就进行输赢判断(该函数下一段讲述);同时要完成悔棋操作,我们需要记住每步棋子的落位方便悔棋。

//下棋
void playChess()
{
    int a, b;//棋盘上的坐标
    MOUSEMSG m;//鼠标类型的数据
    HWND hwnd;//输出窗口
    hwnd = GetHWnd();
    //鼠标左键点击下棋
    while (1)
    {
        m = GetMouseMsg();//获取鼠标消息
        if (m.uMsg == WM_LBUTTONDOWN)//如果左键按下
        {
            a = (m.x + 13) / 25;
            b = (m.y - 70 + 13) / 25;
            if (m.x >= 580 && m.x <= 660 && m.y >= 180 && m.y <= 200)//悔棋
            {
                huiqi(a_v.back(), b_v.back());
                a_v.pop_back(); b_v.pop_back();//利用vector容器进行悔棋
                continue;
            }
            if (a > 17 || a < 0 || b>17 || b < 0)
            {
                MessageBox(hwnd, "鼠标点击越界", "提示", MB_OK);
                continue;
            }
            if (board[a][b] != 0)
            {
                MessageBox(hwnd, "这里已经有棋子了", "提示", MB_OK);
                continue;
            }
            if (flag % 2 == 0)//是偶数
            {
                //显示为黑棋
                setfillcolor(BLACK);
                board[a][b] = 1;
            }
            if (flag % 2 != 0)//为奇数
            {
                //显示为白棋
                setfillcolor(WHITE);
                board[a][b] = 2;
            }
            //落棋
            solidcircle(a * 25 + 5, b * 25 + 70, 10);//画一个圆
            flag++;
            a_v.push_back(a); b_v.push_back(b);
            //判断输赢
            if (judge(a, b))
            {
                if (flag % 2 == 1)
                {
                    MessageBox(hwnd, "玩家2胜利", "提示", MB_OK);
                    exit(0);
                }
                else
                {
                    MessageBox(hwnd, "玩家1胜利", "提示", MB_OK);
                    exit(0);
                }
            }

        }
    }
}

在下棋操作中,我们包括了判断哪方执步,记录并绘出棋子位置,悔棋三种操作,数据由鼠标点击位置获取

MOUSEMSG m;//鼠标类型的数据
    HWND hwnd;//输出窗口
    hwnd = GetHWnd();
    //鼠标左键点击下棋

五、判断输赢操作实现

对于判断输赢的过程,众所周知五个棋子连在一起即可胜利,在实际游戏中,我们通过最后一个落子与周围的同色棋子是否连着存在五个来判断输赢,这也是我判断输赢的方法,由于实际操作要转换为计算机操作,我们必须在每次下棋后就就执行一次判断(横向判、纵向判断、竖向判断)。

//判断输赢
int judge(int a, int b)
{
    //左右
    for (int i = a - 4, num = 1; i <= a + 4; i++)
    {
        if (i > 17 || i < 0) continue;//排除越界
        if (board[a][b] == board[i][b] && a != i)//一旦相同就加1
            num++;
        else
        {
            if (a != i)//排除循环中自己的比较
                num = 1;
        }
        if (num == 5)
            return 1;
    }
    //上下
    for (int i = b - 4, num = 1; i <= b + 4; i++)
    {
        if (i > 17 || i < 0) continue;//排除越界
        if (board[a][b] == board[a][i] && b != i)//一旦相同就加1
            num++;
        else
        {
            if (b != i)//排除循环中自己的比较
                num = 1;
        }
        if (num == 5)
            return 1;
    }
    //斜右
    for (int i = a - 4, j = b + 4, num = 1; i <= a + 4 && j >= b - 4; i++, j--)
    {
        if (i > 17 || i < 0 || j>17 || j < 0) continue;//排除越界
        if (board[a][b] == board[i][j] && a != i && b != j)//一旦相同就加1
            num++;
        else
        {
            if (a != i && b != j)//排除循环中自己的比较
                num = 1;
        }
        if (num == 5)
            return 1;
    }
    //斜左
    for (int i = a - 4, j = b - 4, num = 1; i <= a + 4 && j <= b + 4; i++, j++)
    {
        if (i > 17 || i < 0 || j>17 || j < 0) continue;//排除越界
        if (board[a][b] == board[i][j] && a != i && b != j)//一旦相同就加1
            num++;
        else
        {
            if (a != i && b != j)//排除循环中自己的比较
                num = 1;
        }
        if (num == 5)
            return 1;
    }
    return 0;
}

该函数主要通过存储在数组中的棋子数据来进行判断;如先前所说,在下棋过程中同时进行比较由于输入数据位与二维数组中,通过二维数组来对棋子是否连成五个或五个以上的结果进行判断,结果只返回是否出现赢家,黑棋或白棋胜利有计数器flag记录判断;

六、悔棋操作实现

对于悔棋的过程,我们只需要记录每次下棋的坐标(通过vector容器)vector <int> a_v; vector <int> b_v;//利用容器记录悔棋位置,a,b分别为x,y坐标

//不使用stack栈结构,因为stl中栈的存储大小有限,容易越界导致bug,不使用队列是因为队列的先进先出的操作不适用与悔棋以及是什么棋子执步即可,但由于需要将操作结果面向用户展示,我需要在图像上进行改变,最简单的方法即直接覆盖棋子同时对flag计数器减一,然后将容器尾部数据删除。

//悔棋
void huiqi(int a,int b){
    clearcircle(a * 25 + 5, b * 25 + 70, 10);//清除区域
    line(a * 25-5 , b * 25 + 70, a * 25+15, b * 25 + 70);//画横着的线
    line(a * 25 +5, b * 25 + 70-10,a * 25 + 5, b * 25 + 70+ 10);//画垂直的线
    board[a][b] = 0;
    flag--;
}

该函数主要是对已知位置(x轴,y轴)执行图像上的清除(准确说是覆盖),主要部分(数据存储)还在下棋函数中

在函数设计时,实际函数中只进行了覆盖的操作,即在图上画一个棕色的椭圆以及横竖线,来“伪造”悔棋的操作。

七、主函数

int main()//主函数  有且仅有一个
{
    InitGame();//初始画图形
    playChess();//调用下棋
    return 0;
}

由于操作主要进行在下棋函数中,所以主函数中只需要使用绘制棋盘函数以及主函数即可

  • 20
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
// MainFrm.cpp : implementation of the CMainFrame class // #include "stdafx.h" #include "五子棋.h" #include "MainFrm.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif HCURSOR m_hcursor; ///////////////////////////////////////////////////////////////////////////// // CMainFrame IMPLEMENT_DYNCREATE(CMainFrame, CFrameWnd) BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) //{{AFX_MSG_MAP(CMainFrame) ON_WM_CREATE() ON_WM_SETCURSOR() //}}AFX_MSG_MAP END_MESSAGE_MAP() static UINT indicators[] = { ID_SEPARATOR, // status line indicator ID_INDICATOR_CAPS, ID_INDICATOR_NUM, ID_INDICATOR_SCRL, }; ///////////////////////////////////////////////////////////////////////////// // CMainFrame construction/destruction CMainFrame::CMainFrame() { // TODO: add member initialization code here } CMainFrame::~CMainFrame() { } int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CFrameWnd::OnCreate(lpCreateStruct) == -1) return -1; if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) || !m_wndToolBar.LoadToolBar(IDR_MAINFRAME)) { TRACE0("Failed to create toolbar\n"); return -1; // fail to create } if (!m_wndStatusBar.Create(this) || !m_wndStatusBar.SetIndicators(indicators, sizeof(indicators)/sizeof(UINT))) { TRACE0("Failed to create status bar\n"); return -1; // fail to create } // TODO: Delete these three lines if you don't want the toolbar to // be dockable m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY); EnableDocking(CBRS_ALIGN_ANY); DockControlBar(&m_wndToolBar); return 0; } BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs) { if( !CFrameWnd::PreCreateWindow(cs) ) return FALSE; // TODO: Modify the Window class or styles here by modifying // the CREATESTRUCT cs return TRUE; } ///////////////////////////////////////////////////////////////////////////// // CMainFrame diagnostics #ifdef _DEBUG void CMainFrame::AssertValid() const { CFrameWnd::AssertValid(); } void CMainFrame::Dump(CDumpContext& dc) const { CFrameWnd::Dump(dc); } #endif //_DEBUG ///////////////////////////////////////////////////////////////////////////// // CMainFrame message handlers BOOL CMainFrame::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) { // TODO: Add your message handler code here and/or call default BOOL br = CFrameWnd::OnSetCursor( pWnd, nHitTest,message) ; if(star==1) { if(flag==1) { m_hcursor= AfxGetApp()->LoadCursor(IDC_hei); SetCursor(m_hcursor); br = TRUE; } else if(flag==2) { m_hcursor= AfxGetApp()->LoadCursor(IDC_bai); SetCursor(m_hcursor); br = TRUE; } } return br; // return CFrameWnd::OnSetCursor(pWnd, nHitTest, message); }
好的,实现五子棋小游戏需要以下几个步骤: 1. 引入 EasyX 头文件和命名空间 ```c++ #include <graphics.h> // 引入 EasyX 头文件 using namespace std; // 使用 std 命名空间 ``` 2. 定义游戏面板和棋子 ```c++ const int BOARD_SIZE = 15; // 游戏面板大小 const int BOARD_LEFT = 50; // 游戏面板左边距 const int BOARD_TOP = 50; // 游戏面板上边距 const int BOARD_BLOCK_SIZE = 40; // 每个格子大小 const int EMPTY = 0; // 空位 const int BLACK = 1; // 黑棋 const int WHITE = 2; // 白棋 int board[BOARD_SIZE][BOARD_SIZE] = {0}; // 游戏面板 ``` 3. 绘制游戏面板和棋子 ```c++ void draw_board() { for (int i = 0; i < BOARD_SIZE; i++) { line(BOARD_LEFT, BOARD_TOP + i * BOARD_BLOCK_SIZE, BOARD_LEFT + (BOARD_SIZE - 1) * BOARD_BLOCK_SIZE, BOARD_TOP + i * BOARD_BLOCK_SIZE); // 绘制横线 line(BOARD_LEFT + i * BOARD_BLOCK_SIZE, BOARD_TOP, BOARD_LEFT + i * BOARD_BLOCK_SIZE, BOARD_TOP + (BOARD_SIZE - 1) * BOARD_BLOCK_SIZE); // 绘制竖线 } for (int i = 0; i < BOARD_SIZE; i++) { for (int j = 0; j < BOARD_SIZE; j++) { if (board[i][j] == BLACK) { setfillcolor(BLACK); solidcircle(BOARD_LEFT + i * BOARD_BLOCK_SIZE, BOARD_TOP + j * BOARD_BLOCK_SIZE, BOARD_BLOCK_SIZE / 2 - 2); // 绘制黑子 } else if (board[i][j] == WHITE) { setfillcolor(WHITE); solidcircle(BOARD_LEFT + i * BOARD_BLOCK_SIZE, BOARD_TOP + j * BOARD_BLOCK_SIZE, BOARD_BLOCK_SIZE / 2 - 2); // 绘制白子 } } } } ``` 4. 判断输赢 ```c++ bool check_win(int x, int y, int color) { int count = 1; // 连子数 int i, j; // 横向 for (i = x - 1; i >= 0 && board[i][y] == color; i--, count++); for (i = x + 1; i < BOARD_SIZE && board[i][y] == color; i++, count++); if (count >= 5) return true; // 纵向 count = 1; for (j = y - 1; j >= 0 && board[x][j] == color; j--, count++); for (j = y + 1; j < BOARD_SIZE && board[x][j] == color; j++, count++); if (count >= 5) return true; // 左斜线 count = 1; for (i = x - 1, j = y - 1; i >= 0 && j >= 0 && board[i][j] == color; i--, j--, count++); for (i = x + 1, j = y + 1; i < BOARD_SIZE && j < BOARD_SIZE && board[i][j] == color; i++, j++, count++); if (count >= 5) return true; // 右斜线 count = 1; for (i = x - 1, j = y + 1; i >= 0 && j < BOARD_SIZE && board[i][j] == color; i--, j++, count++); for (i = x + 1, j = y - 1; i < BOARD_SIZE && j >= 0 && board[i][j] == color; i++, j--, count++); if (count >= 5) return true; return false; } ``` 5. 主函数 ```c++ int main() { initgraph(BOARD_LEFT * 2 + BOARD_SIZE * BOARD_BLOCK_SIZE, BOARD_TOP * 2 + BOARD_SIZE * BOARD_BLOCK_SIZE); // 初始化窗口 draw_board(); // 绘制游戏面板 int x, y; // 当前下棋的坐标 int color = BLACK; // 当前下棋的颜色 bool gameover = false; // 游戏是否结束 while (!gameover) { if (ismouseclick(WM_LBUTTONDOWN)) { // 鼠标左键按下 x = (getmousex() - BOARD_LEFT + BOARD_BLOCK_SIZE / 2) / BOARD_BLOCK_SIZE; y = (getmousey() - BOARD_TOP + BOARD_BLOCK_SIZE / 2) / BOARD_BLOCK_SIZE; if (board[x][y] == EMPTY) { // 检查当前位置是否为空 board[x][y] = color; // 下棋 draw_board(); // 重新绘制游戏面板 if (check_win(x, y, color)) { // 判断是否获胜 gameover = true; settextcolor(color == BLACK ? BLACK : WHITE); outtextxy(BOARD_LEFT, BOARD_TOP + BOARD_SIZE * BOARD_BLOCK_SIZE + 10, color == BLACK ? "黑方胜利!" : "白方胜利!"); // 显示胜利者 } color = color == BLACK ? WHITE : BLACK; // 切换下棋颜色 } clearmouseclick(WM_LBUTTONDOWN); // 清除鼠标左键按下消息 } } getch(); // 等待按键 closegraph(); // 关闭窗口 return 0; } ``` 以上就是使用 EasyX 实现五子棋小游戏的全部内容,你可以将上面的代码复制到 Dev-C++、Visual Studio 等 IDE 中进行编译运行,如果需要修改代码,可以根据注释进行修改。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值