在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.5+):
gcc --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实现方案
基于评分系统的初级AI:
int 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