进阶版三子棋(待改进)

进阶版三子棋(待改进)

Designed By Rossi
仅供记录和参考,转载需经本人同意


有段时间没写blog了,感觉自己快生锈了。2021年是时候该整点狠活了,我决定搬出我用c++写了三个月的小游戏


初衷

学了这么久编程,总觉得自己除了算法还应该弄点别的东西,用c++写个软件吧似乎很难实现,而且c++的GUI设计还是比较难的。

既然搞不了软件,那要不写个小游戏吧,毕竟自己也喜欢游戏。于是我想了想,贪吃蛇和雷电我都写不出,推箱子做过了感觉太低级,要不整个三子棋吧。

期初我看了网上很多三子棋的例子,发现很多开源例子都只是停留在简单层面的设计,所以我决定写点花里胡哨的


是时候进入正题了

一、三子棋的介绍

写游戏之前当然得先了解游戏规则和背景吧

三子棋是黑白棋的一种。三子棋是一种民间传统游戏,又叫九宫棋、圈圈叉叉、一条龙、井字棋等。将正方形对角线连起来,相对两边依次摆上三个双方棋子,只要将自己的三个棋子走成一条线,对方就算输了。但是,有很多时候会出现和棋的情况。

二、代码解析

1.登录程序

首先进游戏之前得整个花里胡哨的东西——登录

第一步得先设计好登录的界面UI,然后设计好登录时用户名和密码的输入和后台校验。考虑到登录失败的情况,需要逼真地模拟登录失败后的重新登录和延时登录,因此需要编写一个Time()函数套用到LogIn()函数中。
然后这个功能里我最喜欢的部分就是登录输入密码时用*隐藏原始密码,这一步足足花了我两个星期,此前虽然想了三种实现方法都没有成功,但是最后成功之后出来的效果让我比较满意。

//倒计时
void Time()
{
    
    
	char content[]="9876543210";
	char lable[]="Please wait #S!";
	int len=strlen(content);
	int start=0;
    cout<<lable<<'\r';
	for(start=0;start<len;start++)
	{
    
    
		lable[12]=content[start];//给数组第十三个元素传值
		int t=1000 ;
		Sleep(t);
		cout<<lable<<'\r';
		if(start==len-1)//数传完毕
			cout<<'\b'<<"Please log in again! "<<3;// \b 退格符
	}
	cout<<endl;
}
//登录界面
void LogIn()
{
    
    
	char username[64];
	char password[64];
	char code[64];
	int flag=0;
	cout<<"注意:你只有三次登录机会"<<endl;
	for(int times=0;times<3;times++)
	{
    
    
the:	cout<<"请输入账号:";
		cin>>username;//数组在输入时降维成指针;所以不带&
		cout<<"请输入密码:";
		int i=0;
		if(strcmp(USERNAME,username)==0)
		{
    
       
		//接下来这一步就是实现模拟密码输入时有*隐藏的效果
			do
            {
    
    
                password[i]=getch();
                if(password[i]=='\r')
                    break;
                if(password[i]=='\b')
                {
    
    
                    if(i==0)
                    {
    
    
                        cout<<'\a';
                        continue;
                    }
                    i=i-1;
                    cout<<'\b';//实现删字不影响显示
                }
                else
                {
    
    
                    i=i+1;
                    cout<<"*";
                }
            }while(password[i]!='\n' && i<20);
            password[i]='\0';
            cout<<endl;
            if(strcmp(PASSWORD,password)==0)
            {
    
    
                cout<<"登录成功!"<<endl;
                flag=1;
                break;
            }
            else
            {
    
    
                cout<<"登录失败!"<<endl;
                times==2;
            }
            if(flag=1)
                break;
		}		
		if(times==2)
		{
    
    
			cout<<"请等待 "<<WaitTime<<"秒!"<<'\r';
			Time();
			goto the;//跳转到登录,登录失败1次就延时!
		}
	}
}

2.打印棋盘

登录进去了,那得先有棋盘才能下棋吧

这里我使用了一个二维数组来存放棋盘,所以我需要先进行初始化操作然后打印棋盘(row是列,line是行)

void init(char chessBoard[MAXROW][MAXLINE])
{
    
    
	for(int row=0;row<MAXROW;row++)
		for(int line=0;col<MAXLINE;line++)
			chessBoard[row][line]=' ';
}
void print_chessBoard(char chessBoard[MAXROW][MAXLINE])
{
    
    
	cout<<"+---+---+---+"<<endl;
	for(int row=0;row<MAXROW;row++)
    {
    
    
		cout<<"| "<<chessBoard[row][0]<<" | "<<chessBoard[row][1]<<" | "<<chessBoard[row][2]<<" |"<<endl;
		cout<<"+---+---+---+"<<endl;
	}
}

3.核心代码1:玩家移动,电脑移动与胜负判定

棋盘有了,那可以开始下棋了

因为我用c++写这个游戏没有UI,不像人家那些真游戏那样可以动动鼠标就可以下棋,所以这里只能采用坐标法落子。利用坐标法落子需要注意两个事情:一是落子位置是否已经有棋,二是落子位置是否在棋盘之外。下完棋之后还要做一件事就是“裁判”:设置一个变量来记录比赛结果方便最后根据判定输出结果。还要一个细节就是胜负判定时会出现平局的结果,这时候只需要判断棋盘是否满棋而没有产生胜负就行了。

void playerMove(char chessBoard[MAXROW][MAXLINE])
{
    
    
	while(1)
    {
    
    
		int row=0;
		int line=0;
        cout<<"请输入坐标(范围0~2):";
		cin>>row>>line;
		if(row<0 || row>=MAXROW || line<0 || line>=MAXLINE)
		{
    
    
			cout<<"您的坐标不在合法范围内 [0, 2],请重新输入:"<<endl;
			continue;
		}
		if(chessBoard[row][line]!=' ')
		{
    
    
			cout<<"您下的位置已经有子了!"<<endl;
			continue;
		}
		chessBoard[row][line]='x';
		break;
	}
}
void computerMove(char chessBoard[MAXROW][MAXLINE])
{
    
    
	while(1)
    {
    
    
		int row=rand()%MAXROW;
		int line=rand()%MAXLINE;
		if(chessBoard[row][line]!=' ')
			continue;
		chessBoard[row][line]='o';
		break;
	}
}
int isFull(char chessBoard[MAXROW][MAXLINE])
{
    
    
	for(int row=0;row<MAXROW;row++)
		for(int line=0;line<MAXLINE;line++)
			if(chessBoard[row][line]==' ')
				return 0;
	return 1;
}
char isWin(char chessBoard[MAXROW][MAXLINE])
{
    
    
	for(int row=0;row<MAXROW;row++)
		if(chessBoard[row][0] != ' ' && chessBoard[row][0]==chessBoard[row][1] && chessBoard[row][0]==chessBoard[row][2])
			return chessBoard[row][0];
	for(int line=0;line<MAXLINE;line++)
		if(chessBoard[0][line]!=' ' && chessBoard[0][line]==chessBoard[1][line] && chessBoard[0][line]==chessBoard[2][line])
			return chessBoard[0][line];
	if(chessBoard[0][0] != ' ' && chessBoard[0][0]==chessBoard[1][1] && chessBoard[0][0]==chessBoard[2][2])
		return chessBoard[0][0];
	if(chessBoard[2][0]!=' ' && chessBoard[2][0]==chessBoard[1][1] && chessBoard[2][0]==chessBoard[0][2])
		return chessBoard[2][0];
	if(isFull(chessBoard))
		return 'q';
	return ' ';
}

4.核心代码2:玩家先走和电脑先走

有棋了,怎么走是个问题

下棋总有先手和后手对吧,所以我写了两个函数,game()是玩家先走的开局,fungame()是电脑先走的开局

void game()
{
    
    
	char chessBoard[MAXROW][MAXLINE]={
    
    0};
	init(chessBoard);
	char winner=' ';
	while(1)
    {
    
    
		print_chessBoard(chessBoard);
		playerMove(chessBoard);
		winner=isWin(chessBoard);
		if(winner!=' ')
			break;
		computerMove(chessBoard);
		winner=isWin(chessBoard);
		if(winner!=' ')
			break;
	}
	print_chessBoard(chessBoard);
	if(winner=='x')
		cout<<"恭喜您, 您赢了!"<<endl;
	else if(winner=='o')
    {
    
    
        score-=50;
		cout<<"对不起,你输了!"<<endl;
    }
	else
    {
    
    
        score-=50;
		cout<<"很遗憾,打成了平手!!"<<endl;
    }
}
void fungame()
{
    
    
	char chessBoard[MAXROW][MAXLINE]={
    
    0};
	init(chessBoard);
	char winner=' ';
	while(1)
    {
    
    
		print_chessBoard(chessBoard);
		computerMove(chessBoard);
		winner=isWin(chessBoard);
		if(winner!=' ')
			break;
		playerMove(chessBoard);
		winner=isWin(chessBoard);
		if(winner!=' ')
			break;
	}
	print_chessBoard(chessBoard);
	if(winner=='x')
		cout<<"恭喜您, 您赢了!"<<endl;
	else if(winner=='o')
    {
    
    
        score-=50;
		cout<<"对不起,你输了!"<<endl;
    }
	else
    {
    
    
        score-=50;
		cout<<"很遗憾,打成了平手!!"<<endl;
    }
}

很多人看到这里应该看到了里面的score了吧,别急,下面就是用到它的地方了

5.成就系统(计分)

玩游戏没有分数哪有动力啊对吧

光玩游戏多没意思啊,而且这样写出来也展现不出我的水平。秉持着花里胡哨的理念,我决定写个成就系统
这里因为传值过程会出现一些问题,最终结果会出现一些与预期效果不符的结果,所以这里结合主函数弄了一个算是比较巧的方法(+50,-50)

void honor(int score)
{
    
    
    if(score>=0 && score<100)
        cout<<"当前称号:小菜鸡"<<" 当前积分:"<<score<<endl;
    if(score>=100 && score<250)
        cout<<"当前称号:初出茅庐"<<" 当前积分:"<<score<<endl;
    if(score>=250 && score<500)
        cout<<"当前称号:牛刀小试"<<" 当前积分:"<<score<<endl;
    if(score>=500 && score<800)
        cout<<"当前称号:棋艺精湛"<<" 当前积分:"<<score<<endl;
    if(score>=800)
        cout<<"当前称号:三子棋大师"<<" 当前积分:"<<score<<endl;
}

6.全局变量,定义及部分主函数部分

前面用到的棋盘、分数、等待时间等等,都在函数编写前已经定义好了

int WaitTime=10;
int score=0;

包括宏定义

#define _CRT_SECURE_NO_WARNINGS
#define MAXROW 3
#define MAXLINE 3

有了函数自然得有调用它们的办法,这些方法就塞在主函数里面

srand((unsigned int)time(0));
    notice();//游戏公告
	LogIn();//登录程序
	while(1)
    {
    
    
		int choice=menu();//调用菜单
		if(choice==1)
        {
    
    
            game();
            score+=50;
        }
        else if(choice==2)
        {
    
    
            fungame();
            score+=50;
        }
		else if(choice==0)
		{
    
    
			cout<<"退出游戏,再见!!!!!"<<endl;
			break;
		}
		else
		{
    
    
			cout<<"输入错误!请重新输入!"<<endl;
			continue;
		}
		honor(score);
	}
	system("pause");

三、小感慨

说实话当写出来、调试成功,能玩的时候,心里的成就感真的满满的。
不过这个游戏不完善的地方还是有的,例如电脑判断玩家棋路这方面,这一步涉及到算法,因为忙于学习 还没有时间去完善这个方面。另外还有一个就是登录方面,还没想到怎么去实现注册账号(注册之后还要实现账号的长久保存)、找回密码等等。时间还长,这些得等到以后才能去实现了(PS:如果有大佬有兴趣搞一下这个不妨和小弟一起探讨一下,或者帮小弟写个补全,蒟蒻期待大佬们临幸我)

部分编译截图
在这里插入图片描述
在这里插入图片描述
(这里可以看到电脑的棋路和判断还是挺傻的,以后再来改善)

ps:防止被生搬硬造,这里我就不把完整代码放出来了,想要完整源代码的话到时我会放链接的
(exe文件:点击这里

猜你喜欢

转载自blog.csdn.net/jotaro07/article/details/112421280
今日推荐