提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
没用多文件是因为觉得麻烦,头文件引来引去更懵了,几乎每个文件都把所有的都引了一遍,好累写的时候翻来翻去,总是找不对文件好浪费时间,所以没有分开写
步骤
1.主函数
首先,非常显然我们需要打印一个菜单,有玩游戏和退出两个功能,一个switch语句就可以解决,由于一上来就得把菜单打上来,只需要在外面套一个do while语句,当输入0时,while(0)刚好可以退出,后面电脑下棋的时候要用到随机数,记得先在主函数里写一下。
int main()
{
int input;
srand((unsigned int)time(NULL));
do {
menu();
scanf("%d", &input);
switch (input)
{
case 1:game();
break;
case 0:printf("退出游戏\n");
break;
default:printf("选择错误,请重新选择\n");
break;
}
} while (input);
}
菜单随便画画就好
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#define row 3
#define col 3
char chessboard[row][col] = { 0 };
void menu()
{
printf("请选择\n");
printf("**************************\n");
printf("******** 0.exit ********\n");
printf("******** 1.play ********\n");
printf("**************************\n");
}
2.数组初始化
创建完数组要先把它初始化成全是空格,可以直接写在game函数里,非常简单
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
chessboard[i][j] =' ';
}
3.打印棋盘格
以3*3的棋盘格为例,3个数需要2个|分隔,所以可以看成打印1个字符加上1个|,最后1个字符后面不需要分隔,所以可以直接把最后一个单拎出来,前面的放在循环里。在打完一行之后需要一条横线来分隔,同理最后一行不需要,只需要加一个if语句把最后一行排除就可以了。
void print_chessboard()
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col-1; j++)
{
printf("%c |", chessboard[i][j]);
}
printf("%c\n", chessboard[i][col - 1]);
if(i<row-1)
printf("--------\n");
}
}
4.玩家下棋
if用于判断数组访问是否越界,在没有越界的情况下,如果该位置是空格则可以下棋break跳出,否则continue重新来过,如果访问越界了也一个continue重新来过。玩家输入的坐标是第几行第几列但数组下标是从0开始的,所以人输入的坐标是下标加1,如果i,j是人输入的坐标那么在判断该位置的元素时应该让i,j减1。
void player_move(char chessboard[row][col])
{
while (1)
{
int i= 0;
int j= 0;
printf("请输入坐标:");
scanf("%d %d", &i,&j);
if (i>0&&i<=row&&j>0&&j<=col)
{
if (chessboard[i-1][j-1]!=' ')
{
printf("位置已经有子,请重新输入\n");
continue;
}
chessboard[i-1][j-1]='*';
break;
}
else printf("坐标不合法,请重新输入\n");
continue;
}
}
5.电脑下棋
由于电脑下棋是随机的所以毫无疑问要用到随机数%几范围就是0到这个数减1刚好是数组下标的范围,如果是空格就输入,如果不是就重新来过。
void computer_move(char chessboard[row][col])
{
while (1)
{
int i= rand()%row;
int j= rand()%col;
if (chessboard[i][j]==' ')
{
chessboard[i][j] = 'o';
break;
}
else continue;
}
}
6.判断结果
第一种情况:某一行有三个一样的符号连在一起,直接把这个符号返回,后面可以直接判断出是电脑还是玩家胜利。
第二种情况:某一列有三个一样的符号连在一起,同理直接把这个符号返回。
第三种和第四种情况:某条斜线有三个一样的符号连在一起,同理直接把这个符号返回。
最后一个for用来判断棋盘是否满了,返回c说明没满,返回p说明满了,满了就是平局。一定要先判断前四种情况最后再判断是否还剩下空格,因为前四种情况返回后游戏直接就结束了,如果先判断有无空格,会造成游戏分出胜负但由于有空格游戏仍继续的现象。
char win(char chessboard[row][col])
{
for (int i=0;i<row;i++)
{
if (chessboard[i][0] != ' '&& chessboard[i][0] == chessboard[i][1]&& chessboard[i][0] == chessboard[i][2])
return chessboard[i][0];
}
for (int j=0;j<col;j++)
{
if (chessboard[0][j] != ' '&& chessboard[0][j] == chessboard[1][j]&& chessboard[0][j] == chessboard[2][j])
return chessboard[0][j];
}
if (chessboard[0][0] != ' '&& chessboard[0][0] == chessboard[1][1]&& chessboard[0][0] == chessboard[2][2])
{
return chessboard[0][0];
}
if (chessboard[2][0] != ' '&& chessboard[2][0] == chessboard[1][1]&& chessboard[2][0] == chessboard[0][2])
{
return chessboard[2][0];
}
for (int i=0;i<row;i++)
{
for (int j = 0; j < col; j++)
{
if (chessboard[i][j] == ' ')
{
return 'c';
}
}
}
return 'p';
}
7.game函数
game函数里要包含打印棋盘格,玩家下棋,电脑下棋和判断结果四个部分。每次在下棋之后都要将棋盘再打印一次,用结果判断函数判断一次,只要返回的不是c就说明已经有了结果直接break用if判断结果,如果返回c说明游戏既未分出胜负又仍有空格所以游戏继续。
void game()
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
chessboard[i][j] =' ';
}
print_chessboard();
while (1)
{
player_move(chessboard);
print_chessboard();
if (win(chessboard) != 'c')break;
computer_move(chessboard);
print_chessboard();
if (win(chessboard) != 'c')break;
}
if (win(chessboard) == '*')printf("你赢了\n");
if (win(chessboard) == 'o')printf("你输了\n");
if (win(chessboard) == 'p')printf("平局\n");
}
8.全部代码
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#define row 3
#define col 3
char chessboard[row][col] = { 0 };
void menu()
{
printf("请选择\n");
printf("**************************\n");
printf("******** 0.exit ********\n");
printf("******** 1.play ********\n");
printf("**************************\n");
}
void print_chessboard()
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col-1; j++)
{
printf("%c |", chessboard[i][j]);
}
printf("%c\n", chessboard[i][col - 1]);
if(i<row-1)
printf("--------\n");
}
}
void player_move(char chessboard[row][col])
{
while (1)
{
int i= 0;
int j= 0;
printf("请输入坐标:");
scanf("%d %d", &i,&j);
if (i>0&&i<=row&&j>0&&j<=col)
{
if (chessboard[i-1][j-1]!=' ')
{
printf("位置已经有子,请重新输入\n");
continue;
}
chessboard[i-1][j-1]='*';
break;
}
else printf("坐标不合法,请重新输入\n");
continue;
}
}
void computer_move(char chessboard[row][col])
{
while (1)
{
int i= rand()%row;
int j= rand()%col;
if (chessboard[i][j]==' ')
{
chessboard[i][j] = 'o';
break;
}
else continue;
}
}
char win(char chessboard[row][col])
{
for (int i=0;i<row;i++)
{
if (chessboard[i][0] != ' '&& chessboard[i][0] == chessboard[i][1]&& chessboard[i][0] == chessboard[i][2])
return chessboard[i][0];
}
for (int j=0;j<col;j++)
{
if (chessboard[0][j] != ' '&& chessboard[0][j] == chessboard[1][j]&& chessboard[0][j] == chessboard[2][j])
return chessboard[0][j];
}
if (chessboard[0][0] != ' '&& chessboard[0][0] == chessboard[1][1]&& chessboard[0][0] == chessboard[2][2])
{
return chessboard[0][0];
}
if (chessboard[2][0] != ' '&& chessboard[2][0] == chessboard[1][1]&& chessboard[2][0] == chessboard[0][2])
{
return chessboard[2][0];
}
for (int i=0;i<row;i++)
{
for (int j = 0; j < col; j++)
{
if (chessboard[i][j] == ' ')
{
return 'c';
}
}
}
return 'p';
}
void game()
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
chessboard[i][j] =' ';
}
print_chessboard();
while (1)
{
player_move(chessboard);
print_chessboard();
if (win(chessboard) != 'c')break;
computer_move(chessboard);
print_chessboard();
if (win(chessboard) != 'c')break;
}
if (win(chessboard) == '*')printf("你赢了\n");
if (win(chessboard) == 'o')printf("你输了\n");
if (win(chessboard) == 'p')printf("平局\n");
}
int main()
{
int input;
srand((unsigned int)time(NULL));
do {
menu();
scanf("%d", &input);
switch (input)
{
case 1:game();
break;
case 0:printf("退出游戏\n");
break;
default:printf("选择错误,请重新选择\n");
break;
}
} while (input);
}
总结
主要还是要注意细节,否则会一直出错,只要判断出都要写啥函数,以及正确把握好整个流程,注意好细节就可以直接写出来。