工程结构
对局规则 定下了玩家能看到的输入、输出与对局结果。井字棋工程把这些外部表现对应到目录和文件,先看目录分工,再看每类内容该放进哪个文件。
目录分工
工程根下的目录各放这些内容:
- 动态库:
tictactoe/保存棋盘、对局与电脑落子,编译成动态库供程序调用。 - 程序入口:
apps/当前只编译main.cpp,由它最小调用动态库;终端程序的cli.h、cli.cpp保留在同一目录,但暂不参与构建。 - 测试:
tests/保存棋盘测试;tictactoe_test已接入构建,由 CTest 运行 15 条用例。 - CMake 复用:
cmake/当前只保留CompileSettings.cmake,用它声明 C++ 标准、选择警告等级。 - 回放与网页脚本:
python/提供对局回放与本地网页,通过 JSON 快照读取对局,不参与 C++ 构建。 - 构建产物:
build/由配置和编译生成,存放可执行文件、动态库文件与测试程序。
构建目录 build/ 里是生成物,没有源码。整个目录可以删掉,也可以换一个路径;下一次配置和编译会按源码重新生成。
文件位置
工程自己的配置、源码、脚本与构建产物这样分布;行尾注释说明每一项是什么,目录用 #/,文件用 #:
games/tictactoe/
├── CMakeLists.txt # 整份工程的构建规则
├── apps/ #/ 程序入口
│ ├── src/main.cpp # 最小动态库调用
│ ├── include/cli.h # 终端程序接口,暂未接入
│ └── src/cli.cpp # 终端程序实现,暂未接入
├── build/ #/ 构建产物
├── cmake/ #/ 构建函数
│ └── CompileSettings.cmake # 编译设置
├── python/ #/ 回放与网页
├── running-build.sh # 编译与测试入口
├── tests/ #/ 棋盘测试
│ ├── CMakeLists.txt # 测试构建规则
│ └── testing-board.cpp # 15 条棋盘用例
└── tictactoe/ #/ 动态库
├── include/board.h # 棋盘尺寸与坐标
├── include/game.h # 对局规则
├── include/ai.h # 电脑落子
├── src/board.cpp # 棋盘实现
├── src/game.cpp # 对局实现
└── src/ai.cpp # 电脑落子实现
头文件写接口,源文件写实现;tictactoe/ 编译成动态库。apps/ 的 app 链接它,tests/ 的 tictactoe_test 链接同一份库并由 CTest 运行。build/bin/ 放可执行文件,build/lib/ 放动态库文件,两处都由编译生成。
常见错误
打印逻辑混进动态库
动态库里出现 std::cout 后,测试或换界面都得连终端一起处理。
- 出错的原因:显示属于调用方,库一旦直接打印,就把终端绑进了可复用代码。
- 正确的做法:动态库返回数据,
apps/的终端层决定怎样显示。
构建产物当作源码
在 build/ 里新建头文件或改 CMakeLists.txt,换一个构建目录就丢失。
- 出错的原因:
build/由编译生成,清理或重新编译会覆盖其中的手工改动。 - 正确的做法:源码和脚本放在
apps/、tictactoe/、tests/、cmake/、python/这五个目录里。根目录放CMakeLists.txt、running-build.sh和三个 clang 配置文件。
自测问题
要查找棋盘格子的保存位置,先看
apps/、tests/还是tictactoe/目录?查看答案
先看动态库目录
tictactoe/。棋盘格子的定义在其中的include/board.h,实现放在src/board.cpp。打印棋盘由终端程序实现,还是由动态库实现?
查看答案
由终端程序实现。打印棋盘和读入坐标属于文本交流,放在
apps/。动态库保存棋盘、对局与电脑落子,供终端程序调用。构建完成后,可执行文件和动态库文件分别放在
build/的bin/还是lib/?查看答案
可执行文件在
build/bin/,动态库文件在build/lib/。
本章回顾
你已经能在工程目录里找到动态库、程序入口与测试目录,也能找到保留未接入的终端程序。你还能说出 build/ 为什么可以删掉后重新生成。下一章是程序结构,看这四块怎样连成一份程序。