c语言课设_五子棋(有单人模式200多行)

这个五子棋,有单人模式和双人模式,完全是c语言写的,所以其实就是只有一些基本逻辑,但是我也经常输,hhhh。(半年前写的,有很多地方看起来就,所以想优化一下,hhhh)
![image.png](https://img-blog.csdnimg.cn/img_convert/71b7f5c380c638d2dd348561787e6ad7.png#clientId=u43ae87d1-2467-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=318&id=u105f9f72&margin=[object Object]&name=image.png&originHeight=1269&originWidth=1202&originalType=binary&ratio=1&rotation=0&showTitle=false&size=1928519&status=done&style=none&taskId=u6dc55f5b-4949-45e2-8529-fa1685bf0ef&title=&width=301)

整体思路

用一个数组维护棋盘的棋子,例如,-1为白棋,1为黑棋,0为无棋每次下完棋都根据数组展示一下棋盘。(当然是用鼠标)。

用户界面

![image.png](https://img-blog.csdnimg.cn/img_convert/ae60d125472e254d448cdc5380efaf01.png#clientId=u43ae87d1-2467-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=401&id=ub778ad71&margin=[object Object]&name=image.png&originHeight=802&originWidth=1204&originalType=binary&ratio=1&rotation=0&showTitle=false&size=1470206&status=done&style=none&taskId=u9ea2d9b0-9c0b-458f-9887-ecb6ba85eca&title=&width=602)
这里的单人模式和双人模式是打字的看上去就不是很好看,其实可以用图片来代替一下,看清来就不会像这个看起来那么难受。![image.png](https://img-blog.csdnimg.cn/img_convert/99d04ee950a4d8134357b256d8679d0f.png#clientId=u43ae87d1-2467-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=398&id=u774d060b&margin=[object Object]&name=image.png&originHeight=795&originWidth=1209&originalType=binary&ratio=1&rotation=0&showTitle=false&size=1481029&status=done&style=none&taskId=ud49af197-f392-4ade-8215-bb8f253937b&title=&width=605)好像看起来更丑了,,,,,但是我感觉是因为图片没找好。修改后的代码。

void menu()
{
	for (int x = 0; x < 30; x++)for (int y = 0; y < 30; y++)qizi[x][y] = 100;
	for (int x = 6; x < 25; x++)for (int y = 0; y < 25; y++)qizi[x][y] = 0;
	initgraph(800, 496, EW_SHOWCONSOLE);
	setbkcolor(WHITE);
	cleardevice();
	IMAGE x,a1,a2,b1,b2;
	ExMessage c;
	setfillcolor(RGB(137, 207, 180));
	settextcolor(BLUE);
	settextstyle(35, 20, "微软雅黑");
	loadimage(&x, "hhh.jpg");
	loadimage(&a1, "单人模式按钮图片.png");
	loadimage(&a2, "单人模式按钮图片2.png");
	loadimage(&b1, "双人模式按钮.png");
	loadimage(&b2, "双人模式按钮2.png");
	BeginBatchDraw();
	putimage(0, 0, &x);
	transparentimage(200, 350, &a2, &a1);
	transparentimage(400, 350, &b2, &b1);
	EndBatchDraw();
	while (1) {
		
	
		if (peekmessage(&c, EM_MOUSE)&&c.lbutton) {
			if(c.x>213&&c.x<332&&c.y>360&&c.y<399)
			{
			  game1(); 
			  return;
			}
			if(c.x>413&&c.x<532&&c.y>360&&c.y<399)
			{
			   game2(); 
			   return;
			}
			printf("%d %d\n", c.x, c.y);
		}
	}
}

双人模式

void game2()
{
	closegraph();
	int x1, y1,cc=0;
	char arr[] = "黑方胜利";
	char brr[] = "白方胜利";
	settextcolor(RED);
	settextstyle(20, 20, "微软雅黑");
	initgraph(855,856, EW_SHOWCONSOLE);
	IMAGE x;
	ExMessage c;
	loadimage(&x, "棋盘.jpg");
	putimage(0, 0, &x);
	while (1) {
		getmessage(&c, EM_MOUSE);
		switch (c.message) {
		case WM_LBUTTONDOWN:printf("%d  %d   %d\n", c.x, c.y, sum); if (c.x >= 47 && c.y >= 54&&c.x<=804&&c.y<=807) {
			if (sum % 2 != 0) changeh(c.x, c.y);
			else changeb(c.x, c.y);
		}
			 break;
		}
		map();
		cc=check();
		if (cc != 0) {
			if (cc == 1) outtextxy(20, 20, arr);
			else outtextxy(20, 20, brr);
			system("pause");
			return ;
		}
	}
	
}

这个将黑白棋的函数分开了,其实没必要,完全可以传入参数,来简化代码,还有下棋之后要清空整个屏幕就很浪费。

void game2()
{
	closegraph();
	loadimage(&x3, "白棋真.jpg");
	loadimage(&x31, "白棋假.jpg");
	loadimage(&x2, "黑棋真.jpg");
	loadimage(&x21, "黑棋假.jpg");
	int x1, y1,cc=0,sum=0;
	char arr[] = "黑方胜利";
	char brr[] = "白方胜利";
	settextcolor(RED);
	settextstyle(20, 20, "微软雅黑");
	initgraph(855,856, EW_SHOWCONSOLE);
	IMAGE x;
	ExMessage c;
	loadimage(&x, "棋盘.jpg");
	putimage(0, 0, &x);
	while (1)
	{
		if (peekmessage(&c, EM_MOUSE) && c.lbutton&& c.x >= 47 && c.y >= 54 && c.x <= 804 && c.y <= 807)
		{
			printf("kkk\n");
			if (sum % 2 == 0 && chang(c.x, c.y, 1))
			{
				sum++;
				map(c.x, c.y);
				cc = check(1);
			}
			else if (sum % 2 != 0 && chang(c.x, c.y, -1))
			{
				sum++;
				map(c.x, c.y);
				cc = check(-1);
			}
			if (cc != 0) {
				if (cc == 1) outtextxy(20, 20, arr);
				else outtextxy(20, 20, brr);
				system("pause");
				return;
			}
		}
	}
}

单人模式

这个判断应该下在哪其实就是枚举,当然这个思路我是不会改变,也不知道怎么改。改了一下下后就是

void game1()
{
	closegraph();
	int a = 0,cc=0,b=0;
	initgraph(800, 801, EW_SHOWCONSOLE);
	IMAGE x;
	ExMessage c;
	char arr[] = "你赢了";
	char brr[] = "你输了";
	settextcolor(RED);
	settextstyle(20, 20, "微软雅黑");
	loadimage(&x, "棋盘.jpg");
	putimage(0, 0, &x);
	a=heibai();
	while (1)
	{
		getmessage(&c, EM_MOUSE);//一定要接受信息
		if ( c.lbutton && c.x >= 47 && c.y >= 54 && c.x <= 804 && c.y <= 807&&a%2!=0)
		{
			printf("kkk\n");
			if (chang(c.x, c.y, 1))
			{
				a++;
				map(c.x, c.y);
				cc = check(5,1);
			}
		}
		else
		{
			ai(), a++;
			cc = check(5,-1);
		}
		if (cc != 0) {
			if (cc == 1) outtextxy(20, 20, arr);
			else outtextxy(20, 20, brr);
			system("pause");
			return;
		}
	}
	
}

单人模式的具体实现

判断游戏结束

![wuziq.png](https://img-blog.csdnimg.cn/img_convert/ad534200db7feb050a9b7af8a3d76068.png#clientId=u43ae87d1-2467-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=358&id=uc18b11dd&margin=[object Object]&name=wuziq.png&originHeight=537&originWidth=1014&originalType=binary&ratio=1&rotation=0&showTitle=false&size=8645&status=done&style=none&taskId=u9302365a-522a-44fc-8cc1-10338087ab6&title=&width=676)
正常来说都需要判断8个方向,但是其实考虑四个方向就行,其余四个方向在判断其他棋子时会考虑到,并且可以加入参数来判断几个时为胜利。

int check(int l,int e)
{
	for (int x = 6; x < 25; x++)
	{
		for (int y = 6; y < 25; y++) 
		for (int k = 0; k < 4; k++)
		{
			bool flag = true;
			for (int z = 0; z < l; z++)
			{
				if (qizi[z * dx[k] + x][z * dy[k] + y ]!= e)flag = false;
			}
			if (flag)return e;
		}
	}
	return 0;
}

枚举不同情况

void ai()
{
	/*int a = 0,b=0,a1=0,b1=0,a2=0,b2=0,b3=0;
	for (int x = 6; x < 25; x++)for (int y = 6; y < 25; y++) {
		if (qizi[x][y] == 0) {
			qizi[x][y] = -1;
			b = check(-1);
			if (b == -1) { qizi[x][y] = -1; return; }
			else qizi[x][y] = 0;
		}
	}
	printf("白五");
	for (int x = 6; x < 25; x++)for (int y = 6; y < 25; y++) {
		if (qizi[x][y] == 0) {
			qizi[x][y] = 1;
			a = check(1);
			if (a == 1) { qizi[x][y] = -1; return; }
			else qizi[x][y] = 0;
		}
	}
	printf("黑五");
	for (int x = 6; x < 25; x++)for (int y = 6; y < 25; y++) {
		if (qizi[x][y] == 0) {
			qizi[x][y] = -1;
			b1 = check1();
			if (b1 == -1) { qizi[x][y] = -1; return; }
			else qizi[x][y] = 0;
		}
	}
	printf("白四");
	for (int x = 6; x < 25; x++)for (int y = 6; y < 25; y++) {
		if (qizi[x][y] == 0) {
			qizi[x][y] = 1;
			a1 = check1();
			if (a1 == 1) { qizi[x][y] = -1; return; }
			else qizi[x][y] = 0;
		}
	}
	printf("黑四");
	for (int x = 6; x < 25; x++)for (int y = 6; y < 25; y++) {
		if (qizi[x][y] == 0) {
			qizi[x][y] = -1;
			b2 = check2();
			if (b2 == -1) { qizi[x][y] = -1; return; }
			else qizi[x][y] = 0;
		}
	}
	printf("白三");
	for (int x = 6; x < 25; x++)for (int y = 6; y < 25; y++) {
		if (qizi[x][y] == 0) {
			qizi[x][y] = 1;
			b2 = check2();
			if (b2 == 1) { qizi[x][y] = -1; return; }
			else qizi[x][y] = 0;
		}
	}
	printf("黑三");
	for (int x = 6; x < 25; x++)for (int y = 6; y < 25; y++) {
		if (qizi[x][y] == 0) {
			qizi[x][y] = -1;
			b3 = check3();
			if (b3 == -1) { qizi[x][y] = -1; return; }
			else qizi[x][y] = 0;
		}
	}
	printf("白二");
	for (int x = 6; x < 25; x++)for (int y = 6; y < 25; y++)if (qizi[x][y] == 1) {
		int a=suiji(x, y); if(a==1)return;
		}
	qizi[12][12] = -1;
	return;*/
}

其实就是判断好每种情况的优先级,例如此时场面黑棋和白棋都有4个都有获胜的可能性,但此时你是白棋,且轮到你下棋,白棋就可以获胜,但如果你黑棋是4个,白棋是三个,就需要去堵住黑棋获胜。
但是如果知道应该堵住哪个位置就可以让黑棋不能获胜呢,这个就需要用到check()了,枚举每个位置如果这里是黑棋看黑棋是否获胜。
当然为了更加只能要枚举更多情况,最后也要搞了随机,当然如果考虑完也可以不搞。

int check(int l, int e, bool st = false, int x = 0, int y = 0)
{
	if (st)
	{
		for (int k = 0; k < 4; k++)
		{
			bool flag = true;
			for (int z = 0; z < l; z++)
			{
				if (qizi[z * dx[k] + x][z * dy[k] + y] != e)flag = false;
			}
			if (flag)return e;
		}
		for (int i = 0; i < 8; i++)
		{
			for (int j = 1; j < l; j++)
			{
				int a = x + dx[i] * j, b = y + dy[i] * j;
				for (int k = 0; k < 4; k++)
				{
					bool flag = true;
					for (int z = 0; z < l; z++)
					{
						if (qizi[z * dx[k] + a][z * dy[k] + b] != e)flag = false;
					}
					if (flag)return e;
				}
			}
		}
	}
	else
	{
		for (int x = 6; x < 25; x++)
		{
			for (int y = 6; y < 25; y++)
				for (int k = 0; k < 4; k++)
				{
					bool flag = true;
					for (int z = 0; z < l; z++)
					{
						if (qizi[z * dx[k] + x][z * dy[k] + y] != e)flag = false;
					}
					if (flag)return e;
				}
		}
	}
	return 0;
}

应该还能优化的,,,,

最终代码

#include <graphics.h>
#include<stdio.h>
#include <conio.h>
#include<windows.h>
#include<mmsystem.h>
#include<time.h>
#pragma comment(lib,"Winmm.lib")
int qizi[30][30] = { 0 };
IMAGE x2, x3, x21, x31;
int dx[8] = { -1, -1, -1, 0, 1, 1, 1, 0 };
int dy[8] = { -1, 0, 1, 1, 1, 0, -1, -1 };
int mx[2] = { -1,1 };
void bgm()//背景音乐
{

	mciSendString("open 1.mp3 ", NULL, 0, NULL);
	mciSendString("play 1.mp3 repeat", NULL, 0, NULL);

}
int check(int l, int e, bool st = false, int x = 0, int y = 0)
{
	if (st)
	{
		for (int k = 0; k < 4; k++)
		{
			bool flag = true;
			for (int z = 0; z < l; z++)
			{
				if (qizi[z * dx[k] + x][z * dy[k] + y] != e)flag = false;
			}
			if (flag)return e;
		}
		for (int i = 0; i < 8; i++)
		{
			for (int j = 1; j < l; j++)
			{
				int a = x + dx[i] * j, b = y + dy[i] * j;
				for (int k = 0; k < 4; k++)
				{
					bool flag = true;
					for (int z = 0; z < l; z++)
					{
						if (qizi[z * dx[k] + a][z * dy[k] + b] != e)flag = false;
					}
					if (flag)return e;
				}
			}
		}
	}
	else
	{
		for (int x = 6; x < 25; x++)
		{
			for (int y = 6; y < 25; y++)
				for (int k = 0; k < 4; k++)
				{
					bool flag = true;
					for (int z = 0; z < l; z++)
					{
						if (qizi[z * dx[k] + x][z * dy[k] + y] != e)flag = false;
					}
					if (flag)return e;
				}
		}
	}
	return 0;
}
void transparentimage(int x, int y, IMAGE* srcimg, IMAGE* maskimg)
{
	putimage(x, y, maskimg, SRCAND);
	putimage(x, y, srcimg, SRCPAINT);
}
void map(int x, int y, bool st = false)
{
	int a = x / 41 + 5, b = y / 41 + 5, c = x % 41, d = y % 41;
	if (st)a = x, b = y;
	if (qizi[a][b] == 1)transparentimage(41 * (a - 6) + 38, 41 * (b - 6) + 43, &x2, &x21);
	if (qizi[a][b] == -1)transparentimage(41 * (a - 6) + 38, 41 * (b - 6) + 43, &x3, &x31);
}
bool chang(int x, int y, int e)
{
	int a = x / 41 + 5, b = y / 41 + 5, c = x % 41, d = y % 41;
	if (7 <= c && c <= 27 && 12 <= d && 32 >= d && qizi[a][b] == 0)
	{
		qizi[a][b] = e;
		return true;
	}
	return false;
}
void ai()
{
	for (int l = 5; l > 1; l--)for (int z = 0; z < 2; z++)
		for (int x = 6; x < 25; x++)for (int y = 6; y < 25; y++)
		{
			if (qizi[x][y] == 0)
			{
				qizi[x][y] = mx[z];
				if (check(l, mx[z], true, x, y) == mx[z])
				{
					if (z == 1)qizi[x][y] = -1;
					map(x, y, true);
					printf("%d %d %d %d\n", l, z, x, y);
					return;
				}
				else qizi[x][y] = 0;
			}
		}
	qizi[17][17] = -1;
	map(17, 17, true);
}
int  heibai()
{
	HWND hh = GetHWnd();
	SetWindowText(hh, "五子棋");
	int a = MessageBox(hh, "是否选择先手", "提示", MB_OKCANCEL);
	if (a == IDOK)return 1;
	else return 0;
}
void game1()
{
	closegraph();
	int a = 0, cc = 0, b = 0;
	initgraph(800, 801, EW_SHOWCONSOLE);
	IMAGE x;
	ExMessage c;
	char arr[] = "你赢了";
	char brr[] = "你输了";
	settextcolor(RED);
	settextstyle(20, 20, "微软雅黑");
	loadimage(&x, "棋盘.jpg");
	putimage(0, 0, &x);
	a = heibai();
	while (1)
	{
		if (a % 2 != 0)
		{
			getmessage(&c, EM_MOUSE);
			if (c.lbutton && c.x >= 47 && c.y >= 54 && c.x <= 804 && c.y <= 807)
			{

				if (chang(c.x, c.y, 1))
				{
					a++;
					map(c.x, c.y);
					cc = check(5, 1);
				}
			}
		}
		else
		{
			ai();
			a++;
			cc = check(5, -1);
		}
		if (cc != 0) {
			if (cc == 1) outtextxy(20, 20, arr);
			else outtextxy(20, 20, brr);
			system("pause");
			return;
		}
	}

}
void game2()
{
	closegraph();
	int x1, y1, cc = 0, sum = 0;
	char arr[] = "黑方胜利";
	char brr[] = "白方胜利";
	settextcolor(RED);
	settextstyle(20, 20, "微软雅黑");
	initgraph(855, 856, EW_SHOWCONSOLE);
	IMAGE x;
	ExMessage c;
	loadimage(&x, "棋盘.jpg");
	putimage(0, 0, &x);
	while (1)
	{
		if (peekmessage(&c, EM_MOUSE) && c.lbutton && c.x >= 47 && c.y >= 54 && c.x <= 804 && c.y <= 807)
		{
			if (sum % 2 == 0 && chang(c.x, c.y, 1))
			{
				sum++;
				map(c.x, c.y);
				cc = check(3, 1);
			}
			else if (sum % 2 != 0 && chang(c.x, c.y, -1))
			{
				sum++;
				map(c.x, c.y);
				cc = check(3, -1);
			}
			if (cc != 0) {
				if (cc == 1) outtextxy(20, 20, arr);
				else outtextxy(20, 20, brr);
				system("pause");
				return;
			}
		}
	}
}
void menu()
{
	for (int x = 0; x < 30; x++)for (int y = 0; y < 30; y++)qizi[x][y] = 1000;
	for (int x = 6; x < 25; x++)for (int y = 6; y < 25; y++)qizi[x][y] = 0;
	initgraph(800, 496, EW_SHOWCONSOLE);
	setbkcolor(WHITE);
	cleardevice();
	IMAGE x, a1, a2, b1, b2;
	ExMessage c;
	setfillcolor(RGB(137, 207, 180));
	settextcolor(BLUE);
	settextstyle(35, 20, "微软雅黑");
	loadimage(&x, "hhh.jpg");
	loadimage(&a1, "单人模式按钮图片.png");
	loadimage(&a2, "单人模式按钮图片2.png");
	loadimage(&b1, "双人模式按钮.png");
	loadimage(&b2, "双人模式按钮2.png");
	loadimage(&x3, "白棋真.jpg");
	loadimage(&x31, "白棋假.jpg");
	loadimage(&x2, "黑棋真.jpg");
	loadimage(&x21, "黑棋假.jpg");
	BeginBatchDraw();
	putimage(0, 0, &x);
	transparentimage(200, 350, &a2, &a1);
	transparentimage(400, 350, &b2, &b1);
	EndBatchDraw();
	while (1) {


		if (peekmessage(&c, EM_MOUSE) && c.lbutton) {
			if (c.x > 213 && c.x < 332 && c.y>360 && c.y < 399)
			{
				game1();
				return;
			}
			if (c.x > 413 && c.x < 532 && c.y>360 && c.y < 399)
			{
				game2();
				return;
			}
			printf("%d %d\n", c.x, c.y);
		}
	}
}
int main()
{
	bgm();
	menu();
	return 0;
}

相关素材

阿里云盘

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值