File: Search.cpp

package info (click to toggle)
pentobi 29.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 3,892 kB
  • sloc: cpp: 25,719; javascript: 875; xml: 40; makefile: 13; sh: 6
file content (172 lines) | stat: -rw-r--r-- 5,659 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
//-----------------------------------------------------------------------------
/** @file libpentobi_mcts/Search.cpp
    @author Markus Enzenberger
    @copyright GNU General Public License version 3 or later */
//-----------------------------------------------------------------------------

#include "Search.h"

#include "Util.h"

namespace libpentobi_mcts {

//-----------------------------------------------------------------------------

Search::Search(Variant initial_variant, unsigned nu_threads, size_t memory)
    : SearchBase(nu_threads == 0 ? get_nu_threads() : nu_threads, memory),
      m_variant(initial_variant),
      m_shared_const(m_to_play)
{
    set_default_param(m_variant);
    create_threads();
}

bool Search::check_followup(ArrayList<Move, max_moves>& sequence)
{
    auto& bd = get_board();
    m_history.init(bd, m_to_play);
    bool is_followup = m_history.is_followup(m_last_history, sequence);

    // If avoid_symmetric_draw is enabled, class State uses a different
    // evaluation function depending on which player is to play in the root
    // position (the first player knows about symmetric draws to be able to
    // play a symmetry breaker but the second player pretends not to know about
    // symmetric draws to avoid going for such a draw). In this case, we cannot
    // reuse parts of the old search tree if the computer plays both colors.
    if (m_shared_const.avoid_symmetric_draw
            && is_followup && m_to_play != m_last_history.get_to_play()
            && has_central_symmetry(bd.get_variant())
            && ! check_symmetry_broken(bd))
        is_followup = false;

    m_last_history = m_history;
    return is_followup;
}

unique_ptr<State> Search::create_state()
{
    return make_unique<State>(m_variant, m_shared_const);
}

void Search::get_root_position(Variant& variant, Setup& setup) const
{
    m_last_history.get_as_setup(variant, setup);
    setup.to_play = m_to_play;
}

void Search::on_start_search(bool is_followup)
{
    m_shared_const.init(is_followup);
}

bool Search::search(Move& mv, const Board& bd, Color to_play,
                    Float max_count, size_t min_simulations,
                    double max_time, TimeSource& time_source)
{
    // We need to be sure that the maximum number of legal moves fits into
    // the integer type used in Node. Currently, this is even true for all
    // moves, which is an upper limit to all legal moves.
    LIBBOARDGAME_ASSERT(bd.get_board_const().get_range() <= Node::max_children);
    m_shared_const.board = &bd;
    m_to_play = to_play;
    auto variant = bd.get_variant();
    if (variant != m_variant)
        set_default_param(variant);
    m_variant = variant;
    bool result = SearchBase::search(mv, max_count, min_simulations, max_time,
                                      time_source);
    // Search doesn't generate all useless one-piece moves in Callisto
    if (result && mv.is_null() && bd.get_piece_set() == PieceSet::callisto
            && bd.is_piece_left(to_play, bd.get_one_piece()))
    {
        for (Point p : bd)
            if (! bd.is_forbidden(p, to_play) && ! bd.is_center_section(p))
            {
                auto moves = bd.get_board_const().get_moves(bd.get_one_piece(),
                                                            p, 0);
                LIBBOARDGAME_ASSERT(moves.size() == 1);
                mv = *moves.begin();
                result = true;
                break;
            }
    }
    return result;
}

void Search::set_default_param(Variant variant)
{
    LIBBOARDGAME_LOG("Setting default parameters for ", to_string(variant));
    set_rave_weight(0.7f);
    set_rave_child_max(2000);
    switch (variant)
    {
    case Variant::classic:
    case Variant::classic_2:
    case Variant::classic_3:
    case Variant::gembloq:
    case Variant::gembloq_2_4:
    case Variant::gembloq_3:
        // Tuned for classic_2
        set_exploration_constant(0.4f);
        set_rave_parent_max(50000);
        break;
    case Variant::duo:
    case Variant::junior:
    case Variant::gembloq_2:
        // Tuned for duo
        set_exploration_constant(0.5f);
        set_rave_parent_max(25000);
        break;
    case Variant::trigon:
    case Variant::trigon_2:
    case Variant::trigon_3:
    case Variant::callisto:
    case Variant::callisto_2_4:
    case Variant::callisto_3:
        // Tuned for trigon_2
        set_exploration_constant(0.87f);
        set_rave_parent_max(50000);
        break;
    case Variant::nexos:
    case Variant::nexos_2:
        // Tuned for nexos_2
        set_exploration_constant(0.55f);
        set_rave_parent_max(50000);
        break;
    case Variant::callisto_2:
        set_exploration_constant(0.4f);
        set_rave_parent_max(25000);
        break;
    }
}

string Search::get_info() const
{
    if (get_nu_simulations() == 0)
        return {};
    auto& root = get_tree().get_root();
    auto nu_children = root.get_nu_children();
    if (nu_children <= 0)
        return {};
    ostringstream s;
    s << SearchBase::get_info() << "Mov " << nu_children << ", ";
    if (libpentobi_base::get_nu_players(m_variant) > 2)
    {
        s << "All";
        for (PlayerInt i = 0; i < libpentobi_base::get_nu_colors(m_variant);
             ++i)
        {
            if (get_root_val(i).get_count() == 0)
                s << " -";
            else
                s << " " << setprecision(2) << get_root_val(i).get_mean();
        }
        s << ", ";
    }
    s << get_state(0).get_info();
    return s.str();
}

//-----------------------------------------------------------------------------

} // namespace libpentobi_mcts