欢迎来到我的博客!!💃💃
🏡🏡推荐博客:August_._一起持续学习,不断总结,共同进步🎊🎊
思路讲解
文件结构设计
我们学过多文件的形式对函数的声明和定义,现在我们设计三个文件:
game.h //游戏需要的数据类型和函数声明
game.c //游戏中函数的实现
main.c //游戏的测试逻辑
游戏逻辑流程图
在 main.c 文件中游戏测试的主体逻辑:
游戏简介
连成五子即为胜利!
玩家选择 | 游戏模式 | 玩家 |
---|---|---|
0 | 退出游戏 | |
1 | 人机对战 | X—人 、 0—电脑 |
2 | 双人对战 | X—人 、 0—人 |
初始化棋盘
在 main.c 文件中定义棋盘【二维数组
】:
char board[LEN][LEN];
利用 for 循环初始化棋盘,使数组每个数为空字符。
void initialize_board(char board[LEN][LEN], int row, int col)
{
for(int i=0; i<row; i++)
for(int j=0; j<col; j++)
board[i][j] = ' ';
}
打印棋盘
15 x 15 的棋盘,在 game.h 中先宏定义:
#define LEN 15
代码实现:【printf(“\033[31m[0]\033[0m”); 知识详解见知识补充
】
void print_board(char board[LEN][LEN], int row, int col)
{
int i, j;
printf("\n");
for (i=0; i<=row; i++) printf("%2d ", i);
printf("\n");
for (i=0; i<row; i++) {
printf("%2d ", i+1);
for (j=0; j<col; j++){
if (board[i][j] == 'X') printf("\033[31m[X]\033[0m");
else if (board[i][j] == '0') printf("\033[34m[0]\033[0m");
else printf("[ ]");
}
printf("\n");
}
}
电脑玩家下棋
定义变量 row (行)、col (列),随机生成0—14的数字作为二维数组的下标,再判断数组该处是否为空字符,如果是,则电脑玩家下棋在该处,反之,进入下次循环,重新生成坐标。
void computer_move(char board[LEN][LEN], char Player){
while(1){
int row,col;
//随机生成0-14数字
row = rand()%LEN;
col = rand()%LEN;
if (board[row][col] != ' ') continue;
else{
board[row][col] = Player;
printf("\n 电脑玩家(%c)下在:(%d,%d)", Player, row+1, col+1);
break;
}
}
}
判断移动是否有效
game.c 文件:
int is_valid_move(int row, int col)
{
return (row>=1 && row<=LEN && col>=1 && col<=LEN);
}
若条件成立,则 is_valid_move() 返回数字1,在 main.c 测试过程中用 if 判断:
if (!(is_valid_move(row, col))){
printf("\n请输入正确的行、列(1<=row<=%d, 1<=col<=%d): ", LEN, LEN);
continue;
}
判断胜负
五子棋连城五子即为胜利,判断输赢须在一个棋子的四个方向(横、竖、左斜、右斜
),遍历是否有五子相连。若有五子连棋,则函数返回1,反之,则返回0。
int is_winner(char board[LEN][LEN], char Player)
{
int i, j;
//横
for (i=0; i<LEN; i++){
for (j=0; j<LEN-4; j++){
if (board[i][j]==Player && board[i][j+1]==Player && board[i][j+2]==Player && board[i][j+3]==Player && board[i][j+4]==Player)
return 1;
}
}
//竖
for (i=0; i<LEN; i++){
for (j=0; j<LEN-4; j++){
if (board[i][j]==Player && board[i+1][j]==Player && board[i+2][j]==Player && board[i+3][j]==Player && board[i+4][j]==Player)
return 1;
}
}
//左斜
for (i=0; i<LEN; i++){
for (j=0; j<LEN-4; j++){
if (board[i][j]==Player && board[i+1][j+1]==Player && board[i+2][j+2]==Player && board[i+3][j+3]==Player && board[i+4][j+4]==Player)
return 1;
}
}
//右斜
for (i=0; i<LEN; i++){
for (j=0; j<LEN-4; j++){
if (board[i][j]==Player && board[i-1][j-1]==Player && board[i-2][j-2]==Player && board[i-3][j-3]==Player && board[i-4][j-4]==Player)
return 1;
}
}
return 0;
}
棋盘是否已满
利用 for 循环遍历棋盘,判断棋盘是否已满,若已满,则此局和棋,本局游戏结束;反之,本局游戏继续。
for (int i=0; i<LEN; i++){
for (int j=0; j<LEN; j++){
if (board[i][j] != ' ') counts++;
}
}
if (counts == LEN * LEN){
printf("棋盘已满,未分出胜负,该局和棋!");
break;
}
源代码
头文件 game.h
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define LEN 15
//游戏
void game(char board[LEN][LEN], int game_mode);
//菜单
void meun();
//初始化棋盘
void initialize_board(char board[LEN][LEN], int row, int col);
//打印棋盘
void print_board(char board[LEN][LEN], int row, int col);
//判断移动是否有效
int is_valid_move(int row, int col);
//判断胜负
int is_winner(char board[LEN][LEN], char Player);
//电脑玩家下棋
void computer_move(char board[LEN][LEN], char Player);
主函数 main.c
#include "game.h"
void game(char board[LEN][LEN], int game_mode)
{
char Player = 'X';
int row, col, counts;
//设置随机数种子
srand((unsigned)time(NULL));
//初始化棋盘
initialize_board(board, LEN, LEN);
print_board(board, LEN, LEN);
while(1){
if (game_mode == 2 || Player == 'X'){
printf("当前玩家: %c", Player);
printf("\n请输入你的选择(行 列): ");
if (scanf("%d %d", &row, &col) != 2){
printf("\n输入有误,请正确输入(行 列)!");
//清空缓冲区
while (getchar() != '\n')
continue;
}
//判断下棋是否有效
if (!(is_valid_move(row, col))){
printf("\n请输入正确的行、列(1<=row<=%d, 1<=col<=%d): ", LEN, LEN);
continue;
}
if (board[row-1][col-1] != ' '){
printf("\n此处已经有旗子,请重新输入(行 列) ");
continue;
}
board[row-1][col-1] = Player;
print_board(board, LEN, LEN);
}
//电脑玩家
else{
computer_move(board, Player);
print_board(board, LEN, LEN);
}
//判断胜负
if (is_winner(board, Player)){
printf("恭喜玩家%c获得胜利!", Player);
break;
}
//判断棋盘是否已满
for (int i=0; i<LEN; i++){
for (int j=0; j<LEN; j++){
if (board[i][j] != ' ') counts++;
}
}
if (counts == LEN * LEN){
printf("棋盘已满,未分出胜负,该局和棋!");
break;
}
//切换玩家
Player = (Player == 'X')? '0':'X';
}
}
int main()
{
int game_mode;
char board[LEN][LEN];
do{
//菜单
meun();
//选择模式
printf("请选择游戏模式: ");
scanf("%d", &game_mode);
switch(game_mode){
case 0:
printf("\n游戏结束!");
break;
case 1:
case 2:
game(board, game_mode);
break;
default:
printf("输入有误,请重新输入!");
}
}while(game_mode);
return 0;
}
游戏函数 game.c
#include "game.h"
//菜单
void meun()
{
printf("\n----------------------五子棋-------------------\n");
printf("| 游戏模式 | 游戏介绍 |\n");
printf("| 0.退出游戏 | |\n");
printf("| 1.人机模式 | ‘X' —— 红色 |\n");
printf("| 2.双人对战 | '0' —— 蓝色 |\n");
printf("-----------------------------------------------\n");
}
//初始化棋盘
void initialize_board(char board[LEN][LEN], int row, int col)
{
for(int i=0; i<row; i++)
for(int j=0; j<col; j++)
board[i][j] = ' ';
}
//打印棋盘
void print_board(char board[LEN][LEN], int row, int col)
{
int i, j;
printf("\n");
for (i=0; i<=row; i++) printf("%2d ", i);
printf("\n");
for (i=0; i<row; i++) {
printf("%2d ", i+1);
for (j=0; j<col; j++){
if (board[i][j] == 'X') printf("\033[31m[X]\033[0m");
else if (board[i][j] == '0') printf("\033[34m[0]\033[0m");
else printf("[ ]");
}
printf("\n");
}
}
//判断移动是否有效
int is_valid_move(int row, int col)
{
return (row>=1 && row<=LEN && col>=1 && col<=LEN);
}
int is_winner(char board[LEN][LEN], char Player)
{
int i, j;
//横 —
for (i=0; i<LEN; i++){
for (j=0; j<LEN-4; j++){
if (board[i][j]==Player && board[i][j+1]==Player && board[i][j+2]==Player && board[i][j+3]==Player && board[i][j+4]==Player)
return 1;
}
}
//竖 |
for (i=0; i<LEN; i++){
for (j=0; j<LEN-4; j++){
if (board[i][j]==Player && board[i+1][j]==Player && board[i+2][j]==Player && board[i+3][j]==Player && board[i+4][j]==Player)
return 1;
}
}
//左斜
for (i=0; i<LEN; i++){
for (j=0; j<LEN-4; j++){
if (board[i][j]==Player && board[i+1][j+1]==Player && board[i+2][j+2]==Player && board[i+3][j+3]==Player && board[i+4][j+4]==Player)
return 1;
}
}
//右斜
for (i=0; i<LEN; i++){
for (j=0; j<LEN-4; j++){
if (board[i][j]==Player && board[i-1][j-1]==Player && board[i-2][j-2]==Player && board[i-3][j-3]==Player && board[i-4][j-4]==Player)
return 1;
}
}
return 0;
}
//电脑玩家下棋
void computer_move(char board[LEN][LEN], char Player){
while(1){
int row,col;
//随机生成0-14数字
row = rand()%LEN;
col = rand()%LEN;
if (board[row][col] != ' ') continue;
else{
board[row][col] = Player;
printf("\n 电脑玩家(%c)下在:(%d,%d)", Player, row+1, col+1);
break;
}
}
}
知识补充
在C语言中,printf(“\033[31m[0]\033[0m”); 这行代码的作用是输出带有颜色的文本。
这里使用了ANSI转义序列(ANSI escape codes)来控制文本的颜色。具体来说:
\033[
:这是一个特殊的字符序列,表示接下来的字符是ANSI转义序列的开始。31m
:这个序列表示将文本颜色设置为红色(31是ANSI颜色代码中红色的代号)。[0]
:这是要输出的文本内容。\033[0m
:这个序列表示重置文本颜色为默认颜色(0是ANSI颜色代码中重置颜色的代号)。
所以,printf(“\033[31m[0]\033[0m”); 会在终端中输出红色的"[0]"文本,然后将其颜色重置为默认颜色。请注意,这种颜色输出在支持ANSI转义序列的终端和环境中有效,例如Linux或macOS的终端以及某些Windows命令提示符环境。在不支持ANSI转义序列的环境中,这段代码可能不会有任何效果或者显示奇怪的字符。
运行截图
以下是部分截图,大家可以自己运行试试哦!