哈楼啊米娜桑!
作为一名接触编程不久的新人,很乐意和大家分享我的一些学习过程中的见解与疑惑。对于我的解答如果有更好的建议或者说意见的话,欢迎在评论区留言嗷!
最后如果我的文章对你有帮助的话,可以麻烦点一个免费的赞或者关注吗?阿里嘎多!
一.代码的模块化设计;
从三子棋开始 ,我们就接触到了模块化编写代码了。相较于此前一些不过百行的小程序来说,模块化编写代码会更有利于大型程序的编写,将代码分为不同的部分,一方面便于分工,另一方面有利于程序的调试,有利于程序结构的划分,还能增加程序的可读性和可移植性;比如说多个.c文件需要用到不同的库函数时,就可以直接引用.h文件来使用其中声明的不同的函数;
二.三子棋的游戏思路与逻辑;
1.打印游戏菜单;
2.制作并打印棋盘;
3.玩家下棋;(玩家输入棋子坐标来下棋;
4.判断游戏是否继续即是否有输赢,平局的情况;
5.电脑下棋;(电脑随机生成棋子)
6.判断游戏是否继续即是否有输赢,平局的情况;
(另外在编写中设计可以重复下棋的函数)
三.代码实现;
因为要实现代码的模块化,所以我们要先建立一个头文件用来放置需要引用的函数,以及两个.c文件用来测试代码的逻辑和具体的实现,如下:
*这里我使用的是vs编译器;
①打印游戏的菜单;
不需要返回值,因此用到void类型;
void menu()
{
printf("**********************************");
printf("********** 1.开始游戏 *********");
printf("********** 0.退出游戏 *********");
printf("**********************************");
}
同时我们需要一个可以持续进行,不断循环的游戏,所以可以这样写代码:(重复执行)
根据Input的值来进行游戏,以及用到C语言里面”0“为假,只要输入”0“就不用再次进入do-while循环来看是否继续游戏;
int input = 0;
do
{
menu();
printf("请输入;");
scanf_s("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏");
break;
default:
printf("输入错误,请重新输入\n");
break;
}
} while (input);
接下来就是进行函数主体的编写:放在game函数里面
②初始化并打印棋盘:
首先,我们要打印的是一个三子棋的棋盘,是3×3的,我们可以把它当作一个二维数组来打印(二维数组有行有列,符合棋盘的形状)。另外,要考虑到万一不打印3×3的棋盘,变换棋盘的大小时,不断地在函数中修改行和列的变量会非常麻烦,因此要用到宏定义,#define,这样就可以直接在头文件中修改已经被定义的变量来更改数据,非常方便
#define ROW 3
#define COL 3
初始化并打印棋盘:
//初始化棋盘
void InitBoard(char board[ROW][COL], int row, int col)
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
board[i][j] = ' ';
}
}
}
//打印棋盘
void ShowBoard(char board[ROW][COL], int row, int col)
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
printf(" %c ", board[i][j]);
if (j < col - 1)
{
printf("|");
}
}
printf("\n");
if (i < row - 1)
{
for (int j = 0; j < col; j++)
{
printf("---");
if (j < col - 1)
{
printf("|");
}
}
}printf("\n");
}
}
③玩家下棋=>' * '
我们要知道,玩家下棋的本质就是用一个符号来替换已经初始化的棋盘上面的符号,这是很容易就可以实现的,但是重在于判断棋子的位置合不合适,有以下几点需要注意:
1.棋子的坐标是否在棋盘之内;
2.落子的位置上是否已经有了其他的棋子。
3.编写代码的时候要知道,玩家眼中的第一行并不是电脑里面的第一行:数组的下标是从’0‘开始的,所以需要做出一些调整(代码中有注释);
代码实现:
//玩家下棋
void PlayerMove(char board[ROW][COL], int row, int col)
{
while(1)
{
int i = 0;
int j = 0;
printf("请输入落子的坐标=>");
scanf_s("%d %d", &i, &j);
if (1 <= i && i <= row && 1 <=j && j <= col)
{
if (board[i-1][j-1] == ' ')//数组的下标是从零开始,与玩家的坐标相差一,在这里减掉一个
{
board[i-1][j-1] = '*';
break;//落子之后直接跳出循环
}
else
{
printf("该位置已被占用,请换一个位置吧 o.0\n\n");
}
}
else
{
printf("不看看你输入的是什么嘛,三子棋有这样的格子吗?重新输!\n\n");
}
}
}
④电脑下棋
电脑下棋是随机的,因此需要一个生成随机数的函数,
//电脑下棋
void ComputerMove(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("电脑下棋\n");
while (1)
{
x = rand() % row;//在这里使用%(取余)就可得出0-row的数,col同理;
y = rand() % col;
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
每次落子不管是玩家还是电脑,都要打印棋盘并且判断棋局状况,打印棋盘的代码上面已经写过,接下来是判断棋局的代码,我们用不同的字符作为返回值来判断棋局的状况:
玩家赢---’*'
电脑赢---'#'
平局------‘m'
未能判断胜负平局,游戏继续---’a'
⑤判断棋局状况
//判断输赢
char IsWin(char board[ROW][COL], int row, int col)
{
for (int i = 0; i < row; i++)
{
if (board[i][0] == board[i][1] && board[i][0] == board[i][2] && board[i][0] != ' ')
{
return board[i][0];
}
}
for (int i= 0; i < col; i++)
{
if (board[0][i] == board[1][i] && board[0][i] == board[2][i] && board[0][i] != ' ')
{
return board[0][i];
}
}
if (board[0][0] == board[1][1] && board[0][0] == board[2][2] &&board[0][0]!=' ')
{
return board[0][0];
}
if (board[0][2] == board[1][1] && board[0][2] == board[2][0] &&board[0][2]!=' ')
{
return board[0][2];
}
//判断是否平局
if (IsFull(board, row, col))
{
return 'm';
}
//继续游戏
return 'a';
}
最后输赢的判断这样子实现:
void game()
{
char ret = 0;
char board[ROW][COL] = { 0 };
//初始化棋盘
InitBoard(board, ROW, COL);
//打印棋盘
ShowBoard(board, ROW, COL);
while (1)
{
//玩家下棋
PlayerMove(board, ROW, COL);
//打印棋盘
ShowBoard(board, ROW, COL);
//判断输赢
ret = IsWin(board, ROW, COL);
if (ret != 'a')
{
break;
}
//电脑下棋
ComputerMove(board, ROW, COL);
//打印棋盘
ShowBoard(board, ROW, COL);
//判断输赢
ret = IsWin(board, ROW, COL);
if (ret != 'a')
{
break;
}
}
if (ret == 'm')
{
printf("平局\n");
}
else if (ret == '*')
{
printf("玩家获胜\n");
}
else if (ret == '#')
{
printf("电脑获胜\n");
}
}
以上就是代码的主体构成部分了,具体各个文件里面的代码如下:
头文件:(.h文件)
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define ROW 3
#define COL 3
//打印菜单;
void menu();
//初始化棋盘
void InitBoard(char board[ROW][COL], int row, int col);
//打印棋盘
void ShowBoard(char board[ROW][COL], int row, int col);
//玩家下棋
void PlayerMove(char board[ROW][COL], int row, int col);
//电脑下棋
void ComputerMove(char board[ROW][COL], int row, int col);
//判断棋局状况;
char IsWin(char board[ROW][COL], int row, int col);
逻辑测试的.c文件:
#include"game1.h"
void menu()
{
printf("********************************\n");
printf("********** 1.开始游戏 *********\n");
printf("********** 0.退出游戏 *********\n");
printf("********************************\n");
}
void game()
{
char board[ROW][COL] = { 0 };
//把棋盘初始化;
InitBoard(board, ROW, COL);
//显示棋盘
Displayboard(board, ROW, COL);
char ret = 0;
while (1)
{
//玩家下棋并且打印棋盘
PlayerMove(board,ROW,COL);
Displayboard(board, ROW, COL);
//判断输赢<一共有四种情况>
//玩家赢=>'*'
//电脑赢=>'#'
//平局=>'Q'
//游戏继续,未分胜负=>'C'
ret = Iswin(board, ROW, COL);
if (ret != 'C')
{
break;
}
//电脑下棋并且打印棋盘
ComputerMove(board, ROW, COL);
Displayboard(board, ROW, COL);
//判断输赢
ret = Iswin(board, ROW, COL);
if (ret != 'C')
{
break;
}
}
if ('*' == ret)
{
printf("玩家获胜!\n");
}
else if ('#' == ret)
{
printf("电脑获胜!\n");
}
else if ('Q' == ret)
{
printf("平局!\n");
}
}
int main()
{
srand((unsigned int)time(NULL));
int input = 0;
do
{
menu();//打印菜单;
printf("请选择=>");
scanf_s("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏;\n");
break;
default:
printf("选择错误,请重新选择;\n");
break;
}
} while (input);//while里面的条件是为真则运行,因此可以设置为input;C语言里面0为假;
return 0;
}
游戏的具体实现的.c文件:
#include"game1-Boke.h"
//初始化棋盘
void InitBoard(char board[ROW][COL], int row, int col)
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
board[i][j] = ' ';
}
}
}
//打印棋盘
void ShowBoard(char board[ROW][COL], int row, int col)
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
printf(" %c ", board[i][j]);
if (j < col - 1)
{
printf("|");
}
}
printf("\n");
if (i < row - 1)
{
for (int j = 0; j < col; j++)
{
printf("---");
if (j < col - 1)
{
printf("|");
}
}
}printf("\n");
}
}
//玩家下棋
void PlayerMove(char board[ROW][COL], int row, int col)
{
while(1)
{
int i = 0;
int j = 0;
printf("请输入落子的坐标=>");
scanf_s("%d %d", &i, &j);
if (1 <= i && i <= row && 1 <=j && j <= col)
{
if (board[i-1][j-1] == ' ')//数组的下标是从零开始,与玩家的坐标相差一,在这里减掉一个
{
board[i-1][j-1] = '*';
break;//落子之后直接跳出循环
}
else
{
printf("该位置已被占用,请换一个位置吧 o.0\n\n");
}
}
else
{
printf("不看看你输入的是什么嘛,三子棋有这样的格子吗?重新输!\n\n");
}
}
}
//电脑下棋
void ComputerMove(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("电脑下棋\n");
while (1)
{
x = rand() % row;//在这里使用%(取余)就可得出0-row的数,col同理;
y = rand() % col;
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
//判断是否平局
IsFull(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 IsWin(char board[ROW][COL], int row, int col)
{
for (int i = 0; i < row; i++)
{
if (board[i][0] == board[i][1] && board[i][0] == board[i][2] && board[i][0] != ' ')
{
return board[i][0];
}
}
for (int i= 0; i < col; i++)
{
if (board[0][i] == board[1][i] && board[0][i] == board[2][i] && board[0][i] != ' ')
{
return board[0][i];
}
}
if (board[0][0] == board[1][1] && board[0][0] == board[2][2] &&board[0][0]!=' ')
{
return board[0][0];
}
if (board[0][2] == board[1][1] && board[0][2] == board[2][0] &&board[0][2]!=' ')
{
return board[0][2];
}
//判断是否平局
if (IsFull(board, row, col))
{
return 'm';
}
//继续游戏
return 'a';
}