目录
思路
1.设置一个游戏菜单,让玩家可以自主选择开始游戏或者退出游戏。
2.声明并定义一个二维数组,用来存放棋子。
3.打印一个棋盘,将棋子的布局展示出来。
4.玩家下棋,电脑下棋
5.判断输赢
实现
首先我们打开我们的Visual Studio,创建一个项目
为了代码的简洁性和方便我们调试代码,我们在这里创建了一个头文件,两个源文件
接下来我们开始编写程序一步步实现我们的三子棋。
1.游戏菜单
1.1 打印游戏菜单
首先我们可以使用printf函数打印出一个相对精美的游戏菜单
代码如下:
//test.c
void menu()
{
printf("********************\n");
printf("****** 1.play ******\n");
printf("****** 0.exit ******\n");
printf("********************\n");
}
void test()
{
menu();//打印游戏菜单
}
int main()
{
test();
return 0;
}
1.2 玩家自主选择
我们要做到玩家自主选择玩还是不玩,可以引入一个input变量来接受玩家键入的值,然后再通过switch语句来分别作出对应的操作。
同时,如果玩家玩一次不过瘾想要接着玩,我们这时候就需要一个循环语句来实现,我们可以发现,菜单一开始肯定是要打印出来的,所以是先做一次再判断,我们用do...while语句来实现这个功能。
代码如下:
//test.c
#include <stdio.h>
void menu()
{
printf("********************\n");
printf("****** 1.play ******\n");
printf("****** 0.exit ******\n");
printf("********************\n");
}
void test()
{
int input = 0;
do
{
menu();//打印游戏菜单
printf("请做出你的选择:>");//提示输入
scanf("%d", &input);
switch (input)
{
case 1:
printf("三子棋");//先调试看代码能不能运行,能运行后再写真正的游戏
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("输入错误,请重新输入\n");//如果输入0和1以外的数字,则重新输入
break;
}
} while (input);//input为0跳出循环游戏结束,input不为0再次进入循环进行选择
}
int main()
{
test();
return 0;
}
2.设置游戏函数
为了代码的简洁性,我们封装一个game()函数来实现三子棋游戏主体。
2.1 声明并且定义一个二维数组
玩家下棋和电脑下棋均需要一个东西来存放我们的棋子,那这时候我们就需要引入一个二维数组来存放棋子,因为我们需要的三子棋,所以我们定义一个3*3的二维数组即可,当然,为了后续我们可以升级成N子棋,我们可以在game.h文件中利用#define定义的常量标识符来充当行和列,届时我们只需要修改ROW和COL的值就可以把三子棋改成N子棋。
代码如下:
//game.h
//因为在test.c文件中引入了头文件,所以#include stdio.h就可以放在这个头文件中
#include <stdio.h>
//定义行和列
#define ROW 3
#define COL 3
//test.c
#include "game.h" //这里我们需要引用一下头文件
void menu()
{
printf("********************\n");
printf("****** 1.play ******\n");
printf("****** 0.exit ******\n");
printf("********************\n");
}
void game()
{
char board[ROW][COL] = { 0 };//声明并定义一个数组来存放棋子
}
void test()
{
int input = 0;
do
{
menu();//打印游戏菜单
printf("请做出你的选择:>");//提示输入
scanf("%d", &input);
switch (input)
{
case 1:
game()//游戏函数
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("输入错误,请重新输入\n");//如果输入0和1以外的数字,则重新输入
break;
}
} while (input);//input为0跳出循环游戏结束,input不为0再次进入循环进行选择
}
int main()
{
test();
return 0;
}
2.2 初始化二维数组
先让我们看看棋盘:
我们可以看到,棋盘由字符'|'与字符'-'组合而成,而每个格子中是棋子(未下的地方是空格)
所以我们就需要初始化一下二维数组,使其全为' ',来达到我们的目的。
接下来我们就需要定义函数分别实现二维数组的初始化。
代码如下:
//test.c
void game()
{
char board[ROW][COL] = { 0 };//声明并定义一个数组来存放棋子
init_board(board, ROW, COL);
}
//game.h
//初始化二维数组
void init_board(char* board[ROW][COL], int row, int col);
//game.c
#include "game.h"//注意包含头文件
//初始化二维数组
void init_board(char* board[ROW][COL], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
int j = 0;
for (j = 0; j < col; j++)
{
board[i][j] = ' ';//将二维数组中每个元素初始化为' '
}
}
}
3.打印棋盘
先让我们看看棋盘:
我们可以看到,棋盘由字符'|'与字符'-'组合而成所以我们可以通过printf函数来打印我们的棋盘。
代码如下:
//test.c
void game()
{
char board[ROW][COL] = { 0 };//声明并定义一个数组来存放棋子
init_board(board, ROW, COL);
print_board(board, ROW, COL);
}
//game.h
//打印棋盘
void print_board(char* board[ROW][COL], int row, int col);
//game.c
#include "game.h"//注意包含头文件
//打印棋盘
void print_board(char board[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 ", board[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");
}
}
}
4. 下棋
4.1 玩家下棋
在设计玩家下棋函数之前,我们要知道,普通玩家是没有我们程序员的思维的,他们不知道棋盘的第1行其实是“第0行”,第1列其实是“第0列”,所以我们需要迎合玩家思维,那么如何实现呢?
代码如下:
//test.c
void game()
{
char board[ROW][COL] = { 0 };//声明并定义一个数组来存放棋子
//初始化二维数组
init_board(board, ROW, COL);
//打印棋盘
print_board(board, ROW, COL);
//玩家移动
player_move(board, ROW, COL);
print_board(board, ROW, COL);//下完棋后打印棋盘
}
//game.h
//玩家移动
void player_move(char board[ROW][COL], int row, int col);
//game.c
void player_move(char board[ROW][COL], int row, int col)
{
int x = 0, y = 0;
while (1)
{
printf("请选择要下的位置:>");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)//判断坐标是否合法
{
if (board[x - 1][y - 1] != '*')//判断该位置是否有棋子
{
board[x - 1][y - 1] = '*';//行数-1和列数-1即为数组中的行下标和列下标
break;
}
else
printf("该位置已有棋子,请重新选择!!!\n");
}
else
printf("输入坐标有误,请重新输入!!!\n");
}
}
4.2 电脑下棋
电脑下棋就没有玩家下棋的前提,因为电脑知道棋盘的第1行其实是“第0行”,第1列其实是“第0列”,但是我们需要生成随机数,这就要用到rand()函数、srand()函数和time()函数,而这三个库函数分别要引入<stdlib.h>头文件和<time.h>头文件这里就不做过多讲解,可以自行查找。
代码如下:
//test.c
void game()
{
char board[ROW][COL] = { 0 };//声明并定义一个数组来存放棋子
//初始化二维数组
init_board(board, ROW, COL);
//打印棋盘
print_board(board, ROW, COL);
//玩家移动
player_move(board, ROW, COL);
print_board(board, ROW, COL);//下完棋后打印棋盘
//电脑移动
computer_move(board, ROW, COL);
}
//game.h
//电脑移动
void computer_move(char board[ROW][COL], int row, int col);
//game.c
void computer_move(char board[ROW][COL], int row, int col)
{
while (1)
{
//生成随机数
int x = rand() % 3;
int y = rand() % 3;
if (board[x][y] == ' ')//如果这个位置已经有棋子就重新生成随机数
{
board[x][y] = '#';
break;
}
}
}
5.判断输赢
我们可以看看上面的代码,玩家和电脑各下完一次棋游戏就结束了,这很明显不对,我们需要让他们不断的下棋,直到分出胜负,所以我们需要一个循环来保证游戏的正常进行,棋盘每落下一个棋子就要用到一个判断输赢的函数来打断循环。
代码如下:
//test.c
void game()
{
char board[ROW][COL] = { 0 };//声明并定义一个数组来存放棋子
char ret = 0;
//初始化二维数组
init_board(board, ROW, COL);
//打印棋盘
print_board(board, ROW, COL);
while (1)
{
//玩家移动
player_move(board, ROW, COL);
print_board(board, ROW, COL);//下完棋后打印棋盘
ret = is_win(board, ROW, COL);//判断输赢
//'*'代表玩家胜利
//'#'代表电脑胜利
//'Q'代表平局
//'C'代表游戏继续
if (ret != 'C')//不等于'C'游戏结束,跳出循环
break;
//电脑移动
computer_move(board, ROW, COL);
print_board(board, ROW, COL);
ret = is_win(board, ROW, COL);
is_win(board, ROW, COL);//判断输赢
if (ret != 'C')//不等于'C'游戏结束,跳出循环
break;
}
if (ret == 'Q')
printf("平局\n");
else if (ret == '*')
printf("玩家胜利\n");
else if (ret == '#')
printf("电脑胜利\n");
}
//game.h
//判断输赢
char is_win(char board[ROW][COL], int row, int col);
//game.c
char is_win(char board[ROW][COL], int row, int col)
{
int i = 0, j = 0;
//行相等
for (i = 0; i < row; i++)
{
for (j = 0; j < col - 1; j++)
{
if (board[i][j] != board[i][j + 1] || board[i][j] == ' ')
break;
}
if (j == col - 1)
return board[i][j];
}
//列相等
for (j = 0; j < col; j++)
{
for (i = 0; i < row - 1; i++)
{
if (board[i][j] != board[i + 1][j] || board[i][j] == ' ')
break;
}
if (i == row - 1)
return board[i][j];
}
//正对角线相等
for (i = 0; i < row - 1; i++)
{
j = i;
if (board[i][j] != board[i + 1][j + 1] || board[i][j] == ' ')
break;
}
if (i == col - 1)
return board[i][j];
//反对角线相等
for (i = 0; i < row - 1; i++)
{
j = col - 1 - i;
if (board[i][j] != board[i + 1][j - 1] || board[i][j] == ' ')
break;
}
if (i == row - 1)
return board[i - 1][j];
//平局
for (i = 0; i < row; i++)
{
for (j = 0; i < col; j++)
{
if (board[i][j] == ' ')
break;
}
}
if (i == row && j == col)
return 'Q';
else
return 'C';
}
6. 组合所有步骤
我们把三子棋的实现细化为5个步骤,现在让我们把他们整合起来
最终我们得到了三子棋代码:
分文件展示:
game.h:
#define _CRT_SECURE_NO_WARNINGS 1
//因为在test.c文件中引入了头文件,所以#include stdio.h就可以放在这个头文件中
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
//定义行和列
#define ROW 3
#define COL 3
//初始化二维数组
void init_board(char board[ROW][COL], int row, int col);
//打印棋盘
void print_board(char board[ROW][COL], int row, int col);
//玩家移动
void player_move(char board[ROW][COL], int row, int col);
//电脑移动
void computer_move(char board[ROW][COL], int row, int col);
//判断输赢
char is_win(char board[ROW][COL], int row, int col);
test.c:
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h" //这里我们需要引用一下头文件
void menu()
{
printf("********************\n");
printf("****** 1.play ******\n");
printf("****** 0.exit ******\n");
printf("********************\n");
}
void game()
{
char board[ROW][COL] = { 0 };//声明并定义一个数组来存放棋子
char ret = 0;
//初始化二维数组
init_board(board, ROW, COL);
//打印棋盘
print_board(board, ROW, COL);
while (1)
{
//玩家移动
player_move(board, ROW, COL);
print_board(board, ROW, COL);//下完棋后打印棋盘
ret = is_win(board, ROW, COL);//判断输赢
//'*'代表玩家胜利
//'#'代表电脑胜利
//'Q'代表平局
//'C'代表游戏继续
if (ret != 'C')//不等于'C'游戏结束,跳出循环
break;
//电脑移动
computer_move(board, ROW, COL);
print_board(board, ROW, COL);
ret = is_win(board, ROW, COL);
is_win(board, ROW, COL);//判断输赢
if (ret != 'C')//不等于'C'游戏结束,跳出循环
break;
}
if (ret == 'Q')
printf("平局\n");
else if (ret == '*')
printf("玩家胜利\n");
else if (ret == '#')
printf("电脑胜利\n");
}
void test()
{
int input = 0;
do
{
menu();//打印游戏菜单
printf("请做出你的选择:>");//提示输入
scanf("%d", &input);
switch (input)
{
case 1:
game();//游戏函数
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("输入错误,请重新输入\n");//如果输入0和1以外的数字,则重新输入
break;
}
} while (input);//input为0跳出循环游戏结束,input不为0再次进入循环进行选择
}
int main()
{
test();
return 0;
}
game.c:
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
void init_board(char board[ROW][COL], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
int j = 0;
for (j = 0; j < col; j++)
{
board[i][j] = ' ';//将二维数组中每个元素初始化为' '
}
}
}
void print_board(char board[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 ", board[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 board[ROW][COL], int row, int col)
{
int x = 0, y = 0;
while (1)
{
printf("请选择要下的位置:>");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)//判断坐标是否合法
{
if (board[x - 1][y - 1] == ' ')//判断该位置是否有棋子
{
board[x - 1][y - 1] = '*';//行数-1和列数-1即为数组中的行下标和列下标
break;
}
else
printf("该位置已有棋子,请重新选择!!!\n");
}
else
printf("输入坐标有误,请重新输入!!!\n");
}
}
void computer_move(char board[ROW][COL], int row, int col)
{
while (1)
{
//生成随机数
int x = rand() % 3;
int y = rand() % 3;
if (board[x][y] == ' ')//如果这个位置已经有棋子就重新生成随机数
{
board[x][y] = '#';
break;
}
}
}
char is_win(char board[ROW][COL], int row, int col)
{
int i = 0, j = 0;
//行相等
for (i = 0; i < row; i++)
{
for (j = 0; j < col - 1; j++)
{
if (board[i][j] != board[i][j + 1] || board[i][j] == ' ')
break;
}
if (j == col - 1)
return board[i][j];
}
//列相等
for (j = 0; j < col; j++)
{
for (i = 0; i < row - 1; i++)
{
if (board[i][j] != board[i + 1][j] || board[i][j] == ' ')
break;
}
if (i == row - 1)
return board[i][j];
}
//正对角线相等
for (i = 0; i < row - 1; i++)
{
j = i;
if (board[i][j] != board[i + 1][j + 1] || board[i][j] == ' ')
break;
}
if (i == col - 1)
return board[i][j];
//反对角线相等
for (i = 0; i < row - 1; i++)
{
j = col - 1 - i;
if (board[i][j] != board[i + 1][j - 1] || board[i][j] == ' ')
break;
}
if (i == row - 1)
return board[i - 1][j];
//平局
for (i = 0; i < row; i++)
{
for (j = 0; i < col; j++)
{
if (board[i][j] == ' ')
break;
}
}
if (i == row && j == col)
return 'Q';
else
return 'C';
}
好了,以上就是三子棋的实现,让我们下篇文章再会!