C语言实习报告一担挑游戏.docx

上传人:b****3 文档编号:5268289 上传时间:2022-12-14 格式:DOCX 页数:14 大小:206.53KB
下载 相关 举报
C语言实习报告一担挑游戏.docx_第1页
第1页 / 共14页
C语言实习报告一担挑游戏.docx_第2页
第2页 / 共14页
C语言实习报告一担挑游戏.docx_第3页
第3页 / 共14页
C语言实习报告一担挑游戏.docx_第4页
第4页 / 共14页
C语言实习报告一担挑游戏.docx_第5页
第5页 / 共14页
点击查看更多>>
下载资源
资源描述

C语言实习报告一担挑游戏.docx

《C语言实习报告一担挑游戏.docx》由会员分享,可在线阅读,更多相关《C语言实习报告一担挑游戏.docx(14页珍藏版)》请在冰豆网上搜索。

C语言实习报告一担挑游戏.docx

C语言实习报告一担挑游戏

§1.1题目描述

【一担挑游戏】

【要求】

简单计算机模拟棋盘对弈。

其中棋盘左上角坐标为(1,1),右下角为(3,3)。

游戏规则如下:

1.计算机移动时,使用相应函数扫描棋盘矩阵,寻找未占单元,发现空单元后,置为“O”,未发现时,报告平局后退出。

2.轮到对弈者时,使用相应函数要求对弈者回答想要把“X”放在哪里。

3.谁先三点连成一线了,则报告谁胜出。

4.计算机与对弈者每下一步棋都会使相应位置变为“O”和“X”,便于在屏幕上显示矩阵。

【提示】

棋盘位置用二维数组代表,初始状态每一位置均应为“”(空),其分隔线(即棋盘线)可用——或││来分隔

§1.2算法设计

一担挑小游戏,简单、休闲、益智。

全程序大体由四部分组成:

“玩家落子模块”、“计算机落子模块”、“判断胜负模块”及“打印棋盘模块”。

考量到棋类游戏计算上的复杂性,本程序尽可能简化算法,使计算机简单地按照棋盘顺序落子。

总流程图设计构想如下:

 

 

各功能模块流程图设计如下:

1.玩家落子模块

 

该位置置为“X”

【注】棋盘坐标定义为从1,1到3,3

该模块要求玩家输入想要落子的坐标row,column。

如果位置row-1,column-1处字符数组元素不存在或已经被占,系统给出错误提示,并要求玩家重新输入;否则该位置置为“X”。

 

2.计算机落子模块

 

该模块设计成3*3的循环,按次序检索该单元是否为空。

如果单元已被占则跳过;否则置为“O”。

 

3.判断胜负模块

 

用穷举法判断某行、某列、对角线是否连成一线。

判断顺序如上。

若某一判断为“是”,则将连成线的字符赋值给字符变量winner再交由主函数尾的程序辨析谁获胜;若一直判断为“否”,将空值赋给变量winner,再交由玩家落子模块或计算机落子模块运行。

 

4.打印棋盘模块

 

主函数流程(程序设计布局)

 

§1.3程序设计及代码分析

源程序如下:

#include"stdio.h"

#include"stdlib.h"

voidprintboard();//打印棋盘

voidcheck();//检查结果是否分出胜负

charboard[3][3]={{'\0','\0','\0'},{'\0','\0','\0'},{'\0','\0','\0'}};//棋盘初始化

charwinner='\0';//标记谁是胜者

intmain()

{introw=0,column=0;//定义棋盘的行列

intstep=0;//定义计算步数的变量

printf("\nwelcometothisgame,player!

\n");

printboard();//打印空棋盘

while(winner=='\0'&&step!

=9)//当未分胜负时,循环双方对弈

{//玩家落子

do//当棋子落在无效区时,报错

{printf("\npleaseenterthecoordinatewhereyouwanttoputyourX:

");

scanf("%d,%d",&row,&column);//输入欲落子的坐标

if(row*column>9||row*column<1||board[row-1][column-1]!

='\0')

printf("\nfaultposition!

pleasereput:

");

}while(row*column>9||row*column<1||board[row-1][column-1]!

='\0');

printf("\n\nplayermove\n");

board[row-1][column-1]='X';//落子有效

printboard();//即打印棋盘

step++;//每下一步步数加一

check();//检查是否分出胜负

if(winner!

='\0'||step==9)break;//如果是,结束游戏

//计算机落子

printf("\n\ncomputermove\n");

for(row=0;row<3;row++)//计算机按循环的顺序落子

{

for(column=0;column<3;column++)

{

if(board[row][column]=='\0')

{

board[row][column]='O';

gotoend;//如果计算机已落子,停止扫描棋盘

}

}

}end:

;

printboard();//打印棋盘

step++;//每下一步步数加一

check();//检查是否分出胜负

}//一回合完成,若未分胜负,返回继续执行大循环

//当游戏结束,辨析谁是胜者

if(winner=='O')

printf("*****youlose!

*****\n");//winner值为“O”表示计算机赢

elseif(winner=='X')

printf("*****youwin!

*****\n");//winner值为“X”表示玩家赢

elseif(winner=='\0')

printf("*****draw!

*****\n");//winner值为“\0”表示平局

return0;

}//main函数结束

voidprintboard()//定义打印棋盘函数

{printf("\n");

printf("%c|%c|%c\n",board[0][0],board[0][1],board[0][2]);

printf("-----------\n");

printf("%c|%c|%c\n",board[1][0],board[1][1],board[1][2]);

printf("-----------\n");

printf("%c|%c|%c\n",board[2][0],board[2][1],board[2][2]);

printf("\n\n");

}

voidcheck()//定义判断胜负函数

{if((board[0][0]==board[1][1]&&board[0][0]==board[2][2])||(board[0][2]==board[1][1]&&board[0][2]==board[2][0]))//★

winner=board[1][1];//若某条对角线连成线,返回正中心棋子的值

else

if((board[0][0]==board[0][1]&&board[0][0]==board[0][2])||(board[0][0]==board[1][0]&&board[0][0]==board[2][0]))//★

winner=board[0][0];//若第一行或第一列连成线,返回左上角棋子的值

else

if((board[0][2]==board[1][2]&&board[0][2]==board[2][2])||(board[2][0]==board[2][1]&&board[2][0]==board[2][2]))//★

winner=board[2][2];//若第三行或第三列连成线,返回右下角棋子的值

else

if((board[0][1]==board[1][1]&&board[0][1]==board[2][1])||(board[1][0]==board[1][1]&&board[1][0]==board[1][2]))//★

winner=board[1][1];//若第二行或第二列连成线,返回正中心棋子的值

elsewinner='\0';//未连成线,返回空值

}

【注】1.绿字部分为程序的注释2.打星号处在源程序中不分行

代码分析:

本程序不需要模块的设计,使得功能受限,只能实现最基本的人机对战。

如果要使得功能更加完备,需要增加模块使对战更加灵活(尤其是计算机落子模块需要扩充)。

以下就程序的几个主要部分进行代码分析:

1.主函数

(1)初始化棋盘。

棋盘设计成3*3的二维字符数组,初始每个位置置为'\0',表示空

charboard[3][3]={{'\0','\0','\0'},{'\0','\0','\0'},{'\0','\0','\0'}};

(2)“玩家落子模块”和“计算机落子模块”合在主函数的同一while循环体下,作为整体的一回合运行。

通过循环控制,并未将两个模块单独拉出来做成独立的函数体。

当然,拉出来做成独立的函数体也可以,这样几个模块的关系会更清楚一点。

while(winner=='\0'&&step!

=9)

{//玩家落子模块

do

{printf("\npleaseenterthecoordinatewhereyouwanttoputyourX:

");

scanf("%d,%d",&row,&column);

if(row*column>9||row*column<1||board[row-1][column-1]!

='\0')

printf("\nfaultposition!

pleasereput:

");

}while(row*column>9||row*column<1||board[row-1][column-1]!

='\0');

printf("\n\nplayermove\n");

board[row-1][column-1]='X';

printboard();

step++;

check();

if(winner!

='\0'||step==9)break;

//计算机落子模块

printf("\n\ncomputermove\n");

for(row=0;row<3;row++)

{

for(column=0;column<3;column++)

{

if(board[row][column]=='\0')

{

board[row][column]='O';

gotoend;

}

}

}end:

;

printboard();

step++;

check();

}

(3)执行对弈的充分条件while(winner=='\0'&&step!

=9)表示胜者未出现且步数未满九。

一旦人机共走了九步,棋盘已被占满,则不论是否出现胜者都必须结束游戏。

(4)计算机落子采取逐行逐列(两个for循环的嵌套)检索空格再落子的办法,简单机械,实际上并未对玩家的落子情况做出应对。

不够智能是这个游戏程序的弱点。

(5)判断谁是赢家,利用winner带回的字符。

'O'是计算机的落子,故winner='O'表示计算机获胜。

同理玩家获胜、平局亦是如此。

if(winner=='O')

printf("*****youlose!

*****\n");

elseif(winner=='X')

printf("*****youwin!

*****\n");

elseif(winner=='\0')

printf("*****draw!

*****\n");

return0;

 

2.打印棋盘函数

双方每走一步都要打印棋盘,故该模块做成一个函数体。

函数本身只要求实现打印棋盘即可,只需调用一个printf函数,并不复杂。

 

3.判断胜负函数

双方每走一步都要判断是否分出胜负,以告知程序对战是否继续执行。

分析游戏规则,某行或某列或某条对角线连成线则胜者出现。

三行三列两对角,共八种情况,循环语句难以实现判断,不如干脆穷举罗列。

(详见voidcheck()函数的定义部分)在此基础上略作简化:

第一行、第一列交于左上格,故合并判断左上格的值即可;第二行、第二列交于中心格,故合并判断中心格的值即可;第三行、第三列交于右下格,故合并判断右下格的值即可;两条对角线交于中心格,故合并判断中心格的值即可。

这样if语句可省去一半。

 

§1.4实验数据及运行效果截图

棋盘界面

 

对弈过程,玩家输

 

平局

 

输入错误,重新输入

 

玩家获胜

 

§1.5设计中出现的错误及解决方法

首次尝试大一点的程序设计,没想到直接去设计游戏,果然很有挑战。

这个程序主体不大,不需要设计多少模块,程序的难点在算法上。

1.在判断玩家落子是否正确时,开始我用if((row*column>9||row*column<1)||board[row-1][column-1]!

='\0')来判定落子错误,结果输入1,4时,在棋盘2,1处输出了’X’,虽然有输出,但显然不合要求;输入4,1时不报错,但计算机有输出,显然错误。

【解决方法】追加了两个判断条件row>3和column>3,将上述判断条件改为

if(((row*column>9||row*column<1)||(board[row-1][column-1]!

='\0'||column>3))||row>3)这样,只要其中一个条件成立,则返回重新输入坐标。

2.在执行游戏时,开始未设计计算步数的变量step,结果棋盘下满时,不论是否分出胜负,均报告平局draw!

【解决方法】设计变量step,在玩家或计算机每下一步后使其加一,将对弈程序的循环条件改为while(winner=='\0'&&step!

=9),即未分胜负且棋盘未满,再统一判断胜负平。

3.在设计计算机落子模块时,开始时玩家落子后,计算机连下好几步,因为光用两个for循环只能要求计算机找出空位落子,不能控制计算机落子次数。

几经考虑,设计了两种方案:

(1)追加一个标记变量k,使计算机未落子时,k置为0,否则置为1;再在for循环中检查k的值,一旦为1,退出循环。

设计如下:

k=0;

for(row=0;row<3;row++)

{if(k==1)break;

for(column=0;column<3;column++)

{

if(board[row][column]=='\0')

{k=1;

board[row][column]='O';

break;}

}

}

}

(2)调用"stdlib.h"头文件中的goto函数。

计算机一旦落子,则执行,程序直接跳到循环末尾。

设计如下:

for(row=0;row<3;row++)

{for(column=0;column<3;column++)

{

if(board[row][column]=='\0')

{

board[row][column]='O';

gotoend;

}

}

}end:

;

【解决方法】方案

(2)更简洁,更清楚,实际采用了方案

(2)

4.在设计判断胜负模块时,在判断胜负的方法上几经改进,题目要求“三点一线”则获胜,3*3的棋盘有三行三列两对角,共八种情况,开始时设计八个if语句的嵌套结构,虽然可以运行,但程序冗长可读性低,且判断结果相互交叉,造成运行的事倍功半。

【解决方法】巧妙设计了一个成对判断的算法,使程序节省了一半篇幅。

详见第三节—>代码分析—>判断胜负函数

5.在考虑计算机的落子模式时,我曾尝试过更加复杂的算法,使其不单纯按顺序扫描棋盘落子,力图使其优先追加判断胜负的能力,能赢时下赢着,快输时下守着,但算法实在太复杂,考虑的情况太多,连用八个if语句的嵌套,程序变得十分臃肿难看,而且还不够且运行总是异常,考虑到时间因素,很遗憾未能深入考虑,优化设计,就此搁浅。

结语:

此次游戏软件的设计,不但让我熟悉了软件制作的流程,熟悉了用C进行程序开发的基本方法,还让我了解了软件制作的来之不易,更加坚定了“支持正版,打击剽窃”的信念。

一款好的软件必定集结了各种优秀的要素:

良好的制作环境、熟练的软件设计师、精炼到位的算法、清晰明了的模块化程序设计、千百次的编译调试等等。

开始制作游戏时,我一门心思考虑算法,碰到种种障碍,后来通过海量地查阅资料,才深感知识浅薄、无可奈何。

有些问题只要调用一个函数就能解决,我却洋洋洒洒罗列了各种情况分类讨论。

差距是显然的。

知识匮乏加经验欠缺,这是我在这几天所深深领会的东西。

我尽己所能完成了题目的要求。

在整个课程设计中,我认为最重要的就是耐心和细心。

细心,就是在编写过程中注意拼写,仔细编写程序;耐心,就是程序编译中出现很多错误的时候能够耐心去修改,只有这样,才能很好的完成程序。

 虽然在整个过程中出现了不少错误,但最终还是圆满完成了,

此次c程序设计的经历,我学到很多,同时也让我深刻明白知识及经验对程序开发员的必要性。

从今往后,我还得不断丰富自己的知识储备和提高自己的编程经验。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 幼儿教育 > 育儿知识

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1