当前位置: 首页 > news >正文

在Linux上用C语言手搓一个五子棋:从终端棋盘到胜负判断的完整实现

在Linux上用C语言手搓一个五子棋:从终端棋盘到胜负判断的完整实现

五子棋作为一款经典策略游戏,其规则简单却蕴含丰富的算法思想。对于Linux环境下的C语言学习者而言,实现一个终端版本的五子棋不仅能巩固编程基础,更能深入理解状态管理、算法设计等核心概念。本文将带你从零构建完整的五子棋游戏,重点解析数据结构设计、胜负判断算法等关键环节,同时分享工程化实践中的Makefile编写技巧。

1. 环境准备与项目架构

1.1 开发环境配置

确保你的Linux系统已安装gcc编译器和make工具:

# Ubuntu/Debian sudo apt update && sudo apt install build-essential # CentOS/RHEL sudo yum groupinstall "Development Tools"

1.2 项目目录结构

采用模块化设计,创建以下文件:

gobang/ ├── Makefile # 构建规则 ├── game.h # 头文件(常量定义、函数声明) ├── game.c # 核心逻辑实现 └── main.c # 程序入口

提示:使用tree命令可快速查看目录结构,若未安装可通过sudo apt install tree获取

2. 核心数据结构设计

2.1 棋盘表示方案

采用二维数组存储棋盘状态,定义三种状态值:

// game.h #define EMPTY 0 #define PLAYER1 1 // 黑棋 #define PLAYER2 2 // 白棋 #define BOARD_SIZE 15 // 标准15x15棋盘 int board[BOARD_SIZE][BOARD_SIZE];

2.2 方向枚举优化

为简化五子连珠判断,使用枚举定义8个检测方向:

enum Direction { LEFT, RIGHT, UP, DOWN, LEFT_UP, LEFT_DOWN, RIGHT_UP, RIGHT_DOWN };

3. 关键算法实现

3.1 棋盘渲染函数

实现终端动态刷新效果:

void render_board() { printf("\033[2J\033[H"); // ANSI清屏指令 // 打印列标 printf(" "); for (int j = 0; j < BOARD_SIZE; j++) printf("%2d ", j+1); puts(""); // 打印棋盘内容 for (int i = 0; i < BOARD_SIZE; i++) { printf("%2d ", i+1); for (int j = 0; j < BOARD_SIZE; j++) { switch(board[i][j]) { case EMPTY: printf(" · "); break; case PLAYER1: printf(" ● "); break; case PLAYER2: printf(" ○ "); break; } } puts(""); } }

3.2 智能落子检测

实现输入合法性校验:

bool is_valid_move(int x, int y) { return x >= 1 && x <= BOARD_SIZE && y >= 1 && y <= BOARD_SIZE && board[x-1][y-1] == EMPTY; }

4. 胜负判定系统

4.1 方向计数算法

核心函数count_in_direction实现:

int count_in_direction(int x, int y, enum Direction dir) { int dx[] = {0,0,-1,1,-1,1,-1,1}; int dy[] = {-1,1,0,0,-1,-1,1,1}; int count = 0; int player = board[x][y]; for (int i = 1; i <= 4; i++) { int nx = x + i*dx[dir]; int ny = y + i*dy[dir]; if (nx < 0 || nx >= BOARD_SIZE || ny < 0 || ny >= BOARD_SIZE || board[nx][ny] != player) { break; } count++; } return count; }

4.2 全局胜负判断

组合8个方向的检测结果:

bool check_win(int x, int y) { for (int dir = 0; dir < 4; dir++) { int opposite_dir = dir + 4; int total = 1 + count_in_direction(x, y, dir) + count_in_direction(x, y, opposite_dir); if (total >= 5) return true; } return false; }

5. 工程化实践

5.1 Makefile编写

自动化构建规则:

CC = gcc CFLAGS = -Wall -Wextra TARGET = gobang SRCS = main.c game.c OBJS = $(SRCS:.c=.o) $(TARGET): $(OBJS) $(CC) $(CFLAGS) -o $@ $^ %.o: %.c game.h $(CC) $(CFLAGS) -c $< clean: rm -f $(OBJS) $(TARGET)

5.2 防御式编程技巧

添加边界检查宏:

#define ASSERT_BOARD_POS(x,y) \ do { \ if ((x) < 0 || (x) >= BOARD_SIZE || \ (y) < 0 || (y) >= BOARD_SIZE) { \ fprintf(stderr, "Invalid position: %d,%d\n", x, y); \ exit(EXIT_FAILURE); \ } \ } while(0)

6. 功能扩展思路

6.1 人机对战实现

简单AI算法框架:

typedef struct { int x, y; int score; } Move; Move find_best_move(int player) { Move best = {0}; best.score = -1; for (int i = 0; i < BOARD_SIZE; i++) { for (int j = 0; j < BOARD_SIZE; j++) { if (board[i][j] != EMPTY) continue; int current_score = evaluate_position(i, j, player); if (current_score > best.score) { best.x = i; best.y = j; best.score = current_score; } } } return best; }

6.2 游戏状态保存

实现存档功能:

void save_game(const char* filename) { FILE *fp = fopen(filename, "wb"); if (!fp) { perror("Save failed"); return; } fwrite(board, sizeof(int), BOARD_SIZE*BOARD_SIZE, fp); fclose(fp); }

在项目开发过程中,最容易被忽视的是棋盘边界条件的处理。实际测试发现,当落子位于棋盘边缘时,传统的四方向检测可能引发数组越界。通过引入ASSERT_BOARD_POS宏和方向向量的预计算,既保证了安全性又提升了代码可读性。

http://www.jsqmd.com/news/759205/

相关文章:

  • 2026年5月丨企业选型指南:SD-WAN供应商性价比横向对比 - 品牌企业推荐师(官方)
  • 告别卡顿!在中标麒麟NeoKylin上为你的Qt视频监控软件开启FFmpeg硬解码(QSV/VAAPI)
  • Embedding 模型选型与向量化实战:从 BERT 到多模态
  • 别再写一堆Redis命令了!用Lua脚本实现分布式锁和库存扣减,实战避坑指南
  • Dify上线前必须冻结的6项租户配置,第3项未校验将触发跨租户数据批量导出——立即自查!
  • 初次使用 Taotoken 从注册到发出第一个聊天请求的全流程指南
  • Multisim教育版元件库保姆级使用指南:从虚拟器件到真实元件的快速上手
  • 从乘用车到商用车:搞懂CAN总线,为什么15765和J1939协议硬件一样却用法天差地别?
  • 珠三角高空车防撞车租赁五强出炉!广东战狼凭 “三多” 实力登顶,振邦、老兵紧随其后 - 广州搬家老班长
  • 用Taotoken的OpenAI兼容接口为AE视频片段生成创意文案
  • 2026 嘉兴除甲醛 6 大排名权威发布 - 品牌企业推荐师(官方)
  • SAP PM维修工单实操:从IW31创建到IW32修改,手把手教你搞定设备维修数据归集
  • Dify工业检索响应超时?不是算力问题——而是这6个元数据字段未标准化!(附GB/T 20984-2022合规映射表)
  • 大语言模型上下文优化:CRO方法解析与实践
  • AI代码安全评估框架与SecureCode数据集解析
  • 用Python和Pandas玩转GDELT全球新闻数据库:从数据下载到初步分析的保姆级教程
  • 终极指南:ViGEmBus虚拟手柄驱动 - 3分钟解决Windows游戏手柄兼容性问题
  • 别再手动拖进度条了!用Python+OpenCV实现视频自动摘要,5分钟搞定核心内容提取
  • Dify农业知识库离线版上线倒计时!仅剩72小时——附赠已通过农业农村部备案的NLP微调参数包
  • 2026绍兴除甲醛品牌权威榜单发布!六大实力机构实测测评结果公示 - 品牌企业推荐师(官方)
  • 3步实现Unity游戏自动翻译:XUnity.AutoTranslator新手完全指南
  • 三指拖拽革命:如何在Windows触控板上实现macOS级手势体验
  • 1.5小时用AI+静态网页+Google Sheets打造家庭餐食规划器
  • 告别官方服务器!用自建ZeroTier Planet为你的Homelab打造超低延迟私有网络(Windows/macOS/Linux全平台客户端配置指南)
  • 保姆级教程:在CentOS 9 Stream上用Anaconda3安装MetaPhlAn4,并手动配置最新版数据库(避坑指南)
  • 阴阳师百鬼夜行自动化脚本:5分钟快速上手指南
  • 智能考勤自动化:跨设备远程打卡系统架构解析
  • 别再傻傻用互斥锁了!C++20实战:用std::latch和std::barrier重构你的多线程任务调度
  • 从理论到实战:GCC-PHAT算法在麦克风阵列声源定位中的调参与避坑指南
  • 2026 负债人逾期自救精简手册:靠谱机构亲测 + 核心政策 + 落地上岸方案 - 品牌企业推荐师(官方)