0
点赞
收藏
分享

微信扫一扫

简单的象棋开发

NicoalsNC 2022-03-11 阅读 51
c++c语言

我们需要准备的知识是c语言基础和easyx图形:

easyx官网:

https://easyx.cn/

首先头文件少不了:

#include<stdio.h>(c语言的头文件)
#include<graphics.h>(easyx的)
#include<mmsystem.h>(音乐播放的)
#pragma comment(lib,"winmm.lib")(链接上音乐播放器的库)

 

然后老套路了:

int main(int argc,char *argv[])
{
​
}

创建图形窗口(这里不创建会听到熟悉的声音):

int main(int argc,char *argv[])
{
    initgraph(WIN_WIDTH, WIN_HEIGHT);// (第三个参数SHOWCONSOLE控制控制台窗口的显示与否)
​
}

 

还有个问题图形窗口会闪退:


象棋的属性和一些初始化:

 

#define INTERVAL 50 //前面的间隔
#define CHESS_GRID_SIZE 70//格子宽度
#define ROW 10
#define COL 9
#define WIN_WIDTH ((COL-1)*CHESS_GRID_SIZE+INTERVAL*2+250)
//窗口宽度计算得出
#define WIN_HEIGHT ((ROW-1)*CHESS_GRID_SIZE+INTERVAL*2)
//窗口高度计算得出
IMAGE img_chessBoard;(定义背景图)
void loadImg()(加载背景图)
{
    loadimage(&img_chessBoard, "./res/Chess.jpg", 650, 700);
}
​
enum Pieces //棋子
{
    SPACE = -1,
    車, 馬, 象, 士, 将, 砲, 卒,
    俥, 马, 相, 仕, 帥, 炮, 兵,
    BEGIN, END,
};
//给id赋值
int redChess[] = { 車, 馬, 象, 士, 将, 砲, 卒 };
int blackChess[] = { 俥, 马, 相, 仕, 帥, 炮, 兵 };
//绘制时转化成字符串
const char* ChessName[] = { "車","馬","象","士","将","砲","卒","俥", "马", "相", "仕", "帥", "炮", "兵" };
struct Chess
{
    int id;//棋子名称
    int type;//棋子类型,红棋,还是黑棋
    int x;//坐标
    int y;
    bool river;//是否过了河
}map[ROW][COL];

鼠标的点击初始化:

POINT begin = { -1, -1 }, end = { -1, -1 };//记录前后两次点击的下标
int state = BEGIN;
int whereMove = RED;

 

游戏开始初始化:

void GameInit()
{
    loadImg();
    //遍历二维数组
    for (int i = 0; i < ROW; i++)
    {
        int temp = 0, temp1 = 0, temp2 = 1;
        for (int k = 0; k < COL; k++)
        {
            int chessname = SPACE;
            int mcolor = BLACK;//black黑色
            //黑棋初始化
            if (i <= 4)
            {
                mcolor = BLACK;
                if (i == 0)//第1行
                {
                    if (temp <= 4)
                    {
                        temp++;
                    }
                    else
                    {
                        temp1 = 4 - temp2;
                        temp2++;
                    }
                    chessname = blackChess[temp1];
                    temp1++;
                }
                //设置炮
                if (i == 2 && (k == 1 || k == 7))
                {
                    chessname = blackChess[5];
                }
                //设置小兵
                if (i == 3 && k % 2 == 0)
                {
                    chessname = blackChess[6];
                }
​
            }
            else//红旗初始化
            {
                mcolor = RED;
                if (i == 9)//最后一行
                {
                    if (temp <= 4)
                    {
                        temp++;
                    }
                    else
                    {
                        temp1 = 4 - temp2;
                        temp2++;
                    }
                    chessname = redChess[temp1];
                    temp1++;
                }
                //设置炮
                if (i == 7 && (k == 1 || k == 7))
                {
                    chessname = redChess[5];
                }
                //设置小兵
                if (i == 6 && k % 2 == 0)
                {
                    chessname = redChess[6];
                }
            }
            map[i][k].type = mcolor;
            map[i][k].id = chessname;
            map[i][k].river = false;
            map[i][k].x = k * CHESS_GRID_SIZE + INTERVAL;
            map[i][k].y = i * CHESS_GRID_SIZE + INTERVAL;
​
        }
    }
}

 

游戏绘制:

 

void GameDraw()
{
    setbkcolor(RGB(252, 215, 162));
    cleardevice();
    setlinecolor(BLACK);
    setlinestyle(PS_SOLID, 2);
    setfillcolor(RGB(252, 215, 162));
​
    putimage(0, 0, &img_chessBoard);
​
    //画棋子
    settextstyle(30, 0, "楷体");
    setbkmode(TRANSPARENT);
    for (int i = 0; i < ROW; i++)
    {
        for (int k = 0; k < COL; k++)
        {
            if (map[i][k].id != SPACE)
            {
                if (map[i][k].type == BLACK)
                {
                    settextcolor(BLACK);
                    setlinecolor(BLACK);
                }
                else
                {
                    settextcolor(RED);
                    setlinecolor(RED);
                }
                fillcircle(map[i][k].x, map[i][k].y, 30);
                fillcircle(map[i][k].x, map[i][k].y, 25);
                outtextxy(map[i][k].x - 10, map[i][k].y - 10, ChessName[map[i][k].id]);
            }
        }
    }
    //画点击出现的边框
    if (state == END && map[begin.x][begin.y].id != SPACE)
    {
        setlinecolor(BLUE);
        line(map[begin.x][begin.y].x - 30, map[begin.x][begin.y].y - 30, map[begin.x][begin.y].x + 30, map[begin.x][begin.y].y - 30);
        line(map[begin.x][begin.y].x - 30, map[begin.x][begin.y].y + 30, map[begin.x][begin.y].x + 30, map[begin.x][begin.y].y + 30);
        line(map[begin.x][begin.y].x - 30, map[begin.x][begin.y].y - 30, map[begin.x][begin.y].x - 30, map[begin.x][begin.y].y + 30);
        line(map[begin.x][begin.y].x + 30, map[begin.x][begin.y].y - 30, map[begin.x][begin.y].x + 30, map[begin.x][begin.y].y + 30);
    }
    info();
}

游戏控制:

void KeyControl()
{
    static ExMessage msg;
    if (peekmessage(&msg, EM_MOUSE))
    {
        if (msg.message == WM_LBUTTONDOWN)
        {
            //获取鼠标点击得数组下标
            int row = (msg.y - INTERVAL) / CHESS_GRID_SIZE;
            int col = (msg.x - INTERVAL) / CHESS_GRID_SIZE;
            //if (msg.y > map[row][col].y - 30 && msg.y<map[row][col].y + 30 && msg.x>map[row][col].x - 30 && msg.x < map[row][col].x + 30)
            //{
            //  //在棋子上点击
            //}
            if (msg.x > map[row][col].x + 30 && msg.y < map[row][col].y + 30)
            {
                col++;
            }
            if (msg.x < map[row][col].x + 30 && msg.y > map[row][col].y + 30)
            {
                row++;
            }
            if (msg.x > map[row][col].x + 30 && msg.y > map[row][col].y + 30)
            {
                row++;
                col++;
            }
            if (state == BEGIN)
            {
                printf("begin:(%d,%d)\n", begin.x, begin.y);
                begin.x = row;
                begin.y = col;
                state = END;
            }
            else if (state == END)
            {
                printf("end:(%d,%d)\n", end.x, end.y);
                end.x = row;
                end.y = col;
                state = BEGIN;
            }
        }
    }
}

 

游戏规则:

int check(POINT begin, POINT end)
{
    int _count = 0;
    //水平方向
    int tmax = 0;
    int tmin = 0;
    if (begin.x == end.x)
    {
        tmax = max(begin.y, end.y);
        tmin = min(begin.y, end.y);
        for (int i = tmin + 1; i < tmax; i++)
        {
            if (map[begin.x][i].id != SPACE)
            {
                _count++;
            }
        }
    }
    else if (begin.y == end.y)
    {
        //垂直方向
        tmax = max(begin.x, end.x);
        tmin = min(begin.x, end.x);
        for (int i = tmin + 1; i < tmax; i++)
        {
            if (map[i][begin.y].id != SPACE)
            {
                _count++;
            }
        }
    }
    return _count;
}

 

棋子的移动:

 

void chessMove()
{
    bool isok = false;
    printf("whereMove %d \n", whereMove);
    //点击的不是同一个,以及都有了数据
    if (!(begin.x == end.x && begin.y == end.y) && begin.x != -1 && end.x != -1 && map[begin.x][begin.y].id != SPACE
        && (map[end.x][end.y].id == SPACE || map[end.x][end.y].type != map[begin.x][begin.y].type)
        && map[begin.x][begin.y].type == whereMove)
    {
        POINT general[2] = { 0,3,7,3 };//双方九宫格左上角的位置
        switch (map[begin.x][begin.y].id)
        {
        case Pieces::将:
        case Pieces::帥:
            for (int t = 0; t < 2; t++)
            {
                for (int i = general[t].x; i <= general[t].x + 2; i++)
                {
                    for (int k = general[t].y; k <= general[t].y + 2; k++)
                    {
                        if (end.x == i && end.y == k &&  //结束位置在九宫格内
                            (begin.x == end.x || begin.y == end.y) &&  //结束位置和开始位置,在同一水平或垂直方向(只能走直线)
                            (abs(end.x - begin.x) == 1 || abs(end.y - begin.y) == 1) //一次只能走一格
                            )
                        {
                            isok = true;
                        }
                    }
                }
            }
            break;
        case Pieces::士:
        case Pieces::仕:
            for (int t = 0; t < 2; t++)
            {
                for (int i = general[t].x; i <= general[t].x + 2; i++)
                {
                    for (int k = general[t].y; k <= general[t].y + 2; k++)
                    {
                        if (end.x == i && end.y == k &&  //结束位置在九宫格内
                            (begin.x != end.x && begin.y != end.y) &&  //结束位置和开始位置,不在同一水平或垂直方向(只能走斜线)
                            (abs(end.x - begin.x) == 1 || abs(end.y - begin.y) == 1) //一次只能走一格
                            )
                        {
                            isok = true;
                        }
                    }
                }
            }
            break;
        case Pieces::相:
        case Pieces::象:
            //if ((end.x == begin.x - 2 && end.y == begin.y - 2)
            //  || (end.x == begin.x + 2 && end.y == begin.y - 2)
            //  || (end.x == begin.x - 2 && end.y == begin.y + 2)
            //  || (end.x == begin.x + 2 && end.y == begin.y + 2)
            //  )
            if (abs(end.x - begin.x) == 2 && abs(end.y - begin.y) == 2 && map[end.x][end.y].type == map[begin.x][begin.y].type)
            {
                isok = true;
            }
            break;
        case Pieces::马:
        case Pieces::馬:
            /*if (
                (end.x == begin.x + 1 && end.y == begin.y + 2)
                || (end.x == begin.x + 1 && end.y == begin.y - 2)
                || (end.x == begin.x - 1 && end.y == begin.y + 2)
                || (end.x == begin.x - 1 && end.y == begin.y - 2)
                || (end.x == begin.x + 2 && end.y == begin.y + 1)
                || (end.x == begin.x + 2 && end.y == begin.y - 1)
                || (end.x == begin.x - 2 && end.y == begin.y + 1)
                || (end.x == begin.x - 2 && end.y == begin.y - 1)
                )*/
            if ((abs(end.x - begin.x) == 1 && abs(end.y - begin.y) == 2)
                || (abs(end.x - begin.x) == 2 && abs(end.y - begin.y) == 1))
            {
​
                isok = true;
            }
            break;
        case Pieces::俥:
        case Pieces::車:
            //判断直行
            if (begin.x == end.x || begin.y == end.y)
            {
                //落子位置为空,落子位置和源位置之间没有子挡路
                if (check(begin, end) == 0)
                {
                    isok = true;
                }
            }
            break;
        case Pieces::炮:
        case Pieces::砲:
            //判断直行
            if (begin.x == end.x || begin.y == end.y)
            {
                //落子位置为空,落子位置和源位置之间没有子挡路
                if ((map[end.x][end.y].id == SPACE && check(begin, end) == 0)//走子
                    || (map[end.x][end.y].id != SPACE && check(begin, end) == 1))//吃子
                {
                    isok = true;
                }
                //吃子判断,落子位置有子,落子位置和源位置之间有且只有一个字挡路
            }
            break;
        case Pieces::兵:
        case Pieces::卒:
            //没过河只准向前,不转左右
            if (map[begin.x][begin.y].type == BLACK && begin.x <= 4)
            {
                map[begin.x][begin.y].river = false;
            }
            else if (map[begin.x][begin.y].type == BLACK && begin.x > 4)
            {
                map[begin.x][begin.y].river = true;
            }
            if (map[begin.x][begin.y].type == RED && begin.x >= 5)
            {
                map[begin.x][begin.y].river = false;
            }
            else if (map[begin.x][begin.y].type == RED && begin.x < 5)
            {
                map[begin.x][begin.y].river = true;
            }
​
            //如果没过河,只能向前走
            if (map[begin.x][begin.y].river == false && end.y == begin.y)
            {
                if ((map[begin.x][begin.y].type == BLACK && end.x == begin.x + 1) ||
                    (map[begin.x][begin.y].type == RED && end.x == begin.x - 1))
                {
                    isok = true;
                }
            }//如果过了河,不能往回走
            else if (map[begin.x][begin.y].river == true)
            {
                //如果为黑棋(上方),并且结束位置不小于开始位置
                if (map[begin.x][begin.y].type == BLACK && end.x >= begin.x && (abs(end.x - begin.x) == 1 || abs(end.y - begin.y) == 1))
                {
                    isok = true;
                }//如果为红棋(下方),并且结束位置不大于开始位置
                else if (map[begin.x][begin.y].type == RED && end.x <= begin.x && (abs(end.x - begin.x) == 1 || abs(end.y - begin.y) == 1))
                {
                    isok = true;
                }
            }
            break;
        }
        if (isok == true)
        {
            //落子声音
            mciSendString("close PLAY", 0, 0, 0);
            mciSendString("open ./res/playChess.mp3 alias PLAY", 0, 0, 0);
            mciSendString("play  PLAY", 0, 0, 0);
            map[end.x][end.y].id = map[begin.x][begin.y].id;
        map[end.x][end.y].type =map[begin.x[begin.y].type;
    map[end.x][end.y].river = map[begin.x][begin.y].river;
            //此处有待完善
            map[begin.x][begin.y].id = SPACE;
            //显示哪方行棋
            if (whereMove == RED)
            {
                whereMove = BLACK;
            }
            else
            {
                whereMove = RED;
            }
        }
        //重置点击属性
        //state = BEGIN;
        //begin.x = -1;
        //begin.y = -1;
        //end.x = -1;
        //end.y = -1;
    }
}

判断输赢:

bool JudgeWin()
{
    POINT general[2] = { 0,3,7,3 };//双方九宫格左上角的位置
    int isok = 0;
    for (int t = 0; t < 2; t++)
    {
        for (int i = general[t].x; i <= general[t].x + 2; i++)
        {
            for (int k = general[t].y; k <= general[t].y + 2; k++)
            {
                //统计将领数量,正常为两个
                if (map[i][k].id == 将 || map[i][k].id == 帥)
                {
                    isok++;
                }
            }
        }
    }
    //如果两个首领都在,则未结束,只有一个,则结束
    if (isok == 2)
    {
        return false;
    }
    else
    {
        return true;
    }
}
​

 

main函数的最终写法:

int main(int argc,char *argv[])
{   initgraph(WIN_WIDTH, WIN_HEIGHT);//图像窗口
    GameInit();//初始化
    BeginBatchDraw();//双缓冲
    while (1)//循环绘制
    {
        GameDraw();
        FlushBatchDraw();
        KeyControl();
        chessMove();
        if (JudgeWin() == true)//判断结束弹出窗口
        {
            MessageBox(GetHWnd(), "游戏结束~", "Waring", MB_OK);
            break;
        }
    }
    return 0;
}

 

象棋讲解视频请看:

https://www.bilibili.com/video/BV1tR4y157xD

简单介绍以后编程学习和讲的东西:

1,从C语言开始
基础数据类型,运算符,控制结构,函数,数组,指针,枚举,结构体,联合,文件操作,,动态内存分配
2,数据结构
数组,链表,队列,栈,树,图,常用算 肥婆拉妾数列
3,C++ 
面向对象,类,对象,运算符重载,派生,继承,虚函数,(重点:多态),异常,IO流,STl,正则表达式
4,Windows编程
窗口原理,消息机制,对话框....   
5,windows内核编程
多线程,多进程 注入 hook
6,网络编程
计网,TCP/IP协议栈
7,数据库
MySQL,oracle  SQL语句,SQL注入,
8,Qt跨平台开发
Windows系统 linux系统  ios
9,Linux 黑客必备 运维...
命令 ls shell  
举报

相关推荐

0 条评论