简易三子棋游戏(C语言实现)
-
游戏分析:首先我们可以将游戏分为三个部分
- 一是运行部分test.c
- 二是头文件包含和声明部分game.h
- 三是游戏实现部分game.c
-
运行部分
首先我们先显示一个开始游戏菜单的界面
//test.c文件 #include "game.h" //所引用的头文件全部放在game.h里,这里直接引用game.h就行 void menu() { printf("***********************\n"); printf("****** 1、play ******\n"); printf("****** 0、exit ******\n"); printf("***********************\n"); } int main() { menu(); return 0; }
然后玩家得输入,考虑到玩家每次玩完一把可能还要继续玩,因此我们写一个while循环,玩家输入1则开始游戏,输入0退出游戏。对于玩游戏的实现代码先简易实现一下打印,确保能正常运行,完善如下:
//test.c文件 #include "game.h" //所引用的头文件全部放在game.h里,这里直接引用game.h就行 void game() { printf("开始游戏\n"); } int main() { int input = 0; do { menu(); printf("请输入>:"); scanf("%d", &input); switch (input) { case 0: printf("退出游戏\n"); break; case 1: game();//开始游戏 break; default: printf("输入错误,请重新输入\n"); break; } } while (input); return 0; }
接下来我们开始完善开始游戏
game()
的代码。首先我们得先创建一个棋盘board[ROW][COL]
,其中ROW和COL可以在头文件包含和声明部分game.h中声明大小,以便于后续修改,并且考虑到开始游戏得显示棋盘,因此咱们可以先实现显示棋盘的代码。再就是实现一个初始化棋盘的操作,打印出来我们想要的样子。代码如下:// test.c文件 #include "game.h"// 所引用的头文件全部放在game.h里,这里直接引用game.h就行 void game() { char board[ROW][COL] = {0};//初始化数组 init_board(board, ROW, COL);//初始化棋盘 display_board(board, ROW, COL);//显示棋盘 }
上述函数声明:
//game.h文件 #include <stdio.h> #include <time.h> #include <stdlib.h> #define ROW 3 #define COL 3 //初始化棋盘 void init_board(char board[ROW][COL], int row, int col); //打印棋盘 void display_board(char board[ROW][COL], int row, int col);
上述函数实现:
//game.c文件 #include "game.h"// 所引用的头文件全部放在game.h里,这里直接引用game.h就行 //初始化棋盘 void init_board(char board[ROW][COL], int row, int col) { int i = 0; int j = 0; for (i = 0; i < row; i++) { for (int j = 0; j < col; ++j) { board[i][j] = ' '; } } } //打印棋盘 void display_board(char board[ROW][COL], int row, int col) { int i = 0; int j = 0; for (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 (j = 0; j < col; j++) { printf("---"); if (j < col - 1)//最右一列不打印 printf("|"); } printf("\n"); } } }
代码写到这里我们再打印测试一下功能,防止代码错误发现不及时,导致后面难找出错误。
接下来就是开始实现玩家下棋的代码,我们用’*'代表玩家下棋,考虑到玩家不是程序员,他们的坐标就是正常的矩阵行和列的坐标,就是从(1,1)开始,还得考虑玩家输入的代码合法性和当前要落棋的位置是否被占用。代码实现如下
//game.c文件 //玩家玩游戏 void player_move(char board[ROW][COL], int row, int col) { //1、判断坐标合法性 //2、判断坐标是否被占用 int x = 0; int y = 0; printf("玩家下棋>:\n"); 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] = '*';//落子 break; } else { printf("坐标被占用,请重新输入\n"); } } else { printf("坐标非法,请重新输入\n"); } } }
函数声明:
//game.h文件 //玩家下棋 void player_move(char board[ROW][COL], int row, int col);
然后就是电脑下棋的代码,我们用’#'代表电脑下棋,这里我们采用电脑随机下棋的方式(AI方式要考虑很多情况,暂时不会),但也得考虑落棋位置是否被占用的问题。实现代码如下:
//game.c文件 //电脑下棋 void computer_move(char board[ROW][COL], int row, int col) { printf("电脑下棋>:\n"); while (1) { int x = rand() % row; int y = rand() % col; if (' ' == board[x][y]) { board[x][y] = '#';//落子 break; } } }
函数声明:
//game.h文件 //电脑下棋 void computer_move(char board[ROW][COL], int row, int col);
由于下棋是一直进行的,直到玩家或者电脑赢或者棋盘满了才结束,所以再游戏代码
game()
里写个while循环。代码完善如下://test.c文件 void game() { char board[ROW][COL] = {0};//初始化数组 //初始化棋盘 init_board(board, ROW, COL); //打印棋盘 display_board(board, ROW, COL); //玩游戏 while (1) { player_move(board, ROW, COL); display_board(board, ROW, COL); computer_move(board, ROW, COL); display_board(board, ROW, COL); } }
然后在这步我们继续测试功能是否没有问题。
最后我们得在此循环代码里判断输赢来退出循环,我们写一个判断输赢的函数。考虑游戏时的几种情况(玩家赢,电脑赢,平局(棋盘满了),继续游戏)。玩家赢返回’*‘,电脑赢返回’#‘,平局返回’Q’,继续游戏返回’C’。代码如下:
//game.c文件 //判断棋盘是否满了 //1、满 //0、没满 int is_full(char board[ROW][COL], int row, int col) { for (int i = 0; i < row; ++i) { for (int j = 0; j < col; ++j) { if (' ' == board[i][j]) return 0; } } return 1; } //判断输赢 char is_win(char board[ROW][COL], int row, int col) { for (int i = 0; i < row; ++i) { //判断行 if (board[i][0] == board[i][1] && board[i][1] == 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[1][i] == board[2][i] && board[i][0] != ' ') return board[0][i]; } //判断主对角线 if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] != ' ') return board[0][0]; //判断副对角线 if (board[2][0] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ') return board[1][1]; //判断平局 if (is_full(board, row, col) == 1) return 'Q'; //继续游戏 return 'C'; }
函数声明:
//game.h文件 //判断输赢 char is_win(char board[ROW][COL], int row, int col);
在
game()
里判断输赢。完善代码如下:void game() { //printf("开始游戏\n"); //棋盘 char ret = 0; char board[ROW][COL] = {0};//初始化数组 //初始化棋盘 init_board(board, ROW, COL); //打印棋盘 display_board(board, ROW, COL); //玩游戏 while (1) { player_move(board, ROW, COL); display_board(board, ROW, COL); ret = is_win(board, ROW, COL); //返回值不是继续的信号 if (ret != 'C') break; computer_move(board, ROW, COL); display_board(board, ROW, COL); ret = is_win(board, ROW, COL); //返回值不是继续的信号 if (ret != 'C') break; } if (ret == '*') { printf("玩家赢\n"); } else if (ret == '#') { printf("电脑赢\n"); } else if (ret == 'Q') { printf("平局\n"); } }
最后再测试一下:
-
游戏总代码
test.c
文件#include "game.h" void menu() { printf("***********************\n"); printf("****** 1、play ******\n"); printf("****** 0、exit ******\n"); printf("***********************\n"); } void game() { //printf("开始游戏\n"); //棋盘 char ret = 0; char board[ROW][COL] = {0};//初始化数组 //初始化棋盘 init_board(board, ROW, COL); //打印棋盘 display_board(board, ROW, COL); //玩游戏 while (1) { player_move(board, ROW, COL); display_board(board, ROW, COL); ret = is_win(board, ROW, COL); //返回值不是继续的信号 if (ret != 'C') break; computer_move(board, ROW, COL); display_board(board, ROW, COL); ret = is_win(board, ROW, COL); //返回值不是继续的信号 if (ret != 'C') break; } if (ret == '*') { printf("玩家赢\n"); } else if (ret == '#') { printf("电脑赢\n"); } else if (ret == 'Q') { printf("平局\n"); } } //电脑赢 //玩家赢 //平局 //继续游戏 int main() { int input = 0; srand((unsigned int) time(NULL)); do { menu(); printf("请输入>:"); scanf("%d", &input); switch (input) { case 0: printf("退出游戏\n"); break; case 1: game();//开始游戏 break; default: printf("输入错误,请重新输入\n"); break; } } while (input); return 0; }
game.h
文件#include <stdio.h> #include <time.h> #include <stdlib.h> #define ROW 3 #define COL 3 //初始化棋盘 void init_board(char board[ROW][COL], int row, int col); //打印棋盘 void display_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);
``game.c`文件
// // Created by 徐鹏 on 2023/1/26. // #include "game.h" //初始化棋盘 void init_board(char board[ROW][COL], int row, int col) { int i = 0; int j = 0; for (i = 0; i < row; i++) { for (int j = 0; j < col; ++j) { board[i][j] = ' '; } } } //打印棋盘 void display_board(char board[ROW][COL], int row, int col) { int i = 0; int j = 0; for (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 (j = 0; j < col; j++) { printf("---"); if (j < col - 1)//最右一列不打印 printf("|"); } printf("\n"); } } } //玩家玩游戏 void player_move(char board[ROW][COL], int row, int col) { //1、判断坐标合法性 //2、判断坐标是否被占用 int x = 0; int y = 0; printf("玩家下棋>:\n"); 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] = '*';//落子 break; } else { printf("坐标被占用,请重新输入\n"); } } else { printf("坐标非法,请重新输入\n"); } } } //电脑下棋 void computer_move(char board[ROW][COL], int row, int col) { printf("电脑下棋>:\n"); while (1) { int x = rand() % row; int y = rand() % col; if (' ' == board[x][y]) { board[x][y] = '#';//落子 break; } } } //判断棋盘是否满了 //1、满 //0、没满 int is_full(char board[ROW][COL], int row, int col) { for (int i = 0; i < row; ++i) { for (int j = 0; j < col; ++j) { if (' ' == board[i][j]) return 0; } } return 1; } //判断输赢 char is_win(char board[ROW][COL], int row, int col) { for (int i = 0; i < row; ++i) { //判断行 if (board[i][0] == board[i][1] && board[i][1] == 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[1][i] == board[2][i] && board[i][0] != ' ') return board[0][i]; } //判断主对角线 if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] != ' ') return board[0][0]; //判断副对角线 if (board[2][0] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ') return board[1][1]; //判断平局 if (is_full(board, row, col) == 1) return 'Q'; //继续游戏 return 'C'; }
-
总结
难的不是函数实现代码,而是能不能想出游戏运行的过程,每一步该干嘛,下一步该怎么走,再一步一步实现。