简单的象棋开发
我们需要准备的知识是c语言基础和easyx图形库
首先头文件少不了:
#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控制控制台窗口的显示与否)
}
还有个问题图形窗口会闪退:
所以我们需要阻塞窗口`:
while (1)
{
;
}
或者:
getchar();
象棋的属性和一些初始化:
#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;
如果(开始。x == 结束。(十)
{
tmax = max(begin.是的,结束。y);
tmin = min(begin.是的,结束。y);
for (int i = tmin + 1; i < tmax; i++)
{
if (map[begin.x][i].id != 空格)
{
_count++;
}
}
}
否则如果(开始。y == 结束。y)
{
垂直方向
tmax = max(begin.x,结束。x);
tmin = min(begin.x,结束。x);
for (int i = tmin + 1; i < tmax; i++)
{
if (map[i][begin.y].id != 空格)
{
_count++;
}
}
}
返回_count;
}
棋子的移动:
void chessMove()
{
布尔 isok = 假;
printf("whereMove %d \n", whereMove);
点击的不是同一个,以及都有了数据
如果 (!(开始。x == 结束。x && begin.y == 结束。y) &&begin.x != -1 && end.x != -1 && map[begin.x][begin.y].id != 空格
&& (map[end.x][end.y].id == 空格||map[end.x][end.y].键入 != map[begin.x][begin.y].。类型)
&& map[begin.x][begin.y].类型 == 其中移动)
{
POINT general[2] = { 0,3,7,3 };//双方九宫格左上角的位置
switch (map[begin.x][begin.y].(id)
{
案例件数::将:
表壳件数::帥:
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 <= 一般[t].y + 2;k++)
{
如果(结束。x == i && end.y == k && //结束位置在九宫格内
(开始。x == 结束。x ||开始。y == 结束。y) && ///结束位置和开始位置,在同一水平或垂直方向(只能走直线)
(腹肌(结束。x - 开始。x) == 1 ||腹肌(结束。y - 开始。y) == 1) //一次只能走一格
)
{
isok = true;
}
}
}
}
休息;
表壳片: :士:
表壳片::仕:
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 <= 一般[t].y + 2;k++)
{
如果(结束。x == i && end.y == k && //结束位置在九宫格内
(开始。x != 结束。x && begin.y != 结束。y) && ///结束位置和开始位置,不在同一水平或垂直方向(只能走斜线)
(腹肌(结束。x - 开始。x) == 1 ||腹肌(结束。y - 开始。y) == 1) //一次只能走一格
)
{
isok = true;
}
}
}
}
休息;
案例件数::相:
表壳件::象:
如果 ((结束。x == 开始。x - 2 && end.y == 开始。y - 2)
// ||(完。x == 开始。x + 2 && end.y == 开始。y - 2)
// ||(完。x == 开始。x - 2 && end.y == 开始。y + 2)
// ||(完。x == 开始。x + 2 && end.y == 开始。y + 2)
// )
如果 (abs(结束。x - 开始。x) == 2 && abs(结束。y - 开始。y) == 2 && map[end.x][end.y].type == map[begin.x][begin.y].。类型)
{
isok = true;
}
休息;
表壳件::马:
表壳片::马:
/*如果 (
(完。x == 开始。x + 1 && end.y == 开始。y + 2)
||(完。x == 开始。x + 1 && end.y == 开始。y - 2)
||(完。x == 开始。x - 1 && end.y == 开始。y + 2)
||(完。x == 开始。x - 1 && end.y == 开始。y - 2)
||(完。x == 开始。x + 2 && end.y == 开始。y + 1)
||(完。x == 开始。x + 2 && end.y == 开始。y - 1)
||(完。x == 开始。x - 2 && end.y == 开始。y + 1)
||(完。x == 开始。x - 2 && end.y == 开始。y - 1)
)*/
如果 ((abs(结束。x - 开始。x) == 1 && abs(结束。y - 开始。y) == 2)
||(腹肌(结束。x - 开始。x) == 2 && abs(结束。y - 开始。y) == 1))
{
isok = true;
}
休息;
表壳件数::俥:
表壳件数::車:
判断直行
如果(开始。x == 结束。x ||开始。y == 结束。y)
{
落子位置为空,落子位置和源位置之间没有子挡路
if (check(begin, end) == 0)
{
isok = true;
}
}
休息;
案例片数::炮:
表壳件数::砲:
判断直行
如果(开始。x == 结束。x ||开始。y == 结束。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;
}
吃子判断,落子位置有子,落子位置和源位置之间有且只有一个字挡路
}
休息;
案例片::兵:
表壳件数::卒:
没过河只准向前,不转左右
if (map[begin.x][begin.y].类型 == 黑色 && 开始。x <= 4)
{
map[begin.x][begin.y].河流 = 假;
}
else if (map[begin.x][begin.y].类型 == 黑色 && 开始。x > 4)
{
map[begin.x][begin.y].河流 = 真;
}
if (map[begin.x][begin.y].键入 == RED && begin。x >= 5)
{
map[begin.x][begin.y].河流 = 假;
}
else if (map[begin.x][begin.y].键入 == RED && begin。x < 5)
{
map[begin.x][begin.y].河流 = 真;
}
如果没过河,只能向前走
if (map[begin.x][begin.y].河流 == 假 && 结束。y == 开始。y)
{
if ((map[begin.x][begin.y].类型 == 黑色 && 结束。x == 开始。x + 1) ||
(map[begin.x][begin.y].。type == RED && end.x == 开始。x - 1))
{
isok = true;
}
}//如果过了河,不能往回走
else if (map[begin.x][begin.y].河流 == 真)
{
如果为黑棋(上方),并且结束位置不小于开始位置
if (map[begin.x][begin.y].类型 == 黑色 && 结束。x > = 开始。x && (abs(end.x - 开始。x) == 1 ||腹肌(结束。y - 开始。y) == 1))
{
isok = true;
}//如果为红棋(下方),并且结束位置不大于开始位置
else if (map[begin.x][begin.y].type == RED && end.x < = 开始。x && (abs(end.x - 开始。x) == 1 ||腹肌(结束。y - 开始。y) == 1))
{
isok = true;
}
}
休息;
}
if (isok == true)
{
落子声音
mciSendString("close PLAY", 0, 0, 0);
mciSendString("open ./res/playChess.mp3 别名播放", 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].键入 =map[开始。x[开始。y]。类型;
map[end.x][end.y].river = map[begin.x][begin.y].。河流;
此处有待完善
map[begin.x][begin.y].id = 空间;
显示哪方行棋
if (其中Move == RED)
{
其中移动 = 黑色;
}
还
{
其中移动 = 红色;
}
}
重置点击属性
状态 = 开始;
开始。x = -1;
开始。y = -1;
结束。x = -1;
结束。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;
}