如果你正在寻找主仓库,请访问 Surakarta
第一阶段你有两项任务:
- 完成游戏规则的实现
- 实现一个简单的 AI
所有我认为你需要阅读/填空/修改的代码,我都加了 TODO
注释,你可以全局搜索。
你需要填空 src/surakarta/surakarta_rule_manager.cpp
中的函数以正确完成一系列和规则判断有关的函数。
游戏的执行逻辑已经在 src/surakarta/surakarta_game.cpp
中实现,他们会调用你实现的函数,了解执行逻辑可能会有助于你完成 surakarta_rule_manager.cpp
中的函数。
因为用到了少量未来课程的知识,你还可以通过完成 src/hello_cpp
中的 TODO 来学习。
在 src/surakarta/surakarta_agent
下有两个具体的 AI 实现,其中 surakarta_agnet_random
是已经实现好的随机 AI,只要你把 rule_manager
的 JudgeMove
实现好,就可以正确运行。
surakarta_agnet_mine
是你需要实现的 AI,你可以在其中实现你的 AI 算法,并最终在 src/surakarta/main.cpp
中调用你的 AI 和随机 AI 进行对战。
实现好后,你可以运行 build/bin/main
来观察,这一部分没有 google test。
一种粗暴的方式是 clone 完代码后,删掉 .git 文件夹,重新初始化成你的仓库。
但是我强烈建议,甚至应该说要求用以下这种方式 clone,以保证你可以借助 git 工具来将这个仓库的更新 pull 到你的仓库里。
The following instructions are adapted from the Github documentation on duplicating a repository. The procedure below walks you through creating a private Surakarta-RuleAiTest repository that you can use for development.
-
Go here to create a new repository under your account. Pick a name (e.g.
Surakarta-RuleAiTest-private
) and select Private for the repository visibility level. -
On your development machine, create a bare clone of the public Surakarta-RuleAiTest repository:
$ git clone --bare https://github.com/panjd123/Surakarta-RuleAiTest.git Surakarta-RuleAiTest-public
-
Next, mirror the public Surakarta-RuleAiTest repository to your own private Surakarta-RuleAiTest repository. Suppose your GitHub name is
student
and your repository name isSurakarta-RuleAiTest-private
. The procedure for mirroring the repository is then:$ cd Surakarta-RuleAiTest-public # If you pull / push over HTTPS $ git push https://github.com/student/Surakarta-RuleAiTest-private.git master # If you pull / push over SSH $ git push git@github.com:student/Surakarta-RuleAiTest-private.git master
This copies everything in the public Surakarta-RuleAiTest repository to your own private repository. You can now delete your local clone of the public repository:
$ cd .. $ rm -rf Surakarta-RuleAiTest-public
-
Clone your private repository to your development machine:
# If you pull / push over HTTPS $ git clone https://github.com/student/Surakarta-RuleAiTest-private.git # If you pull / push over SSH $ git clone git@github.com:student/Surakarta-RuleAiTest-private.git
-
Add the public Surakarta-RuleAiTest repository as a second remote. This allows you to retrieve changes from the panjd123 repository and merge them with your solution throughout the semester:
$ git remote add public https://github.com/panjd123/Surakarta-RuleAiTest.git
You can verify that the remote was added with the following command:
$ git remote -v origin https://github.com/student/Surakarta-RuleAiTest-private.git (fetch) origin https://github.com/student/Surakarta-RuleAiTest-private.git (push) public https://github.com/panjd123/Surakarta-RuleAiTest.git (fetch) public https://github.com/panjd123/Surakarta-RuleAiTest.git (push)
-
You can now pull in changes from the public Surakarta-RuleAiTest repository as needed with:
$ git pull public master
We suggest working on your projects in separate branches. If you do not understand how Git branches work, learn how. If you fail to do this, you might lose all your work at some point in the semester, and nobody will be able to help you.
git clone git@github.com:google/googletest.git
cd googletest
mkdir build
cd build
cmake ..
make
sudo make install
mkdir build
cd build
cmake ..
make
./bin/main # 对应 src/surakarta/main.cpp,你可以用来调试 surakarta
./bin/main_ta # 对应 src/surakarta_ta/main.cpp,相当于助教的实现,你们完成项目后应该达成的效果
./bin/hello_cpp_test # 验证 src/hello_cpp/hello_cpp.h 的正确性
./bin/surakarta_rule_manager_test # 验证 src/surakarta/surakarta_rule_manager.cpp 的正确性
该项目推荐使用 VSCode + 插件 C/C++, CMake, CMake Tools 在 Linux 下开发。
为了 IntelliSense
能正常工作,我推荐你在本 Workspace 下这样设置 settings.json
:
{
// "C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools",
"C_Cpp.default.configurationProvider": "ms-vscode.cpp-tools",
"C_Cpp.default.includePath": [
"${workspaceFolder}/src"
],
}
"C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools"
会有点问题
一种比较简单的实现吃子判断的思路是:在吃子路线上绕一圈,维护一个棋子链,检查每个圆弧的两边是不是异色棋子,如果是,这对棋子就是可以互吃的。
这是一个粗糙的思路,还有细节的问题请自行思考。
我们会测试棋盘不变的情况下,多次(100次)查询不同的 JudgeMove
和 JudgeEnd
,而不总是棋盘每次改变只查询一次,你可以针对性地优化性能。
我们给 JudgeEnd
和 JudgeMove
单独写了测试,你不必一上来就跑最后的那个随机测试。
随机测试默认会跑 10000 局,每局约 100 步,每步会插入 100 条随机测试。测试耗时在 10-100 秒之间是比较合理的。你可以这样修改具体的参数,比如跑更多的局数。
export NUM_GAME=100000
export OFFLINE_TEST_ROUND=100
./bin/surakarta_rule_manager_test
我写了两个例子,比较正式的方法是 SurakartaRuleManager::HelloWorld
,比较省事的是 SurakartaRuleManager::InlineHelloWorld
。
智能指针,避免手动管理内存以预防内存泄露,我建议一开始就学习使用智能指针,不要使用裸指针。(虽然这个是后面课程的内容)
考虑下面这段代码,其中 new
会在堆上分配内存,delete
会释放内存,但是如果你忘记 delete
,那么这块内存就会一直被占用,直到重启电脑。这就是内存泄露,而智能指针可以帮助我们避免这种情况。
// raw pointer example
#include <iostream>
int main(){
int* p = new int(1);
std::cout << *p << std::endl;
// delete p;
}
std::shared_ptr
和 std::unique_ptr
都是智能指针,它们的区别在于,std::shared_ptr
可以被多个指针指向同一个对象,而 std::unique_ptr
只能被一个指针指向。
其原理是 p 是分配在栈上的,其会被自动释放,其自动释放时会把指向对象的引用计数减一,当引用计数为 0 时,其就会自动释放堆上的内存。
unique_ptr 的稍微特别一点,其不允许被复制,但是可以被移动,即本来是 r 指向的对象,现在变成了 s 指向的对象,但这样 r 就不再指向任何对象了,或者说变成了空指针,你再使用 r 就会出错。
// smart pointer example
#include <iostream>
#include <memory>
int main() {
std::shared_ptr<int> p = std::make_shared<int>(1);
std::shared_ptr<int> q = p;
std::cout << *p << std::endl;
std::cout << *q << std::endl;
std::unique_ptr<int> r = std::make_unique<int>(1);
// std::unique_ptr<int> s = r; // Compile error
std::cout << *r << std::endl;
std::unique_ptr<int> s = std::move(r); // ok
std::cout << *s << std::endl;
// std::cout << *r << std::endl; // Segmentation fault
}
智能指针,你可以理解为,写起来复杂,但只要写出来了就一般不会错。普通指针就是好写,但是容易出错。
可以,但是我们仍然不可避免地会遇到“棋子类”,比如你在 Qt 中想要用某个控件表示棋子,这个控件必然是一个类。 此时这个 board_ 更像一个映射,由坐标到类的映射,方便在比如你吃掉一个棋子的时候,找到对应的控件并删除它。 但是还有一种比较暴力的方法是,每次都根据 board_ 遍历棋盘,重绘所有棋子,当画画来处理,那可能就不需要这种形式的实现了。但我更推荐前者的实现逻辑。
这个阶段必须用这个框架,之后你可以自己写一个框架,但是要求能通过这个测试,即你把你的框架内的规则相关的类取出来,然后在 JudgeMove
和 JudgeEat
中调用你的函数,你可能需要做一个转化,比如你是用二维int数组表示棋盘的,你就在函数里预处理一下啥的。
设计这个测试的一大目的是强制面向对象。
该部分和学生任务无关
cmake .. -DENV=TEST # 测试环境
cmake .. -DENV=DEV # 开发环境
开发环境下 make install
会生成助教实现的 src/surakarta_ta/surakarta_rule_manager_imp.cpp
的动态链接库到 surakarta_ta
测试环境下会到 surakarta_ta
下寻找动态链接库用于测试。