要求使用easy-x实现五子棋的人人对战,键盘操作,显示光标所在位置,落子情况。
我光标的移动是使用清屏来实现的,但是清屏就会清除以前的落子情况,用来输出光标图片的坐标也在变化,不能通过它的参数输出以前的落子,又不知道会下几步棋,于是我放弃了用其他变量输出落子的想法。翻了easy-x的函数库好像又没有可以清除某个指定图片的函数,于是不知道该怎么做下去了。
想知道如何才能实现键盘控制光标标移动,又不会影响落子情况和已绘制的棋盘。
initgraph(480, 540);
loadimage(&bkg, _T("board.jpg"));
loadimage(&cursor, _T("6.png"));
//初始化
int num = 0;
int current_player; //0:黑子 1:白子
int cursor_x, cursor_y; //光标位置
int x, y;
//重置光标
cursor_x = 213;
cursor_y = 213;
putimage(0, 0, 240, 240, &bkg, 60, 60);
putimage(0, 240, 240, 240, &bkg, 60, 60);
putimage(240, 0, 240, 240, &bkg, 60, 60);
putimage(240, 240, 240, 240, &bkg, 60, 60);
setlinecolor(BLACK);
for (x = 15; x < 480; x += 30)
{
line(x, 15, x, 465);
for (y = 15; y < 480; y += 30)
line(15, y, 465, y);
}
setfillcolor(BLACK);
for (int i = 4 * 30 - 15; i <= 12 * 30 - 15; i += 4 * 30)
for (int j = 4 * 30 - 15; j <= 12 * 30 - 15; j += 4 * 30)
fillcircle(i, j, 2.5);
putimage(cursor_x, cursor_y, 26, 26, &cursor, 0, 0); //print cursor
if (1)
current_player = 1;
else
current_player = 2;
//start game
while (1)
{
int key = _getch();
switch (key)
{
case 0XE0:
switch (key = _getch())
{
case 'w':
case 'W':
case 72:if (cursor_y >= 15)
cursor_y -= 30; break;
case 'a':
case 'A':
case 75:if (cursor_x >= 15)
cursor_x -= 30; break;
case 's':
case 'S':
case 80:if (cursor_y <= 452)
cursor_y += 30; break;
case 'd':
case 'D':
case 77:if (cursor_x <= 452)
cursor_x += 30; break;
}
}
cleardevice();
putimage(0, 0, 240, 240, &bkg, 60, 60);
putimage(0, 240, 240, 240, &bkg, 60, 60);
putimage(240, 0, 240, 240, &bkg, 60, 60);
putimage(240, 240, 240, 240, &bkg, 60, 60);
for (x = 15; x < 480; x += 30)
{
line(x, 15, x, 465);
for (y = 15; y < 480; y += 30)
line(15, y, 465, y);
}
for (int i = 4 * 30 - 15; i <= 12 * 30 - 15; i += 4 * 30)
for (int j = 4 * 30 - 15; j <= 12 * 30 - 15; j += 4 * 30)
fillcircle(i, j, 2.5);
putimage(cursor_x, cursor_y, 26, 26, &cursor, 0, 0);
draw_piece(num, cursor_x + 13, cursor_y + 13);
//m = GetMouseMsg();
//if (m.uMsg == WM_LBUTTONDOWN)
//x++;
}
return 0;
}
void draw_piece(int num, int xx ,int yy)
{
if (num == 0)
setfillcolor(BLACK);
else if (num == 1)
setfillcolor(WHITE);
int ch = _getch();
if (ch == 32)
fillcircle(xx, yy, 10);
num = (num + 1) % 2;
}
https://blog.csdn.net/lie_u/article/details/107950505
#include <graphics.h>
#include <conio.h>
#include<stdio.h>
#include <time.h>
#define NUM_B 225 //棋子数量
#define HL 15 //上下
#define X(x) 162+x50
#define Y(y) 30+y50
#define BXY 15 //横轴/纵轴数量
void board(void);
int get_x(short xx);
int get_y(short yy);
int left_right(int(*arr)[BXY], short x, short y); //左右
int up_down(int(*arr)[BXY], short x, short y); //上下
int lu_rd(int(*arr)[BXY], short x, short y); //左上右下
int ld_ru(int(*arr)[BXY], short x, short y); //左下右上
void win_b(void);
void win_w(void);
void fall_w(void); //落白子
void fall_b(void); //落黑子
int main()
{
int undo_x = 0, undo_y = 0;
int again = 0; //用于胜利后开启下一局的开关
int cut = 0; //用于胜利后棋盘不可下棋的开关
int FLAG[BXY][BXY]; //棋盘,储存棋子,0代表空,1代表白子,2代表黑子
int x, y; //坐标
int i, j, wb; //i,j储存鼠标上一个状态,wb控制下一局开局的棋子颜色(这个感觉有没有都一样,,,写了就不删了)
i = j = wb = 0;
int x1[2] = { -2,-2 }, y1[2] = { -2,-2 }; //储存鼠标前后状态,用于消除十字准星
board(); //创建窗口
fall_b();
/* 储存所有棋子坐标,并且把棋子状态设为0 */
for (y = 0; y < 15; y++)
for (x = 0; x < 15; x++)
FLAG[x][y] = 0;
MOUSEMSG m; // 定义鼠标消息
while (true) //游戏无限循环
{
m = GetMouseMsg(); //获取鼠标信息
switch (m.uMsg)
{
case WM_MOUSEMOVE: //鼠标移动
if (cut == 0 && (get_x(m.x) > -1 && get_x(m.x) < 15) && (get_y(m.y) > -1 && get_y(m.y) < 15) && FLAG[get_x(m.x)][get_y(m.y)] < 1) //十字准星
{
// 创建一个矩形区域
HRGN rgn = CreateRectRgn(162, 30, 862, 730);
// 将该矩形区域设置为裁剪区
setcliprgn(rgn);
// 不再使用 rgn,清理 rgn 占用的系统资源
DeleteObject(rgn);
if (i == 0)
{
x1[i] = get_x(m.x);
y1[i] = get_y(m.y);
i = 1;
j = 0;
}
else if (i == 1)
{
x1[i] = get_x(m.x);
y1[i] = get_y(m.y);
i = 0;
j = 1;
}
setfillcolor(LIGHTBLUE);
solidrectangle(X(get_x(m.x)) - 15, Y(get_y(m.y)) - 3, X(get_x(m.x)) + 15, Y(get_y(m.y)) + 3);
solidrectangle(X(get_x(m.x)) - 3, Y(get_y(m.y)) - 15, X(get_x(m.x)) + 3, Y(get_y(m.y)) + 15);
}
break;
case WM_LBUTTONDOWN: //鼠标左键点击
if (cut == 0 && (get_x(m.x) > -1 && get_x(m.x) < 15) && (get_y(m.y) > -1 && get_y(m.y) < 15) && FLAG[get_x(m.x)][get_y(m.y)] < 1)
{
// 取消之前设置的裁剪区
setcliprgn(NULL);
if (wb == 0)
{
setfillcolor(BLACK);
solidcircle(X(get_x(m.x)), Y(get_y(m.y)), 20);
undo_x = get_x(m.x);
undo_y = get_y(m.y);
fall_w();
wb = 1;
FLAG[get_x(m.x)][get_y(m.y)] = 2;
if (left_right(FLAG, m.x, m.y) > 0 || up_down(FLAG, m.x, m.y) > 0 || lu_rd(FLAG, m.x, m.y) > 0 || ld_ru(FLAG, m.x, m.y) > 0)
{
win_b();
again = 1;
cut = 1;
}
}
else if (wb == 1)
{
setfillcolor(WHITE);
solidcircle(X(get_x(m.x)), Y(get_y(m.y)), 20);
undo_x = get_x(m.x);
undo_y = get_y(m.y);
fall_b();
wb = 0;
FLAG[get_x(m.x)][get_y(m.y)] = 1;
if (left_right(FLAG, m.x, m.y) > 0 || up_down(FLAG, m.x, m.y) > 0 || lu_rd(FLAG, m.x, m.y) > 0 || ld_ru(FLAG, m.x, m.y) > 0)
{
win_w();
again = 1;
cut = 1;
}
}
}
break;
case WM_RBUTTONUP: //鼠标右键点击
if (again == 1)
{
for (y = 0; y < 15; y++)
for (x = 0; x < 15; x++)
FLAG[x][y] = 0;
// 取消之前设置的裁剪区
setcliprgn(NULL);
board();
undo_x = undo_y = 0;
again = 0;
cut = 0;
if (wb == 1)
{
wb = 0;
fall_b();
}
else
{
wb = 1;
fall_w();
}
}
else
{
if (FLAG[undo_x][undo_y] == 1)
{
// 取消之前设置的裁剪区
setcliprgn(NULL);
setfillcolor(RGB(209, 186, 116)); //填充背景颜色
solidrectangle(X(undo_x) - 20, Y(undo_y) - 20, X(undo_x) + 20, Y(undo_y) + 20);
line(X(undo_x) - 20, Y(undo_y), X(undo_x) + 20, Y(undo_y));
line(X(undo_x), Y(undo_y) - 20, X(undo_x), Y(undo_y) + 20);
/*9个带黑点的落子位置*/
if (undo_x != 15 && undo_y != 15 && (undo_x + 1) % 4 == 0 && (undo_y + 1) % 4 == 0)
{
setfillcolor(BLACK);
fillcircle(X(undo_x), Y(undo_y), 5);
}
fall_w();
FLAG[undo_x][undo_y] = 0;
wb = 1;
}
else if (FLAG[undo_x][undo_y] == 2)
{
// 取消之前设置的裁剪区
setcliprgn(NULL);
setfillcolor(RGB(209, 186, 116)); //填充背景颜色
solidrectangle(X(undo_x) - 20, Y(undo_y) - 20, X(undo_x) + 20, Y(undo_y) + 20);
line(X(undo_x) - 20, Y(undo_y), X(undo_x) + 20, Y(undo_y));
line(X(undo_x), Y(undo_y) - 20, X(undo_x), Y(undo_y) + 20);
/*9个带黑点的落子位置*/
if (undo_x != 15 && undo_y != 15 && (undo_x + 1) % 4 == 0 && (undo_y + 1) % 4 == 0)
{
setfillcolor(BLACK);
fillcircle(X(undo_x), Y(undo_y), 5);
}
fall_b();
FLAG[undo_x][undo_y] = 0;
wb = 0;
}
}
break;
}
if (((get_x(m.x)) != x1[j] || (get_y(m.y) != y1[j])) && FLAG[x1[j]][y1[j]] < 1)
{
setfillcolor(RGB(209, 186, 116)); //填充背景颜色
solidrectangle(X(x1[j]) - 15, Y(y1[j]) - 15, X(x1[j]) + 15, Y(y1[j]) + 15);
line(X(x1[j]) - 15, Y(y1[j]), X(x1[j]) + 15, Y(y1[j]));
line(X(x1[j]), Y(y1[j]) - 15, X(x1[j]), Y(y1[j]) + 15);
/*9个带黑点的落子位置*/
if (x1[j] != 15 && y1[j] != 15 && (x1[j] + 1) % 4 == 0 && (y1[j] + 1) % 4 == 0)
{
setfillcolor(BLACK);
fillcircle(X(x1[j]), Y(y1[j]), 5);
}
}
}
// 关闭图形窗口
closegraph();
_getch();
return 0;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
}
void board()
{
initgraph(1024, 760); //窗口大小
setbkcolor(RGB(190, 231, 233)); //窗口背景
cleardevice();
setlinecolor(BLACK); //线条颜色
setlinestyle(PS_SOLID | PS_ENDCAP_SQUARE, 2); //棋盘边框线条样式
setfillcolor(RGB(209, 186, 116)); //棋盘背景颜色
fillrectangle(132, 0, 892, 760);
fillrectangle(162, 30, 862, 730); //棋盘大小,棋盘规格15X15
setlinestyle(PS_SOLID | PS_ENDCAP_SQUARE, 2); //棋盘线条样式
for (int i = 80; i <= 730; i += 50) //棋盘横线
line(162, i, 862, i);
for (int i = 212; i <= 862; i += 50) //棋盘竖线
line(i, 30, i, 730);
setfillcolor(BLACK); //圆点填充颜色为黑色
for (int i = 3; i <= 12; i += 4) //绘制9个圆点
{
fillcircle(X(i), Y(3), 5);
fillcircle(X(i), Y(7), 5);
fillcircle(X(i), Y(11), 5);
}
setfillcolor(RGB(190, 237, 199)); //棋盘背景颜色
fillrectangle(20, 310, 115, 425);
settextcolor(BLACK);
settextstyle(25, 0, _T(“Consolas”));
wchar_t s[] = L"请落子";
outtextxy(30, 315, s);
fillrectangle(5, 460, 125, 495);
settextstyle(15, 0, _T("Consolas"));
wchar_t s2[] = L"点击鼠标右键悔棋";
outtextxy(10, 470, s2);
settextstyle(25, 0, _T("Consolas"));
wchar_t s1[] = L"yp_lien";
settextcolor(RGB(214, 213, 183));
outtextxy(930, 730, s1);
1
2
3
4
5
6
7
8
9
}
利用EasyX图形库实现五子棋程序(C语言课程设计
借鉴实用都可以
void GameInit()
{
//利用图形库创建一个窗口
initgraph(500,440);
//添加背景图片,引号前加L是因为要将格式改成多字节字符集
loadimage(NULL,L"Background1.jpg");
setlinecolor(BLACK); //将棋盘线条颜色改为黑色
setlinestyle(PS_SOLID,2);//将线条加粗
//绘制棋盘
line(21,21,21+399,21); //横轴
for(int i=1;i<=20;i++)
{
line(i*21,21,i*21,399+21); //纵轴
line(21,21+i*21,21+399,21+i*21); //横轴
}
settextcolor(BLACK); //将背景字体设置为黑色
setbkmode(0); //将背景字体设置透明
/*显示下棋方*/
outtextxy(435,50,L"玩家1:"); //图形库文字函数(x,y,"显示字符")
outtextxy(465,70,L"黑棋");
outtextxy(435,120,L"玩家2:");
outtextxy(465,140,L"白棋");
outtextxy(435,220,L"Esc:"); //
outtextxy(435,240,L"退出游戏"); //
}
int playChess(void) //鼠标下棋函数
{
//鼠标右键点击
MOUSEMSG Mouse; //鼠标结构体变量
/*a,b为二维数组号,x,y为当前鼠标点击的坐标*/
int a = 0;
int b = 0;
int x = 0;
int y = 0;
HWND hwnd; //窗口句柄
hwnd = GetHWnd();//窗口置前
int ret = 0; //判断游戏是否结束标志
int KeyRet = 0; //键盘判断是否退出游戏
int Key = 0; //用作键盘热键判断的变量
while(1)
{
Mouse = GetMouseMsg(); //获取一个鼠标消息
Key = GetAsyncKeyState(VK_ESCAPE);//获取Esc键状态,若按下返回-127或-128
if(Key<0) //判断获取键盘的信息,若键盘按下Esc,Key值小于0,则退出游戏
{
KeyRet = MessageBox(hwnd,L"是否想退出游戏?",L"提示",MB_YESNO|MB_ICONINFORMATION); //MB_YESNO显示选项,MB_ICONINFORMATION为提示字前方图标
if(KeyRet==IDYES) //判断是否想重新开始一局游戏
{
exit(0); //退出程序
}
}
//下棋时鼠标点击横纵轴交点,用绝对值将点击的x,y坐标值取整,使鼠标点击规定的棋盘位置(向右向下偏移1格)
for(int i = 1;i<21; i++)
{
for(int j = 1;j<21; j++)
{
if(abs(Mouse.x-i*21)<11&&abs(Mouse.y-j*21)<11) //将点击的范围内的值取整
{
a = i; //行列号
b = j;
x = i*21; //坐标
y = j*21;
}
}
}
if(Mouse.uMsg == WM_LBUTTONDOWN) //判断当前鼠标左键是否按下
{
if(board[a][b]!=0) //有棋子
{
MessageBox(hwnd,L"此处已有棋子,请重新选择下棋点",L"五子棋",MB_OK); //MB_OK为确定键
//退出循环
continue;
}
if(flag % 2==0) //取余
{
setfillcolor(BLACK); //棋子颜色设置黑色
solidcircle(x,y,10); //画黑色棋子
board[a][b] = 1; //给数组赋值黑棋色号
}
else
{
setfillcolor(WHITE); //棋子颜色设置白色
solidcircle(x,y,10); //画白色棋子
board[a][b] = 2; //给数组赋值白棋色号
}
flag++; //下棋手判断
if(flag>=400) //当棋盘下满时,平局。(0 - 399)
{
MessageBox(hwnd,L"本局平局",L"游戏结束",MB_OK); //MB_OK为确定键
if(ret==IDYES) //判断是否想重新开始一局游戏
{
flag = 0; //用来记录轮到哪个人下棋
memset(board,0,sizeof(board)); //清空数组
break;
}
else //不重新开始,退出程序
{
exit(0); //退出程序
}
}
}
if(JudgeWin(a,b)) //找到了五子连成一条线
{
if(flag % 2 ==1)
{
MessageBox(hwnd,L"玩家1(黑棋)胜利",L"游戏结束",MB_OK); //MB_OK为确定键
}
else
{
MessageBox(hwnd,L"玩家2(白棋)胜利",L"游戏结束",MB_OK); //MB_OK为确定键
}
ret = MessageBox(hwnd,L"是否想重新开始一局游戏?",L"提示",MB_YESNO|MB_ICONINFORMATION); //MB_YESNO显示选项,MB_ICONINFORMATION为提示字前方图标
if(ret==IDYES) //判断是否想重新开始一局游戏
{
flag = 0; //用来记录轮到哪个人下棋
memset(board,0,sizeof(board)); //清空数组
break;
}
else //不重新开始,退出程序
{
exit(0); //退出程序
}
}
}
return 0;
}
//判断输赢
int JudgeWin(int a,int b)
{
/*
算法逻辑:以当前下棋点为原点,
1.以x轴(a - 4) - (a + 4),开始检测连续点,若连续点>=5,则判定win
2.以y轴a不变,(b - 4) - (b + 4),开始检测连续点,若连续点>=5,则判定win
3.以y = x轴,(a - 4) - (a + 4),(b - 4) - (b + 4),开始检测连续点,若连续点>=5,则判定win
4.以y = -x轴,(a - 4) - (a + 4),(b + 4) - (b - 4),开始检测连续点,若连续点>=5,则判定win
*/
int i = 0;
int j = 0;
int Cont_i = 0; //连续棋子数
int t = 2 - flag % 2; //判定此次所下棋子色号
//x轴判断
for(i = ContLimit(a - 4);i <= ContLimit(a + 4);i++) //i值范围:(a - 4)至(a + 4)
{
j = b;
if(board[i][j] != t) //若不是当前下的棋子色号
{
Cont_i = 0; //连续棋子数清零
}
else if(board[i][j] == t) //若是当前下的棋子色号
{
Cont_i+=1;
}
if(Cont_i>=5) //若连续棋子数大于等于5
{
return 1; //返回1,判定胜利
}
}
Cont_i = 0; //x轴判定未胜利,连续棋子数清零,进行y轴判定
//y轴判断
for(j = ContLimit(b - 4);j <= ContLimit(b + 4);j++) //j值范围:(b - 4)至(b + 4)
{
i = a;
if(board[i][j] != t) //若不是当前下的棋子色号
{
Cont_i = 0; //连续棋子数清零
}
else if(board[i][j] == t) //若是当前下的棋子色号
{
Cont_i+=1;
}
if(Cont_i>=5) //若连续棋子数大于等于5
{
return 1; //返回1,判定胜利
}
}
Cont_i = 0; //x轴判定未胜利,连续棋子数清零,进行y轴判定
//y = x判断
for(i = ContLimit(a - 4),j = ContLimit(b - 4);i <= ContLimit(a + 4) && j <= (b + 4);i++,j++) //i值范围:(a - 4)至(a + 4),j值范围:(b - 4)至(b + 4)
{
//i = a;
if(board[i][j] != t) //若不是当前下的棋子色号
{
Cont_i = 0; //连续棋子数清零
}
else if(board[i][j] == t) //若是当前下的棋子色号
{
Cont_i+=1;
}
if(Cont_i>=5) //若连续棋子数大于等于5
{
return 1; //返回1,判定胜利
}
}
Cont_i = 0; //x轴判定未胜利,连续棋子数清零,进行y轴判定
//y = -x判断
for(i = ContLimit(a - 4),j = ContLimit(b + 4);i <= ContLimit(a + 4) && j >= ContLimit(b - 4);i++,j--) //i值范围:(a - 4)至(a + 4),j值范围:(b + 4)至(b - 4)
{
//i = a;
if(board[i][j] != t) //若不是当前下的棋子色号
{
Cont_i = 0; //连续棋子数清零
}
else if(board[i][j] == t) //若是当前下的棋子色号
{
Cont_i+=1;
}
if(Cont_i>=5) //若连续棋子数大于等于5
{
return 1; //返回1,判定胜利
}
}
return 0;
}
int ContLimit(int n) //用来限制二维数组a,b的值 其范围在1 - 20
{
if(n>20) //若输入数据大于20
{
return 20; //返回20
}
else if(n<0) //若输入数据小于0
{
return 0; //返回0
}
else //若不满足以上条件,返回原值
{
return n;
}
return n;
}
可以使用 easy-x 库中的函数 getch 来实现键盘控制光标的移动。以是一个示例代码,它可以帮助你在控制台中控制光标的移动:
#include <stdio.h>
#include <conio.h>
int main(void)
{
char ch;
int x = 0, y = 0;
printf("Press arrow keys to move the cursor.\n");
while (1)
{
ch = getch();
if (ch == 0 || ch == 0xE0) // Special keys
{
ch = getch();
if (ch == 72) // Up arrow
{
if (y > 0) y--;
}
else if (ch == 80) // Down arrow
{
if (y < 24) y++;
}
else if (ch == 75) // Left arrow
{
if (x > 0) x--;
}
else if (ch == 77) // Right arrow
{
if (x < 79) x++;
}
}
// Move the cursor to the new position
printf("\033[%d;%dH", y + 1, x + 1);
}
return 0;
}
在这段代码中,我们使用了 getch 函数来获取键盘输入。当用户按下方向键时,我们会检测到特殊键的输入,并根据按键的不同来更新光标的位置。最后,我们使用 ANSI 控制码来移动光标到新的位置。
你可以在五子棋游戏的主循环中使用类似的方法来控制光标的移动,并在绘制棋盘时考虑光标的位置。