在CentOS 7上用C语言手搓一个终端五子棋从Makefile到胜负判定的完整流程五子棋作为中国传统棋类游戏其规则简单却蕴含深奥的策略思维。对于Linux环境下的C语言学习者而言实现一个终端版本的五子棋不仅能巩固编程基础更能深入理解模块化开发思想。本文将带你从零开始在CentOS 7系统上构建完整的五子棋项目涵盖环境配置、核心算法到最终打包的全过程。1. 开发环境准备与项目初始化1.1 基础工具安装在干净的CentOS 7系统中首先确保开发工具链完整sudo yum groupinstall Development Tools sudo yum install vim-enhanced验证gcc版本建议4.8.5gcc --version | head -n11.2 项目目录结构设计采用标准的C项目布局Gobang/ ├── include/ # 头文件目录 │ └── game.h ├── src/ # 源文件目录 │ ├── game.c │ └── main.c ├── Makefile # 构建脚本 └── README.md # 项目说明创建项目骨架mkdir -p Gobang/{include,src} touch Gobang/{Makefile,README.md,include/game.h,src/{game.c,main.c}}2. 核心数据结构设计2.1 棋盘表示方案采用15×15的二维数组作为棋盘基础数据结构在game.h中定义#define BOARD_SIZE 15 typedef enum { EMPTY 0, BLACK 1, // 玩家1执黑 WHITE 2 // 玩家2执白 } Piece; typedef struct { Piece board[BOARD_SIZE][BOARD_SIZE]; int last_move_x; // 记录最后落子位置 int last_move_y; } GameState;2.2 游戏状态枚举定义游戏进行状态typedef enum { ONGOING, BLACK_WIN, WHITE_WIN, DRAW } GameStatus;3. 关键功能模块实现3.1 棋盘初始化与渲染实现清屏和动态刷新效果void clear_screen() { printf(\033[2J\033[H); // ANSI转义序列 } void print_board(const GameState *state) { clear_screen(); printf( ); for (int i 0; i BOARD_SIZE; i) { printf(%2d , i 1); } printf(\n); for (int i 0; i BOARD_SIZE; i) { printf(%2d , i 1); for (int j 0; j BOARD_SIZE; j) { switch (state-board[i][j]) { case BLACK: printf(● ); break; case WHITE: printf(○ ); break; default: printf(· ); break; } } printf(\n); } }3.2 落子合法性校验包含边界检查和位置占用判断int is_valid_move(const GameState *state, int x, int y) { return x 0 x BOARD_SIZE y 0 y BOARD_SIZE state-board[x][y] EMPTY; }4. 胜负判定算法实现4.1 方向枚举与向量计算定义8个检测方向typedef enum { DIR_HORIZONTAL, DIR_VERTICAL, DIR_DIAG_UP, DIR_DIAG_DOWN } Direction; const int dir_vectors[4][2] { {0, 1}, // 水平 {1, 0}, // 垂直 {1, 1}, // 主对角线 {1, -1} // 副对角线 };4.2 连续子检测算法采用双向扫描法提高效率int count_consecutive(const GameState *state, int player, Direction dir) { int dx dir_vectors[dir][0]; int dy dir_vectors[dir][1]; int count 1; // 当前落子点 // 正向检测 for (int i 1; i 5; i) { int nx state-last_move_x dx * i; int ny state-last_move_y dy * i; if (nx 0 || nx BOARD_SIZE || ny 0 || ny BOARD_SIZE || state-board[nx][ny] ! player) break; count; } // 反向检测 for (int i 1; i 5; i) { int nx state-last_move_x - dx * i; int ny state-last_move_y - dy * i; if (nx 0 || nx BOARD_SIZE || ny 0 || ny BOARD_SIZE || state-board[nx][ny] ! player) break; count; } return count 5; }5. Makefile自动化构建5.1 基础编译规则CC gcc CFLAGS -Wall -I./include TARGET gobang SRC src/main.c src/game.c OBJ $(SRC:.c.o) $(TARGET): $(OBJ) $(CC) $(CFLAGS) -o $ $^ %.o: %.c $(CC) $(CFLAGS) -c $ -o $ clean: rm -f $(OBJ) $(TARGET)5.2 添加调试支持debug: CFLAGS -g debug: $(TARGET)6. 人机对战扩展思路6.1 简单AI实现方案基于评分系统的初级AIint evaluate_position(const GameState *state, int player) { int score 0; // 实现简单的棋型评估 // 连珠数、活三、冲四等棋型的分数累加 return score; } void computer_move(GameState *state, int computer_side) { int best_score -1; int best_x -1, best_y -1; for (int i 0; i BOARD_SIZE; i) { for (int j 0; j BOARD_SIZE; j) { if (state-board[i][j] EMPTY) { state-board[i][j] computer_side; int current_score evaluate_position(state, computer_side); state-board[i][j] EMPTY; if (current_score best_score) { best_score current_score; best_x i; best_y j; } } } } if (best_x ! -1) { state-board[best_x][best_y] computer_side; state-last_move_x best_x; state-last_move_y best_y; } }7. 终端交互优化技巧7.1 输入错误处理增强鲁棒性的输入循环int get_player_move(GameState *state, int player) { int x, y; while (1) { printf(玩家%d请输入坐标(行 列): , player); if (scanf(%d %d, x, y) ! 2) { while (getchar() ! \n); // 清空输入缓冲区 printf(输入格式错误请重新输入\n); continue; } x--; y--; // 转换为0-based索引 if (is_valid_move(state, x, y)) { state-board[x][y] (player 1) ? BLACK : WHITE; state-last_move_x x; state-last_move_y y; return 1; } printf(无效落子请重新输入\n); } }7.2 颜色提示功能使用ANSI颜色代码增强可读性void print_colored(const char *text, int color_code) { printf(\033[1;%dm%s\033[0m, color_code, text); } // 使用示例 print_colored(玩家1获胜, 31); // 红色 print_colored(玩家2获胜, 34); // 蓝色8. 项目进阶方向当基础版本完成后可以考虑以下扩展网络对战功能基于socket实现联机对战棋谱记录与回放将对局保存为文本或二进制格式AI算法优化实现minimax算法配合alpha-beta剪枝跨平台移植使用条件编译适配Windows/macOS// 条件编译示例 #ifdef _WIN32 #include windows.h void clear_screen() { system(cls); } #else void clear_screen() { printf(\033[2J\033[H); } #endif