司机镇楼!!!!!!
口号:好好学习,努力养家
备注:看了正式版看不懂可以转接娱乐版
注意:这是个对于初学者来说的大型工程,分成了三部分来写:test.c,game.c,game.h
正式版:
兄台,也不知道你同不同意,我就放个链接!谢谢!
(18条消息) 三子棋代码实现思路解析与易错点纠正_xbhinsterest11的博客-CSDN博客
这位兄台的就很不错,正式版就用这位大神的吧
娱乐版:
test.c(游戏的测试逻辑)
#define _CRT_SECURE_NO_WARNINGS 1
//游戏的测试逻辑,game.h和game.c才是游戏的主题,这边你可以认为就是个“主函数”
//game为“副函数”船长离不开大副
//船长只是一个主心骨负责统领,大副才是真正干实事的大佬
//#include<stdio.h>证明我存在过,只是后来觉得重复,你不要了,哎!像极了备胎
#include"game.h"//这是自己写的头文件
void menu()
{printf("**************\n");printf("****1.play****\n");printf("****0.exit****\n");printf("**************\n");
}
void game()
{//三子棋,要先有棋盘//要有电脑和人相互下棋的操作//任何下棋后下棋的位置要保存起来//输入的棋子是输入的字符,而棋盘输入是3*3的,我们输入字符输入时是几行几列//所以相当于是一个字符类型的二维数组//******************************************//以上为思考,下面是定义//数据存储到一个字符的二维数组中,玩家下棋是“*”电脑下棋是“#”//这里先构建棋盘,再下棋char board[ROW][COL] = { 0 };//数组的内容应该是全部空格InitBoard(board, ROW, COL);//初始化棋盘//打印棋盘确定是不是初始化正确,不过说实话,你一步步来咋可能错吗?DisplayBoard(board, ROW, COL);//注意哦,不要一看到打印就行到printf,这也打印不出来呀!char ret = 0;while (1){player_move(board,ROW,COL);//玩家下棋一样是在几行几列下棋//是在这个二维数组里面下棋DisplayBoard(board, ROW, COL);//打印棋盘ret = is_win(board, ROW, COL);//马上来一次判断是平局还是继续if (ret != 'C')//-C是继续,-Q是平局{break;//意思就是如果返回值不等于继续-'C'就跳出循环//就是说只要不是继续下棋肯定就是出结果了,不要呆在这个while循环里了}computer_move(board, ROW, COL);//电脑下棋DisplayBoard(board, ROW, COL);//打印棋盘ret = is_win(board, ROW, COL);//注意一定要有,不然你会很困惑,建议尝试去点一下//补充if (ret != 'C'){break;}//到了这里,框架结束,要开始判断输赢了}if(ret == '*'){printf("玩家胜利!\n");}else if(ret == '#'){printf("电脑赢!\n");}else{printf("平局!\n");}
}
void test()
{int input = 0;do{menu();printf("请选择:");scanf("%d", &input);switch (input){case 1:printf("三子棋\n");game();//真正的三子棋游戏break;case 0:printf("退出游戏\n");break;default:printf("选择错误\n");}} while (input);//非零为真,运行选择程序,为零则跳出结束游戏//这就是用do while 的原因,while是零也已经进行了一次do循环
}int main()
{srand((unsigned)time(NULL));test();return 0;
}
game.h(游戏的实现函数声明)
//建议最开始来这么一句,就好像做ppt呀开题要告诉下面的老师,你要讲啥
//游戏的实现函数的声明
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>//这个东东写在这纯属因为啊printf动不动来个未定义
//反正两个c文件都要用,干脆写在都需要调用的game.h里面
#include<time.h>
#include<stdlib.h>
//在头文件里宏定义行和列
//减少不必要的操作且直观清楚
//即如果是10*10的十字棋,只需要在宏定义修改即可
//说实话,你要是觉得也麻烦不想写英文也不用这样
#define ROW 3
#define COL 3
void InitBoard(char board[ROW][COL], int row, int col);//注意区分大小写
//注意:这里的row和ROW不是一个东西
//InitBoard(board,ROW,COL);//初始化棋盘操作
//这句话括号内的参数ROW和COL是int整形,用row表示,这样清楚且不冲突
//这里只是函数声明,函数实现在game.c里进行
void DisplayBoard(char board[ROW][COL], int row, int col);
//啰嗦一句,数组传参,用char a[][]用来接收a[][],或者用指针
//详细说明一下
void player_move(char board[ROW][COL],int row,int col);
//电脑下棋,在ROW*COL的棋盘的(row,col)下棋
void computer_move(char board[ROW][COL], int row, int col);
//判断输赢的代码
//玩家赢-'*'
//电脑赢-'#'
//平局-'Q'
//继续-'C'
char is_win(char board[ROW][COL], int row, int col);
game.c(游戏的实现逻辑)
#define _CRT_SECURE_NO_WARNINGS 1
//游戏的实现逻辑
#include"game.h"
//留一行给未来的老婆,(原谅我复习的时候也不记得这个啥意思了)
void InitBoard(char board[ROW][COL], int row, int col)
{//在board(3*3的棋盘)中下棋,row和col为落子位置的行和列//即将数组全部初始化为空格,构建棋盘int i = 0;int j = 0;for (i = 0; i < row; i++){for (j = 0; j < col; j++){board[i][j] = ' ';//注意啊,这里有个空格} }}
//void DisplayBoard(char board[ROW][COL], int row, int col)
//{
// //此处并不是直接打印空格就行了
// int i = 0;
// int j = 0;
// for (i = 0; i < row; i++)
// {
// printf(" %c | %c | %c \n",board[i][0],board[i][1],board[i][2]);
// if (i < row - 1)
// {
// //即代表第三行不要打印下面这东东
// printf("---|---|---\n");
// }
// //注意,可以试着打印一下
// //发现第三行打印的这个———没有必要
// //哈哈哈,你终于打完了棋盘!congratuation!!!
// //结果你发现这种方叫做傻瓜打印法,只适用于三子棋
// //注释掉
// }
//
//}
void DisplayBoard(char board[ROW][COL], int row, int col)
{int i = 0;int j = 0;for (i = 0; i < row; i++){//数据for (j = 0; j < col; j++){printf(" %c ",board[i][j]);//逗号后面别忘记,说给自己听的if (j < col - 1){printf("|");}//打个比方,3行3列,i=0,j=0,打印第一列,0<3-1,打印|//j=1,打印第二列,1<3-1,打印|//j=2,打印第三列,2=3-1,不打印}printf("\n");//把他们分开,换行,打印完第一行打印第二行//下面打印---|---|---//分割行//把你放在身边怕忘记//井// | | (数组第一行)//---|---|--- (这就是分割线)// | | (数组第二行)//---|---|--- (分割线)// | | (数组第三行)//所以下一步看怎么打印分割线if (i < row - 1)//同理第三行不要了{for (j = 0; j < col; j++){printf("---");if (j < col - 1){printf("|");}}}printf("\n");}//别忘记!}void player_move(char board[ROW][COL], int row, int col)
{printf("玩家下棋:\n");//井字棋,玩家只能下在三行三列这个范围内int x = 0;int y = 0;while (1){scanf("%d %d", &x, &y);//想办法加个条件让他只能3*3if (x >= 1 && x <= row && y >= 1 && y <= row){//下过棋的地方不能再下棋//我们看到的第一行第一列,电脑看到的是第零行零列//所以x-1,y-1if (board[x - 1][y - 1] == ' ')//注意此处是单引号{board[x - 1][y - 1] = '*';break;}else{printf("该坐标被占用,请重新输入!\n");}//留心细节单双引号,单引号在字符常量时使用,表示单个字符。//char c = 'aA'; // 编译出错,单引号只能是一个字符//char c = ''; // 单引号中间没有任何字符时,编译出错//双引号在表示字符串常量时使用,可以表示0到多个字符组成的字符串。//char s1[] = "a";//char s2[] = "a1A";//char s3[] = ""; // 双引号中间可以没有任何字符,表示空字符串}else{printf("坐标非法!请重新输入!\n");}}
}//这样电脑下棋太蠢,待优化
void computer_move(char board[ROW][COL], int row, int col)
{int x = 0;int y = 0;printf("电脑下棋:\n");//电脑随机下,更难的不会,初学者望谅解while(1){x = rand() % ROW;//这样余数就只可能是0,1,2三种y = rand() % COL;if (board[x][y] == ' ')//这里没有减一是因为前面xy已经限制好了{board[x][y] = '#';break;//一定要,不然电脑就会一直下棋}//不需要else了,不解释}
}//判断结果
int is_full(char board[ROW][COL], int row, int col)
{int i = 0;int j = 0;for (i = 0; i < row; i++){for (j = 0; j < col; j++){if (board[i][j] == ' '){return 0;}}}return 1;//位置不要放错
}//下面也写死了,需要下多行棋时,需要进行修改
char is_win(char board[ROW][COL], int row, int col)
{int i = 0;//三行的判断for (i = 0; i < row; i++){if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][1] != ' '){return board[i][1];}}//三列的判断for (i = 0; i < col; i++){if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[1][i] != ' '){return board[1][i];}}//对角线的情况判断if (board[0][0] == board[1][1] && board[1][1] == board[2][2]&&board[1][1]!=' '){return board[1][1];}if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' '){return board[1][1];}//判断平局//即有空格说明没有平局if (1 == is_full(board, row, col))//注意这是在函数char is_win(char board[ROW][COL], int row, int col)里{return 'Q';}//继续return 'C';
}