中国象棋是中国一种流传十分广泛的游戏。 下棋双方根据自己对棋局形式的理解和对棋艺规律的掌握,调动车马,组织兵力,协调作战在棋盘这块特定的战场上进行着象征性的军事战斗。 象棋,亦作“象碁”,为了区别“国际象棋”也作“中国象棋”,中国象棋在中国有着悠久的历史,属于二人对抗性游戏的一种,由于用具简单,趣味性强,成为流行极为广泛的棋艺活动。

游戏规则

行棋规则:

棋子行棋规则帅/将移动范围:只能在九宫内移动移动规则:每一步只可以水平或垂直移动一点特殊规则:帅和将不准在同一直线上直接对面(中间无棋子),如一方已先占据位置,则另一方必须回避,否则就算输仕/士移动范围:只能在九宫内移动移动规则:每一步只可以沿对角线方向移动一点相/象移动范围:河界的一侧移动规则:每一步只可以沿对角线方向移动两点,可使用汉字中的田字形象地表述:田字格的对角线,俗称相(象)走田字。当相(象)行走路线中,即田字中心有棋子时(无论己方或是对方棋子),则不允许走过去,俗称:塞相(象)眼。馬移动范围:任何位置移动规则:每一步只可以水平或垂直移动一点,再按对角线方面向左或者右移动。可使用汉字中的日字来形容马的行走方式,俗称:马走日字(斜对角线)。当馬行走时,第一步直行或横行处有别的棋子(无论己方或是对方棋子)挡住,则不许走过去,俗称:蹩马腿。車移动范围:任何位置移动规则:可以水平或垂直方向移动任意个无阻碍的点炮/砲移动范围:任何位置移动规则:移动起来和车很相似,但它必须跳过一个棋子来吃掉对方棋子。兵/卒移动范围:任何位置移动规则:过河界前,每步只能向前移动一点。过河界后,增加了向左右移动的能力,兵(卒)不允许向后移动。

吃子规则:

无论什么棋子,通常只要根据行棋规则能走到的部位有对方的棋子就能吃掉对方的棋子。

唯一例外的是炮的吃棋方法,比较特殊,需要中间隔有棋子(无论是己方或对方棋子)才能吃掉对方的棋子。

胜负判定:

帅(将)被对方“将死”或“困毙”一方算输。

宣布认输的一方算输。

今天我就用C语言带大家一步步去完成好玩有趣学会就能和朋友对弈的中国象棋小游戏。

PS:要安装easyx图形库哦 #include<easyx.h>

开发工具为VS2013

在此之前呢,和大家说明一下,因为这是一个比较大的项目了,所以展示所有代码会有些困难,所以我裁剪了主要的大部分代码,主要目的是让大家明白实现这个项目的逻辑思路,希望大家可以理解

第一步:创建一个项目,并将准备好的素材资源(文末获取)放到同级目录下如图:

第二步:接下来就是我们的主要函数main.Cpp了,创建一个窗口再贴上棋盘图,加上双缓冲绘图防止闪屏:

int main()
{
//创建图形窗口
initgraph(740, 820,EW_SHOWCONSOLE);
//设置背景模式
setbkmode(TRANSPARENT);
//贴棋盘
IMAGE img_board;
loadimage(&img_board, "./res/ChessBoard.png"); init();
//双缓冲绘图,防止闪屏
BeginBatchDraw();
while (true)
{
cleardevice();
putimage(0, 0, &img_board);
draw();
mouseEvent(); FlushBatchDraw();
}
EndBatchDraw(); getchar();
return 0;
}

第三步:利用绘图找到各个点的坐标并绘制棋子,以及黑红棋子及棋子过河等:

enum Pieces //棋子
{
NONE = -1,
車, 馬, 象, 士, 将, 砲, 卒,
俥, 马, 相, 仕, 帥, 炮, 兵,
BEGIN, END,
};
//给id赋值
enum Pieces redChess[] = { 車, 馬, 象, 士, 将, 砲, 卒 };
enum Pieces blackChess[] = { 俥, 马, 相, 仕, 帥, 炮, 兵 };
//绘制时转化成字符串
const char* ChessName[] = { "車","馬","象","士","将","砲","卒","俥", "马", "相", "仕", "帥", "炮", "兵" }; //每一个棋子的属性
struct Chess
{
enum Pieces id; //棋子名称
DWORD type; //棋子类型,红?黑?
short x;
short y;
bool isRiver; //是否过了河
};

第四步:宏定义#define ROW 10 #define COL 9 绘制十列九行的地图,并初始化数据,设置棋子的特殊移动规则:

//游戏地图
struct Chess map[ROW][COL]; struct State
{
int begr;
int begc;
int endr;
int endc;
int state;
}state = {-1,-1,-1,-1,BEGIN}; void chessMove();
//打印数组
void show()
{
for (size_t i = 0; i < ROW; i++)
{
for (size_t k = 0; k < COL; k++)
{
printf("%2d ", map[i][k].id);
}
printf("\n");
}
}
//初始化数据
void init()
{
//遍历地图
for (size_t i = 0; i < ROW; i++)
{
size_t temp = 0;
for (size_t k = 0; k < COL; k++)
{
map[i][k].id = NONE; //先把棋子置为没有
if (i <= 4) //黑棋子
{
map[i][k].type = BLACK;
if (i == 0) //放置第一行的棋子
{
//0 1 2 3 4
if (k <= 4)
{
temp = k;
}
// 3 2 1 0
else
{
// k == 5
temp = 4 - (k - 4);
/*
4 - (5-4) //3
4 - (6-4) //2
4 - (7-4) //1
4 - (8-4) //0
*/
}
map[i][k].id = blackChess[temp];
}
//设置炮
if (i == 2 && (k == 1 || k == 7))
{
map[i][k].id = blackChess[5];
}
//设置兵
if (i == 3 && k % 2 == 0)
{
map[i][k].id = blackChess[6];
}
}
else //红棋
{
map[i][k].type = RED;
if (i == 9) //放置第一行的棋子
{
//0 1 2 3 4
if (k <= 4)
{
temp = k;
}
// 3 2 1 0
else
{
// k == 5
temp = 4 - (k - 4);
/*
4 - (5-4) //3
4 - (6-4) //2
4 - (7-4) //1
4 - (8-4) //0
*/
}
map[i][k].id = redChess[temp];
}
//设置炮
if (i == 7 && (k == 1 || k == 7))
{
map[i][k].id = redChess[5];
}
//设置兵
if (i == 6 && k % 2 == 0)
{
map[i][k].id = redChess[6];
}
}
map[i][k].isRiver = false;
map[i][k].x = k * GRID_SIZE + INTERVAL;
map[i][k].y = i * GRID_SIZE + INTERVAL;
}
}
}
//绘制
void draw()
{
setfillcolor(RGB(252, 215, 162));
setlinestyle(PS_SOLID, 2);
//设置文字的样式
settextstyle(30, 0, "楷体");
for (size_t i = 0; i < ROW; i++)
{
for (size_t k = 0; k < COL; k++)
{
if (map[i][k].id == NONE)
continue;
settextcolor(map[i][k].type);
setlinecolor(map[i][k].type);
//绘制棋子
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 - 15, map[i][k].y - 15, ChessName[map[i][k].id]);
}
}
}

第五步:设置获取鼠标操作:

//鼠标操作
void mouseEvent()
{
ExMessage msg; //定义消息结构体变量
if(peekmessage(&msg, EM_MOUSE))
{
if (msg.message == WM_LBUTTONDOWN) //鼠标左键按下
{
//通过鼠标坐标得出点击的数组的下标
//k * GRID_SIZE + INTERVAL = x;
int col = (msg.x - INTERVAL) / GRID_SIZE;
int row = (msg.y - INTERVAL) / GRID_SIZE; //下标校准
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++;
}
//printf("(%d %d)\n", row, col); if (state.state == BEGIN)
{
state.begr = row;
state.begc = col;
state.state = END;
}
else if (state.state == END)
{
state.endr = row;
state.endc = col;
state.state = BEGIN;
}
chessMove();
}
}
}
int hasBlock(struct State* state)
{
int cnt = 0;
state->begr;
state->begc;
state->endr;
state->endc; */ return cnt;
}

第六步:设置棋子的移动:

//移动棋子
void chessMove()
{
printf("beg(%d %d) end(%d %d)\n", state.begr, state.begc, state.endr, state.endc);
bool canMove = false;
//什么情况下能够移动棋子
if (!(state.begr == state.endr && state.begc == state.endc) && //点击的不是同一个棋子
state.endr!=-1 && state.begr!=-1&& //下标必须合法
map[state.begr][state.begc].id != NONE//没有棋子不能移动
/*&&map[state.begr][state.begc].type != map[state.endr][state.endc].type*/) //不能自己吃自己
{ switch (map[state.begr][state.begc].id)
{
case 車:
case 俥:
if (state.begr == state.endr || state.begc == state.endc)
{
//起始点和结束点之间是否有阻碍
if (hasBlock(&state))
{
canMove = true;
} }
break;
case 馬:
case 马:
break;
case 象:
case 相:
break;
case 士:
case 仕:
break;
case 将:
case 帥:
break;
case 砲:
case 炮:
break;
case 卒:
case 兵:
break;
default:
break;
}
if (canMove)
{
printf("canMove\n");
map[state.endr][state.endc].id = map[state.begr][state.begc].id;
map[state.begr][state.begc].id = NONE; map[state.endr][state.endc].isRiver = map[state.begr][state.begc].isRiver;
map[state.endr][state.endc].type = map[state.begr][state.begc].type;
}
}
}

中国象棋的教程就到此结束啦,有兴趣的同学可以尝试写出来,后续我会发布更多的项目教程,希望大家可以持续关注,希望大家可以在这里得到自己想要的知识,也希望如果对你有所帮助的话可以多多关注点赞评论,有建议也可以在评论区提出,谢谢大家的支持,大家也可以多逛逛我的主页!

搜索

复制

C/C++游戏项目:中国程序员一定要会的中国象棋教程的更多相关文章

  1. [转]ThoughtWorks(中国)程序员读书雷达

    http://agiledon.github.io/blog/2013/04/17/thoughtworks-developer-reading-radar/#rd?sukey=f64bfa68330 ...

  2. 第一章-第七题( 有人认为,“中文编程”, 是解决中国程序员编程效率一个秘密武器,请问它是一个 “银弹” 么? )--By 侯伟婷

    首先,“银弹”在百度百科中的解释是银色的子弹,我们更熟知的“银弹”一词,应该是在<人月神话>中提到的.银弹原本应该是指某种策略.技术或者技巧可以极大地提高程序员的生产力[1].此题目中关于 ...

  3. 【转载】张逸--ThoughtWorks(中国)程序员读书雷达

    原文地址:ThoughtWorks(中国)程序员读书雷达 软件业的特点是变化.若要提高软件开发的技能,就必须跟上技术发展的步伐.埋首醉心于项目开发与实战,固然能够锤炼自己的开发技巧,却难免受限于经验与 ...

  4. 远程办公《Remote》读书笔记:中国程序员在家上班月入过六万不是梦

    这不是一本新书,这是一本很值得中国程序员看的老书,所以我不是来做卖新书广告的:) 但它的确是一本好书,这本书在Amazon上3个business categories排第一.作者Jason Fried ...

  5. ThoughtWorks(中国)程序员读书雷达 —— 书籍下载整理

    ThoughtWorks(中国)程序员读书雷达 http://agiledon.github.io/blog/2013/04/17/thoughtworks-developer-reading-rad ...

  6. ThoughtWorks(中国) 程序员读书雷达

    ThoughtWorks(中国)程序员读书雷达 软件业的特点是变化.若要提高软件开发的技能,就必须跟上技术发展的步伐.埋首醉心于项目开发与实战,固然能够锤炼自己的开发技巧,却难免受限于经验与学识.世界 ...

  7. 中国程序员容易发错音的单词「GitHub 热点速览 v.22.23」

    中国程序员容易发错音的单词,像极了学生时代的纠错本,收录着偶尔会忘记的单词.不过,它似乎更新频率跟不上我们的进步速度,至少一半以上的单词读起来是没有压力的.同样没有压力的还有让应用程序动起来的 aut ...

  8. 对程序员的不尊重是中国it产业的悲哀。

    电脑刚进入中国时,“程序员”三个字是一份令人尊敬的岗位,那个时候中国互联网人才奇缺.程序员的价格也就水涨船高.小的时候电视里到处播放着电脑培训学院的招生广告.一说到程序员,给我们的印象都是白领,高薪的 ...

  9. 推荐:ThoughtWorks(中国)程序员读书雷达

    部分转自张逸的博客:http://agiledon.github.io/blog/2013/04/17/thoughtworks-developer-reading-radar/ 长久以来一直对程序员 ...

随机推荐

  1. Makefile学习(一)

       objects = main.o kbd.o command.o display.o \              insert.o search.o files.o utils.o       ...

  2. C++ TCHAR* 与char* 互转

    C++ TCHAR* 与char* 互转 在MSDN中有这么一段: Note: The ANSI code pages can be different on different computers, ...

  3. Linux 性能调优都有哪几种方法?

    1.Disabling daemons (关闭 daemons).    2.Shutting down the GUI (关闭 GUI).    3.Changing kernel paramete ...

  4. 一台 Linux 系统初始化环境后需要做一些什么安全工作?

    1.添加普通用户登陆,禁止 root 用户登陆,更改 SSH 端口号.        修改 SSH 端口不一定绝对哈.当然,如果要暴露在外网,建议改下.l    2.服务器使用密钥登陆,禁止密码登陆. ...

  5. Dubbo 如何优雅停机?

    Dubbo 是通过 JDK 的 ShutdownHook 来完成优雅停机的,所以如果使用 kill -9 PID 等强制关闭指令,是不会执行优雅停机的,只有通过 kill PID 时,才 会执行.

  6. Oracle入门基础(十一)一一PL/SQL基本语法

    1.打印Hello World declare --说明部分 begin --程序 dbms_output.put_line('Hello World'); end; 2.引用型变量 查询并打印783 ...

  7. 什么是 AQS ?

    AQS 是 AbustactQueuedSynchronizer 的简称,它是一个 Java 提高的底层同步工具类,用一个 int 类型的变量表示同步状态,并提供了一系列的 CAS 操作来管理这个同步 ...

  8. MariaDB 存储引擎一览(官方文档翻译)

    inline-translate.translate { } inline-translate.translate::before, inline-translate.translate::after ...

  9. 如何设置出IDEA中VCS下的Enable Version Control Intergration

    File–>settings–>Version Control

  10. fsdfd

    static int kWeiOfVal(int val, int k) { int n = 1; int temVal = val; int result; while (1) { temVal = ...