目录
一:先写三子棋的开始菜单逻辑
二.接下来写game()部分。
1.初始化棋盘(InItbroad)
2.打印棋盘(Dispalybroad)
3.玩家输入(player_move)
接下来实现电脑下棋:computer_move
1.实现随机,需要用?rand &&?srand && time 函数?
判断输赢(is_win)
1.判断行
2.判断列:
3.*判断对角线:
4.判断平局:
所以,最终我们写成:
最后
实现这个三子棋,想要他能实现: 1.先打印一个3X3的棋盘→九宫格→3X3二维数组→分割行 2.玩家下棋和电脑下棋的位置都要存储
一:先写三子棋的开始菜单逻辑
#include<stdio.h>
void menu()
{
printf("**************************\n");
printf("*********1.start**********\n");
printf("*********0. exit *********\n");
printf("**************************\n");
}
void test()
{
int input = 0;
do
{
menu();
printf("请输入>");
scanf("%d", &input);
switch (input)
{
case 1:
//game()
printf("开始游戏\n");
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("重新输入\n");
}
} while (input);
}
int main()
{
test();
return 0;
}
?逻辑没有问题
二.接下来写game()部分。
1.首先需要打印棋盘,九个位置必须是初始化为空格,且要有分割行。 我们写三个文件: test.c→游戏逻辑 game.c→游戏的实现 game.h→函数的声明
1.首先我们要求, row为行,col为列
这样写的优势在于:以后我如果想打印10x10的棋盘,只需要修改row,col的定义即可,这样就更方便我进行修改。
接下来的关于游戏的函数都写在test.c里的game()文件里,函数的实现写在game.c文件里
1.初始化棋盘(InItbroad)
void InItbroad(char broad[ROW][COL], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
int j = 0;
for (j = 0; j < col; j++)
{
broad[i][j] = ' ';
}
}
}
2.打印棋盘(Dispalybroad)
重点在于如何添加分割行 倘若我们这样写:
void Dispalybroad(char broad[ROW][COL], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
int j = 0;
for (j = 0; j < col; j++)
{
printf("%c", broad[i][j]);
}
printf("\n");
}
}
那么打印的将会是全是空格,什么也看不见 ?
观察可得,是_ _ _ 一个 | ,中间是我们数据。?所以我可以写成:?
void Dispalybroad(char broad[ROW][COL], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
int j = 0;
for (j = 0; j < col; j++)
{
printf(" %c ", broad[i][j]);//打印数据
if (j < col - 1)
{
printf("|");
}
}
printf("\n");
//打印分割行
if (i < row - 1)
{
for (j = 0; j < col; j++)
{
printf("---");
if (j < col - 1)
printf("|");
}
}
printf("\n");
}
}
3.玩家输入(player_move)
数组虽说是0开始,但是玩家输入要从1开始。所以我可以写成:
void player_move(char broad[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
while (1)
{
printf("玩家下棋,请输入坐标:\n");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
//下棋
if (broad[x - 1][y - 1] == ' ')
{
broad[x - 1][y - 1] = '*';
break;
}
else
{
printf("坐标被占用,重输入\n");
}
}
else
{
printf("输入非法,重新输入\n");
}
}
}
接下来实现电脑下棋:computer_move
1.实现随机,需要用?rand &&?srand && time 函数
void computer_move(char broad[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("电脑下棋\n");
while (1)
{
x = rand() % row; //0-2
y = rand() % col; //0-2
if (broad[x][y] == ' ')
{
broad[x][y] = '#';
break;
}
}
}
1.使用rand函数前,需在调用game函数前调用一次srand函数。我们引用time.h和stdlib.h头文件,然后使用srand,传入time空指针。以时间为参照物实现随机。 2.为什么是rand()%row,rand()%col呢? 这涉及一个小学问题:要使余数最大,方框里分别填几? 答:余数肯定比除数要小,要想余数最大,就只能除以比余数小1的数。 例如:rand()%3,那么他的余数最大,就是2
判断输赢(is_win)
第一步,先将玩家和用户下棋的部分设为循环,再加入判断输赢的函数,决定是否需要跳出循环,打印结果,结束游戏。 game()逻辑部分我们这样设定,来实现判断: 玩家赢→'*' 电脑赢→'#' 平局→'Q' 继续→'C'
void game()
{
char ret = 0;
//存放下棋的数据
char broad[ROW][COL] = { 0 };
//初始化棋盘
InItbroad(broad, ROW, COL);
//打印棋盘
Dispalybroad(broad, ROW, COL);
//玩家下棋
while (1)
{
player_move(broad, ROW, COL);
Dispalybroad(broad, ROW, COL);
//判断输赢
ret = is_win(broad, ROW, COL);
if (ret != 'C')
{
break;
}
//电脑下棋
computer_move(broad, ROW, COL);//随机
Dispalybroad(broad, ROW, COL);
ret = is_win(broad, ROW, COL);
if (ret != 'C')
{
break;
}
}
if (ret == '*')
{
printf("玩家赢了\n");
}
else if (ret == '#')
{
printf("电脑赢\n");
}
else if(ret =='Q')
{
printf("平局\n");
}
Dispalybroad(broad, ROW, COL);
}
?第二步,我们来写输赢判断函数(is_win).(初学者可以先自己思考一番)
1.判断行
//判断行
int i = 0;
for (i = 0; i < row; i++)
{
int count = 0;
int j = 0;
for (j = 0; j < col-1; j++)
{
if ( broad[i][j] == broad[i][j + 1] && broad[i][0] != ' ')
{
count++;
}
}
if (count == col - 1)
{
return broad[i][0];
}
}
我当时写遇到的第一个问题:如果我不引用count来计数的话,就难以建立判断条件。
2.判断列:
//判断列
for (i = 0; i < col; i++)
{
int count = 0;
int j = 0;
for (j = 0; j < row-1; j++)
{
if (broad[j][i] == broad[j + 1][i] && broad[0][i] != ' ')
{
count++;
}
}
if (count == row - 1)
{
return broad[0][i];
}
}
3.*判断对角线:
左斜对角线: 假若我们这样写:
//判断左斜对角线 row行, col 列
for (i = 0; i < col-1; i++)
{
int count2 = 0;
if (broad[i][i] == broad[i + 1][i + 1] && broad[0][i] != ' ')
{
count2++;
}
if (count2 == col - 1)
{
return broad[0][0];
}
}
这样写就会有一个非常明显的错误,当我条件已经不满足for语句时,我就不会进入for语句,也就不会进入判断部分。所以我们要把判断部分拿出来:
int count2 = 0;
for (i = 0; i < col - 1; i++)
{
if (broad[i][i] == broad[i + 1][i + 1] && broad[0][i] != ' ')
{
count2++;
}
}
if (count2 == col - 1)
{
return broad[0][0];
}
右斜对角线: 假若我们不知道for语句可以同时对两个变量进行调整的话,我们也许会这样写:
这样写的话,他会等到 j 这个变量走完后,才调整i这个变量,j和i并不会同时变化。于是我想了办法,使用goto语句:
?这样写,最终造成了死循环。
这段代码有两个错误,其中最为严重的是goto语句的错误使用。 原因是:goto语句会直接跳到标签部分,而不会进入调整部分,i++和j--都不会被执行,因此造成了死循环。 第二个次要问题在于if在for语句里面,倘若for语句不成立了,就不会进入到判断部分。
最后询问了@^jhao^后,找到了正确的写法,应该写成这种形式:两个调整部分。
?所以,最终应该写成
//右斜对角线row行, col 列
int count = 0;
for (int j = col - 1, i = 0; i < row - 1 && j>0; i++, j--)//0 1 2
{
if (broad[i][j] == broad[i + 1][j - 1] && broad[0][col - 1] != ' ')
{
count++;
}
}
if (count == col - 1)
{
return broad[0][col - 1];
}
4.判断平局:
我们直接写一个ping函数,来进行判断
//判断平局
if (ping(broad,row,col) == 1)
{
return 'Q';
}
接下来实现ping函数部分 假若我们这样写:
int ping(char broad[ROW][COL], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
int j = 0;
for (j = 0; j < col; j++)
{
if (broad[i][j] != ' ')
{
return 0;//没满
}
}
}
return 1;
}
程序到最后会出问题,为什么? 原因在于if判断部分出了问题。 假若我们broad[ i ][ j ] ! = '? ',那就说明,他是存了东西的,但他只能证明这一个地方存了东西,而不能证明所有的格子,都存了东西。第一次写这个代码时,在这里逻辑就可能会出错,必须要多加小心。 改正方法: 法1:我可以把return改写成continue,但是这样的话要引入变量,就比较冗余。 法2:我直接把!=’ ‘,改写成 ==,即可。
所以正确写法是:
int ping(char broad[ROW][COL], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
int j = 0;
for (j = 0; j < col; j++)
{
if (broad[i][j] == ' ')
{
return 0;//没满
}
}
}
return 1;
当以上情况都不满足时,我们直接return 'C',继续游戏。
所以,最终我们写成:
test.c:
#include"game.h"
void menu()
{
printf("**************************\n");
printf("*********1.start**********\n");
printf("*********0. exit *********\n");
printf("**************************\n");
}
void game()
{
char ret = 0;
//存放下棋的数据
char broad[ROW][COL] = { 0 };
//初始化棋盘
InItbroad(broad, ROW, COL);
//打印棋盘
Dispalybroad(broad, ROW, COL);
//玩家下棋
while (1)
{
player_move(broad, ROW, COL);
Dispalybroad(broad, ROW, COL);
//判断输赢
ret = is_win(broad, ROW, COL);
if (ret != 'C')
{
break;
}
//电脑下棋
computer_move(broad, ROW, COL);//随机
Dispalybroad(broad, ROW, COL);
ret = is_win(broad, ROW, COL);
if (ret != 'C')
{
break;
}
}
if (ret == '*')
{
printf("玩家赢了\n");
}
else if (ret == '#')
{
printf("电脑赢\n");
}
else if(ret =='Q')
{
printf("平局\n");
}
Dispalybroad(broad, ROW, COL);
}
/*
什么时候赢呢?
玩家赢→'*'
电脑赢→'#'
平局→'Q'
继续→'C'
*/
void test()
{
int input = 0;
srand((unsigned int) time(NULL));
do
{
menu();
printf("请输入>");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("重新输入\n");
}
} while (input);
}
int main()
{
test();
return 0;
}
game.h:
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#define ROW 3
#define COL 3
#include<stdlib.h>
#include<time.h>
void InItbroad(char broad[ROW][COL], int , int );//初始化棋盘
void Dispalybroad(char broad[ROW][COL], int , int );//打印棋盘
void player_move(char broad[ROW][COL], int , int );//玩家下棋
void computer_move(char broad[ROW][COL], int, int);//电脑下棋
char is_win(char broad[ROW][COL], int, int);//判断输赢
game.c:
#include"game.h"
void InItbroad(char broad[ROW][COL], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
int j = 0;
for (j = 0; j < col; j++)
{
broad[i][j] = ' ';
}
}
}
void Dispalybroad(char broad[ROW][COL], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
int j = 0;
for (j = 0; j < col; j++)
{
printf(" %c ", broad[i][j]);//打印数据
if (j < col - 1)
{
printf("|");
}
}
printf("\n");
//打印分割行
if (i < row - 1)
{
for (j = 0; j < col; j++)
{
printf("---");
if (j < col - 1)
printf("|");
}
}
printf("\n");
}
}
void player_move(char broad[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
while (1)
{
printf("玩家下棋,请输入坐标,行,列:\n");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
//下棋
if (broad[x - 1][y - 1] == ' ')
{
broad[x - 1][y - 1] = '*';
break;
}
else
{
printf("坐标被占用,重输入\n");
}
}
else
{
printf("输入非法,重新输入\n");
}
}
}
void computer_move(char broad[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("电脑下棋\n");
while (1)
{
x = rand() % row; //0-2
y = rand() % col; //0-2
if (broad[x][y] == ' ')
{
broad[x][y] = '#';
break;
}
}
}
int ping(char broad[ROW][COL], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
int j = 0;
for (j = 0; j < col; j++)
{
if (broad[i][j] == ' ')
{
return 0;//没满
}
}
}
return 1;
}
char is_win(char broad[ROW][COL], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
int count = 0;
int j = 0;
for (j = 0; j < col - 1; j++)
{
if (broad[i][j] == broad[i][j + 1] && broad[i][0] != ' ')
{
count++;
}
}
if (count == col - 1)
{
return broad[i][0];
}
}
//判断列
for (i = 0; i < col; i++)
{
int count = 0;
int j = 0;
for (j = 0; j < row - 1; j++)
{
if (broad[j][i] == broad[j + 1][i] && broad[0][i] != ' ')
{
count++;
}
}
if (count == row - 1)
{
return broad[0][i];
}
}
//判断对角线 row行, col 列
int count2 = 0;
for (i = 0; i < col - 1; i++)
{
if (broad[i][i] == broad[i + 1][i + 1] && broad[0][i] != ' ')
{
count2++;
}
}
if (count2 == col - 1)
{
return broad[0][0];
}
//row行, col 列
int count = 0;
for (int j = col - 1, i = 0; i < row - 1 && j>0; i++, j--)//0 1 2
{
if (broad[i][j] == broad[i + 1][j - 1] && broad[0][col - 1] != ' ')
{
count++;
}
}
if (count == col - 1)
{
return broad[0][col - 1];
}
//判断平局
if (ping(broad,row,col) == 1)
{
return 'Q';
}
//继续
return 'C';
}
程序正常运行
最后
感谢@^jhao^。 初学者可以试写这段代码,可以加强对分支循环语句,二维数组的理解与运用。
|