logo资料库

VC++课程设计报告 三子连珠游戏.doc

第1页 / 共18页
第2页 / 共18页
第3页 / 共18页
第4页 / 共18页
第5页 / 共18页
第6页 / 共18页
第7页 / 共18页
第8页 / 共18页
资料共18页,剩余部分请下载后查看
VC++VC++VC++课程设计课程设计课程设计 VC++课程设计报告 课 院 程: 系: 选题名称: TICTACTOE 游戏(三子连珠游戏) 题目级别: B 级 班 学 姓 时 级: 号: 名: 间: 指导老师: (源码网整理:www.codepub.com) 0
VC++VC++VC++课程设计课程设计课程设计 程序功能简介 该程序是 TICTACTOE 游戏,棋盘为 3*3,3 个棋子连起来即为赢。输入参数 时,若输入的数字超过边界或在已有棋子的地方再输入,则提示出错,要求重 新输入。 课程设计要求 1. 将程序改写成类。 2. 将棋盘扩充成 4*4。 3. 统计输赢结果并打印输出。 4. 选做:使游戏更生动。(输赢条件相同) 评定难易程度:B 程序设计思想 设计一个玩家下棋的操作类,里面封装了棋盘﹑棋子类别和输赢次数等成员 数据。 操作类的函数包括有初始化棋盘﹑下棋﹑判断输赢等。定义一个类的对象, 在调用类中函数时直接使用对象名加函数名即可。 将两个玩家定义为两个数组用于区分他们的信息,分别用‘O’和‘X’代表 两个玩家所用棋子,然后分别对两个玩家通过已定义的类的对象调用类中的函 数,完成下棋过程。 进一步改进程序: 1. 程序中用 if else if 格式的语句来判断玩家的输赢,当棋盘增大时,三 子连珠的各种可能性成倍增加,使得语句非常繁琐,所以将其改为 for 语 句的循环结构进行判断,当棋盘增大时,只需更改循环条件结束的参数即 可,可灵活使用于各种尺寸的棋盘。 2. 为防止用户误操作,特别是在姓名的输入时的失误,可以采用 cin.getline 函数读入在判断确认。 3. 在完成第一步的基础上可将三子连珠扩充为标准的五子棋。 原程序各个功能说明 原程序的结构(见下页)(源码网整理:www.codepub.com) 1
VC++VC++VC++课程设计课程设计课程设计 错 误 错 误 不 符 合 Y 结束 N 开始 输 出 菜 单 及 提 示 信息 输入姓名 由“O”先手下棋 “O”输入棋子所在 的行列 正 确 “X”输入棋子所在 的行列 正确 判 断 胜 负 ﹑ 和 棋条件 符 合 输出结果 询问是否继续下棋 输出最终结果 2
VC++VC++VC++课程设计课程设计课程设计 1. 类的说明 类是对一组具有相同属性、相同行为的对象的抽象的描述,不占用内存空间。 可以把类看作“理论上”的对象,也就是说,它为对象提供蓝图,但在内存中并 不存在。从这个蓝图可以创建任何数量的对象。从累创建的所有对象都有相同的 成员:属性、行为或方法。这些对象才是具体的独立的个体,占用存储空间,因 此,对象又称作类的实例。 下面以具体程序说明。 在头文件之后定义了一个名为 CGobang 的类: class CGobang { char board[4][4];//用数组来定义一个 4*4 的棋盘 public: void Guize();//打印菜单总体情况,说明游戏规则和方法,无返回值 void Dayinqp();//打印棋盘,无返回值 void Xiaqi(char*,int &,int &,char);//下棋,无返回值 int Huosheng(int,int,char);//判断那个选手赢,返回值为一整形数 void Choice(char &);//是否再玩,无返回值 void Chongzhi();//重置棋盘,无返回值 }; 在 这 个 类 中 , 定 义 了 一 个 未 经 说 明 的 数 组 被 默 认 为 私 有 成 员 , 即 char board[4][4],用它来存储玩家在下棋的过程中所输入的棋子的坐标,并以此来 区分表示不同的两个玩家。另外,这个类中还说明了五个没有返回值的函数以及 一个返回值为整形数的函数,对它们的定义将出现在主函数完成之后,所以本着 “先定义,后调用”的原则,在类中的说明相当于自定义函数中的函数说明,这 样可以使在主函数调用类中的公有函数时变得更加明了清晰。 在这个函数中,对类的对象的定义出现在了主函数第一行,即: CGobang s;//定义类的一个对象 s 对这个对象的定义的目的是,在下面不同玩家的下其中的不同操作中,可以直接 通过这个对象来分别调用类中的任意公有成员函数,这样就避免了通过类名来调 用函数时可能出现的冗长。可以说,在这个程序里,这个对象 s 起到了把主函数 与类连接起来的桥梁作用。 课程设计要求的实现 一、类的封装。 首先,在源程序代码中出现的主要函数程序有: void PrintBoard(); void PrintInfo(); void PrintStats(int, int, int); void IfError(int&, int&); void ChoiceOfChar(char&); void PromptTurnO(int&, int&); void PromptTurnX(int&, int&); char board[3][3]; // 打印棋盘 //输出游戏提示信息 // 输出统计的胜负信息 // 判断输入时候有错 // 询问用户是否在玩一局 // 选择“O”的玩家下棋(先走) // 选择“X”的玩家下棋(后走) // 棋盘 3
VC++VC++VC++课程设计课程设计课程设计 在我的程序中的主要函数程序为: void Guize();//打印菜单总体情况,说明游戏规则和方法,无返回值 void Dayinqp();//打印棋盘,无返回值 void Xiaqi(char*,int &,int &,char);//下棋,无返回值 int Huosheng(int,int,char);//判断那个选手赢,返回值为一整形数 void Choice(char &);//是否再玩,无返回值 void Chongzhi();//重置棋盘,无返回值 以此来对比说明。 ◎源代码中的关于打印棋盘以及规则提示的说明的函数没有变动。 ◎去掉了关于输出统计胜负信息的函数,在主函数体中用三个一组的条件自 增变量代替,这样减少了复杂的函数调用,说明以及定义,精简了程序,并且达 到了预想的目的。 ◎由于对玩家输入是否有错的判断在玩家每次确定下棋之后必须进行,所以 如果像源代码一样把玩家下棋的函数和判断是否有误分开定义的话,在没下一步 棋之后都要重复调用判断函数,显得十分复杂,所以把源代码中的判断是否有错 的函数与玩家下棋合并在 void Xiaqi(char*,int &,int &,char) 中,对它们的定义在后面的类的成员函数的定义中一起定义,这样可以减少很多 不必要的麻烦,起到了精简程序的作用。 ◎源代码中把连个玩家分别定义为两个函数,用以区别先后手,然后在定义 一个数组 char board[3][3](由于源代码中显示的是 3*3 的棋盘,所以数组定 义为 board[3][3])来表示棋盘。在这点我做了比较大的改动,首先是定义了一 个类中的私有成员数组,用以记录每位玩家所下棋子的坐标,这样既可以通过用 不同的指针变量来指向键盘的方法来区分不同的玩家,亦可以同时用它表示整个 棋盘。这样使程序得到了进一步的精简。 void CGobang::Xiaqi(char*player1,int & x,int & y,char c) { cout<<"该"<>x; cout<<" "<<" "<<" "<<" "<<"棋子所在列:"; cin>>y; while(x>4||y>4||x<1||y<1||‘ ’!=board[x-1][y-1]) //输入数字超过边界或在已有棋子的地方再输入 //' '!=board[x-1][y-1]表示已有棋子 { cout<<"对不起,您的输入有误,请重新输入!"<>x; cout<<" "<<" "<<" "<<" "<<"棋子所在列:"; cin>>y; } board[x-1][y-1]=c;//在 x 行,y 列处下 O 或 X } 4
◎ 由 于 需 要 重 复 使 用 空 棋 盘 , 我 又 增 加 了 一 个 重 置 棋 盘 的 函 数 void VC++VC++VC++课程设计课程设计课程设计 Chongzhi()来进行每次开始下棋时的棋盘清空重置。 void CGobang::Chongzhi() { for(int Row=0;Row<4;Row++) for(int Column=0;Column<4;Column++) board[Row][Column]=' '; } ◎完成对主要函数的改动之后,把它们封装到类 CGobang 中即可。 二、将棋盘扩充为 4*4 在类的封装中已经详细的将我改动过的棋盘说明了,所以,要把棋盘扩充为 n*n 只需把定义过的私有成员数组 board[n][n]中的 n 改为所需数字即可。即, 定义 board[4][4],就完成了对棋盘 4*4 的扩充。 三、统计输出结果并打印输出。 同样,在类的封装中也已说明我对记录胜负结果以及输出的方法,下面给出 源代码: 记录胜负结果: int FirstWin=0,SecondWin=0,Draws=0,x,y,N; 在每次获胜、失败以及和棋的判断完成之后,令 FirstWin SecondWin Draws 分别依情况自增,达到记录胜负次数的目的。 打印输出: //输出游戏输赢次数 cout<
VC++VC++VC++课程设计课程设计课程设计 cin.getline(player1,20);//连续读取数据,实现对玩家一命名 cout<<"请输入第二个玩家姓名:"; cin.getline(player2,20);//连续读取数据,实现对玩家二命名 while(choice=='Y'||choice=='y')//条件成立,开始下棋 { s.Chongzhi();//通过对象 s 调用 Chongzhi 函数 N=0;//对变量付初值,表示已经下在棋盘上的妻子总数 while(N<=16)//在棋盘未满的条件下下棋 { s.Dayinqp();//打印棋盘 s.Xiaqi(player1,x,y,'O');//调用下棋的运行函数 N++;//记录已下棋子数 if(s.Huosheng(x-1,y-1,'O'))//返回值不为 0 则条件成立 { cout<
VC++VC++VC++课程设计课程设计课程设计 //定义判断获胜条件的函数 /*此函数以下棋的点为坐标分别向 8 个方向判断是否能构成胜利条件,若能 返回值 1,则该选手获胜,程序结束;若不能,返回值为 0,继续循环下棋程 序。*/ int CGobang::Huosheng(int x,int y,char c) { int count,a; //从 左斜上 方向判断是否构成胜利条件 for(a=0,count=0;(x-a>=0)&&(y-a>=0)&&(board[x-a][y-a]==c);a++) if(++count==3) return 1; //从 右斜下 方向判断是否构成胜利条件 for(a=1;(x+a<4)&&(y+a<4)&&(board[x+a][y+a]==c);a++) if(++count==3) return 1; //从 上向下 方向判断是否构成胜利条件 for(a=0,count=0;(x-a>=0)&&(board[x-a][y]==c);a++) if(++count==3) return 1; //从 下向上 方向判断是否构成胜利条件 for(a=1;(x+a<4)&&(board[x+a][y]==c);a++) if(++count==3) return 1; //从 左至右 方向判断是否构成胜利条件 for(a=0,count=0;(y-a>=0)&&(board[x][y-a]==c);a++) if(++count==3) return 1; //从 右至左 方向判断是否构成胜利条件 for(a=1;(y+a<4)&&(board[x][y+a]==c);a++) if(++count==3) return 1; //从 右斜上 方向判断是否构成胜利条件 for(a=0,count=0;(x-a>=0)&&(y+a<4)&&(board[x-a][y+a]==c);a++) if(++count==3) return 1; //从 左斜下 for(a=1;(x+a<4)&&(y-a>=0)&&(board[x+a][y-a]==c);a++) 方向判断是否构成胜利条件 if(++count==3) return 1; return 0; } 设计过程中的疑难及解答方案和设计的不足 ◎设计过程中的疑难及解答方案 在这次课程设计的过程中,我遇到了不小的阻力,还有也从中学习到了很多 以前没有掌握好或这根本没有掌握的知识。 在 定 义 玩 家 名 字 的 输 入 接 受 的 时 候 我 遇 到 了 一 个 从 未 见 过 的 函 数 cin.ignore(),这个函数是我从一个同样是输入存储用户姓名的程序里看到 的,上面对它的注释是:“输入输出流,前面如果有输入把输入行所有字符去 空,一边后面的输入从新的一行开始。”我对这个想了很长时间,但是一直没 有明白。最后解决问题的方法是我通过网络查询找到了这个函数,在其他一些 7
分享到:
收藏