zoukankan      html  css  js  c++  java
  • 再写围棋的MC模拟

      有了棋串的数据结构后,落子就变得很高效了,接下来要生成随机棋步。

      以9x9棋盘为例,直接生成0~80的随机数进行模拟会很低效,因为它们并不都是合法落子点——有3类落子点是非法的:1. 非空点 2. 劫争点 3. 自杀点。

      自然想在模拟过程中增量维护这3类点集,前两类很容易维护,难点在于自杀点的增量维护。

      着手写自杀点的维护后,才发现问题出乎意料的复杂。我先写了个IsSuiside函数,通过试下作为最终的裁决,而这又涉及到对象的拷贝,太过昂贵。于是想尽量少用,通过位运算来判定多数情况。然后随着测试的进行,陆续发现多处的位运算判定不可靠,不得不用IsSuiside函数替代……

      最后的效率可想而知,9 x 9棋盘模拟1w局,用时约40秒——这是不可授受的。

      回过头来思考,越发觉得这件事并不必要做。多数情况下,自杀点本身并无价值(除了打劫时也许可作劫材),即使允许自杀,在UCT搜索过程中,自杀点自然会冷下来——用过多的资源判定自杀点划不来。

      于是修改程序,让规则允许自杀,不过为了尽早结束棋局,不允许自填眼位,也不允许填对方眼位而不提子。增量维护眼位集合要简单得多。

      测试下来要快很多,9 x 9棋盘,2.3秒模拟1万局,CPU是2.4G core 2,编译器是clang,开O3优化级。

      Simulate函数:

    template <BoardLen BOARD_LEN>
    PointIndex
    MCSimulator<BOARD_LEN>::Simulate(const BoardInGm<BOARD_LEN> &input_board) const
    {
        BoardInGm<BOARD_LEN> bingm;
        bingm.Copy(input_board);
    
        do {
            PlayerColor last_player = bingm.LastPlayer();
            PlayerColor cur_player = OppstColor(last_player);
            const auto &playable = bingm.PlayableIndexes(cur_player);
    
            std::bitset<BLSq<BOARD_LEN>()> noko_plbl(playable);
            PointIndex ko = bingm.KoIndex();
            if (ko != BoardInGm<BOARD_LEN>::NONE) {
                std::bitset<BLSq<BOARD_LEN>()> kobits;
                kobits.set();
                kobits.reset(ko);
                noko_plbl &= kobits;
            }
    
            PointIndex play_c = noko_plbl.count();
            if (play_c > 0) {
                PointIndex rand = this->Rand(play_c - 1);
                PointIndex cur_indx =
                    GetXst1<BLSq<BOARD_LEN>()>(noko_plbl, rand);
                bingm.PlayMove(Move(cur_player, cur_indx));
            } else {
                bingm.Pass(cur_player);
            }
        } while(bingm.PlayableIndexes(BLACK_PLAYER).count() > 0 ||
                bingm.PlayableIndexes(WHITE_PLAYER).count() > 0);
    
        return bingm.BlackRegion();
    }

      忽然想试试19路标准棋盘下,双方随机落子黑棋能赢多少,测试函数:

    template <BoardLen BOARD_LEN>
    void MCSimulator<BOARD_LEN>::TEST()
    {
        int begin = clock();
        int sum = 0;
        const int a = 10000;
        for (int i=0; i<a; ++i) {
            BoardInGm<TEST_LEN> b;
            b.Init();
            auto &mcs = MCSimulator<TEST_LEN>::Ins();
            int r = mcs.Simulate(b);
            sum += r;
        }
        int end = clock();
        printf("time = %f\n", (float)(end - begin) / 1000000);
        printf("simulate complte.\n");
        printf("average black = %f\n", (float)sum / a);
    }

      19路的模拟速度有点慢,28秒1w局。看来随机落子的先行优势并不明显……

      代码:https://github.com/chncwang/FooGo

  • 相关阅读:
    ZOJ Problem Set–2417 Lowest Bit
    ZOJ Problem Set–1402 Magnificent Meatballs
    ZOJ Problem Set–1292 Integer Inquiry
    ZOJ Problem Set–1109 Language of FatMouse
    ZOJ Problem Set–1295 Reverse Text
    ZOJ Problem Set–1712 Skew Binary
    ZOJ Problem Set–1151 Word Reversal
    ZOJ Problem Set–1494 Climbing Worm
    ZOJ Problem Set–1251 Box of Bricks
    ZOJ Problem Set–1205 Martian Addition
  • 原文地址:https://www.cnblogs.com/qswang/p/2815632.html
Copyright © 2011-2022 走看看