学习前
想象特别美好,现实特别残酷,脑袋里感觉每个点都想到怎么写了,就打算自己试试,结果发现总会卡壳,直到学习了一下具体写法,真是大彻大悟。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
void Menu(void)
{
printf("************************\n");
printf("*******三子棋游戏*******\n");
printf("************************\n");
printf("*********play 1*********\n");
printf("*********exit 0*********\n");
printf("************************\n");
}
int Game()
{
int a[3][3] = { 0 }, b = 0, c = 0;
int b[3][3] = { 0 }, c[3][3] = 0;
int i = 0, j = 0,k=0,l=0,m=0,n=0,part=0;
printf("*********游戏开始喽*********\n");
printf("双方轮流输入下棋位置\n");
for (i = 0; i < 3; i++) {
for (j = 0; j < 3; j++)
printf("%d ", a[i][j]);
printf("\n");
}
part++;
if (part % 2 != 0) {
scanf("%d%d\n", &k, &l);
printf("\n");
}
}
int main()
{
int a;
do {
Menu();
scanf("%d", &a);
switch (a)
{
case 0:goto byebye;
case 1:goto again;
}
} while (1);
byebye:
printf("Goodbye!\n");
again:
Game();
return 0;
步骤一 分析所写程序
1.可反复参与游戏、可自行退出
2.应用多文件写代码
test.c 游戏测试
game.c 游戏函数的实现
game.h 游戏函数的声明
pppps. 包含自己头文件形式 #include “game.h”
宏定义的使用:已知3*3二维数组一直不变/方便改想要的格数
3.需要3*3的二维数组存储数据
4.棋盘在每个阶段怎么设计
5.下棋时具体情况细节,能不能落子,玩家输错提示,重新输入
6.怎样设计之后方便更改(宏定义)
步骤二 写好主函数框架
int main()
{
int input;
srand((unsigned int)time(NULL));
do {
Menu();
scanf("%d", &input);
switch (input)
{
case 0:printf("退出游戏~下次见咯!\n");
break;
case 1:Game();
break;
default:printf("输入有误,请重新输入:\n");
}
} while (input);
return 0;
}
步骤三 游戏实现文件
在这一部分中,我觉得比较难理解的是设计棋盘的部分和判断输赢部分,下面我来简略解释一下这两个部分:
Display_board
void Display_board(char board[ROW][COL], int row, int col)//棋盘设计
{
int i, j;
for (i = 0; i < ROW; i++)
{
//这个部分有两个列循环
//分别是数据打印和棋盘分割线打印
//打印数据行格式 “ %c | %c | %c ” 上图中蓝绿色部分
//打印分割线格式 “ ---|----|--- ” 上图中黄色部分
//打印方式不唯一哦
for (j = 0; j < COL; j++)
{
//打印数据
printf(" %c ", board[i][j]);
if (j < col - 1)//最后一个数据打印完无需“|”
printf("|");//由列数控制
}
printf("\n");//容易遗忘
//打印分割线
if (i < row - 1){
int j;
for (j = 0; j < col; j++) {
printf("---");
if (j < col-1 )
printf("|");//和列数相关
}
printf("\n");
}
}
printf("\n"); //切记每一行打印完都需要换行打印!!!
}
需要注意的点
1.每次落子后都需再次调用棋盘设计函数
2.无论是玩家下棋还是电脑下棋都要采取赋值的方式,直接打印棋子会导致如下情况
3.形参和实参不要搞混
4.注意参数定义范围,切忌重复定义
Is_Win
char Is_Win(char board[ROW][COL], int row, int col)
{//整体思路 _主函数通过Is_Win 函数返回值来给用户反馈
//这个部分需要分为四个部分
//分别从行、列、对角线获胜 + 平局 + 未满足以上两种情况继续游戏
//行
int i; for (i = 0; i < row; i++) { //行相等且都不为空才能满足赢的条件 if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][2] != ' ') return board[i][0];//返回满足该条件的符号 }
//列
int j = 0; for (j = 0; j < col; j++) { //列相等且都不为空才能满足赢的条件 if (board[0][j] == board[1][j] && board[1][j] == board[2][j] && board[2][j] != ' ') return board[0][j];//返回满足该条件的符号 }
//对角线
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] != ' ') return board[0][0]; else if (board[1][1] == board[0][2] && board[0][2] == board[2][0] && board[1][1] != ' ') return board[1][1];
//平局
//单独定义一个函数_我理解为方便定义变量
//避免变量重复定义或定义新变量的复杂情况
int Is_FULL(char board[ROW][COL], int row, int col) { int i, j; for (i = 0; i < row; i++) { int j; for (j = 0; j < col; j++) { //判断有无落子区域 //有一个就返回0 //无落子区域则返回1 if (board[i][j] == ' ') return 0; } } return 1; } if (Is_FULL(board, row, col) == 1) { return 'Q'; }
//不满足以上任何一种情况 则返回 ' C '
//当既不满足获胜条件也不满足无法落子情况,游戏继续 return 'C'; //继续
}
完整代码分享(欢迎交流讨论哦)
game.h
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include <time.h> #define ROW 3 #define COL 3 //棋盘初始化 void Initboard(char board[ROW][COL], int row, int col); //设计棋盘 void Display_board(char board[ROW][COL], int row, int col); //玩家下棋 void Player_board(char board[ROW][COL], int row, int col); //电脑下棋 void Computer_Player(char board[ROW][COL], int row, int col); //判断输赢,返回相应符号 char Is_Win(char board[ROW][COL], int row, int col); //判断是否还有落子区域 //这里重新建一个函数我认为是方便定义变量 //避免变量重复定义的复杂情况 int Is_FULL(char board[ROW][COL], int row, int col);
test.c
#define _CRT_SECURE_NO_WARNINGS #include "game.h" #define ROW 3 #define COL 3 void Menu(void) { printf("************************\n"); printf("*******三子棋游戏*******\n"); printf("************************\n"); printf("*********play 1*********\n"); printf("*********exit 0*********\n"); printf("************************\n"); } int Game()//游戏实现 { char board[ROW][COL] = { 0 }; Initboard(board,ROW ,COL); Display_board(board, ROW, COL); char ret = 0; while (1) { //玩家下棋 Player_board(board, ROW, COL); Display_board(board, ROW, COL); //判断输赢 ret=Is_Win(board, ROW, COL);//返回一个值,再判断 if (ret != 'C') break; //计算机下棋 Computer_Player(board, ROW, COL); Display_board(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"); } int main() { int input; srand((unsigned int)time(NULL)); do { Menu(); scanf("%d", &input); switch (input) { case 0:printf("退出游戏~下次见咯!\n"); break; case 1:Game(); break; default:printf("输入有误,请重新输入:\n"); } } while (input); return 0; }
注意!
无论是玩家下棋还是电脑下棋,都牵涉输赢情况的改变,所以每次下完都需要返回一次Is_Win的值
game.c
#define _CRT_SECURE_NO_WARNINGS #include "game.h" #include <stdio.h> //游戏中应用到的代码 void Initboard(char board[ROW][COL],int row,int col)//棋盘初始化 { int i ,j; for (i = 0; i < row; i++) for (j = 0; j < col; j++) board[i][j] = ' '; } void Display_board(char board[ROW][COL], int row, int col)//棋盘设计 { int i, j; for (i = 0; i < ROW; i++) { for (j = 0; j < COL; j++) { //打印数据 printf(" %c ", board[i][j]); if (j < col - 1)//最后一个数据打印完无需“|” printf("|");//由列数控制 } printf("\n");//容易遗忘 //打印分割线 if (i < row - 1){ int j; for (j = 0; j < col; j++) { printf("---"); if (j < col-1 ) printf("|");//和列数相关 } printf("\n"); } } printf("\n"); } void Player_board(char board[ROW][COL], int row, int col) { int x=0, y=0; printf("玩家下棋>\n"); while (1) { printf("请输入下棋坐标:\n"); scanf("%d %d", &x, &y); /*if (sizeof(x) != sizeof(int) || sizeof(y) != sizeof(int)) { printf("输入格式错误,请重新输入\n"); break; }*/ if (x >= 1 && x <= row && y >= 1 && y <= col)//玩家输入合法 { if (board[x - 1][y - 1] == ' ')//是否有空位可以落子 { // printf("*", board[x - 1][y - 1]); break;//错误写法,会使棋盘错位 board[x - 1][y - 1] = '*'; break;//一定要记得break否则会陷在此函数,棋盘消失 } else printf("此位置已被占用,请重新输入!\n"); } else//不合法 { printf("输入非法,请重新输入\n"); } } } void Computer_Player(char board[ROW][COL], int row, int col) { //电脑下棋 int x = 0, y = 0; printf("电脑下棋>\n"); while (1) //一直生成随机数,直到满足落子条件 { x = rand() % row;//生成随机数 y = rand() % col; if (board[x][y] == ' ')//判断能否落子 { board[x][y] = '#';//一定要采用赋值哦,不然棋盘会错位 break; } } } int Is_FULL(char board[ROW][COL], int row, int col) { int i, j; for (i = 0; i < row; i++) { int j; for (j = 0; j < col; j++) { if (board[i][j] == ' ')//判断有无落子区域有一个就返回0都无则返回1 return 0; } } return 1; } char Is_Win(char board[ROW][COL], int row, int col) { //行 int i; for (i = 0; i < row; i++) { //行相等且都不为空才能满足赢的条件 if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][2] != ' ') return board[i][0];//返回满足该条件的符号 } //列 int j = 0; for (j = 0; j < col; j++) { //列相等且都不为空才能满足赢的条件 if (board[0][j] == board[1][j] && board[1][j] == board[2][j] && board[2][j] != ' ') return board[0][j];//返回满足该条件的符号 } //对角线 if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] != ' ') return board[0][0]; else if (board[1][1] == board[0][2] && board[0][2] == board[2][0] && board[1][1] != ' ') return board[1][1]; //判断是否还有落子区域 if (Is_FULL(board, row, col) == 1) { return 'Q'; } //当既不满足获胜条件也不满足无法落子情况,游戏继续 return 'C'; //继续 }