-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpimc.cc
More file actions
171 lines (155 loc) · 6.15 KB
/
Copy pathpimc.cc
File metadata and controls
171 lines (155 loc) · 6.15 KB
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
//
// Created by qzz on 2023/11/20.
//
#include "pimc.h"
#include "absl/strings/str_cat.h"
#include "playcc/common_utils/log_utils.h"
int Rollout(const ble::BridgeState& state, const ble::BridgeMove& move) {
SetMaxThreads(0);
auto child = state.Child(move);
const ble::Contract contract = state.GetContract();
if (child.IsTerminal()) {
// The state may reach terminal after playing a card.
if (IsActingPlayerDeclarerSide(state)) {
return child.NumDeclarerTricks() >= contract.level + 6;
}
return child.NumDeclarerTricks() < contract.level + 6;
}
auto dl = StateToDDSDeal(child);
const ble::Player child_player = child.CurrentPlayer();
futureTricks fut{};
const int res = SolveBoard(dl,
/*target=*/-1, // Maximum number of tricks
/*solutions=*/1, // One card
/*mode=*/2, // Reuse tt
&fut,
/*threadIndex=*/0);
if (res != RETURN_NO_FAULT) {
char error_message[80];
ErrorMessage(res, error_message);
SpielFatalError(absl::StrCat("double dummy solver:", error_message));
}
const int num_tricks_left = ble::kNumTricks - child.NumTricksPlayed();
// The player act at original state is declarer side.
if (const bool is_max_node = IsActingPlayerDeclarerSide(state); is_max_node) {
// The player act at child state is declarer side.
if (ble::Partnership(child_player) ==
ble::Partnership(state.CurrentPlayer())) {
return fut.score[0] + child.NumDeclarerTricks() >= contract.level + 6;
} else {
// The player act at child state is defender side.
return num_tricks_left - fut.score[0] + child.NumDeclarerTricks() >=
contract.level + 6;
}
}
// The player act at original state is defender side.
if (ble::Partnership(child_player) ==
ble::Partnership(state.CurrentPlayer())) {
// The player act at child state is defender side.
// Defender side wins if declarer win less tricks than (target level + 6)
const int num_tricks_declarer_can_win =
num_tricks_left - fut.score[0] + child.NumDeclarerTricks();
return num_tricks_declarer_can_win < contract.level + 6;
}
// The player act at child state is declarer side.
const int num_tricks_declarer_can_win =
fut.score[0] + child.NumDeclarerTricks();
return num_tricks_declarer_can_win < contract.level + 6;
}
std::pair<ble::BridgeMove, int> GetBestAction(const SearchResult& res) {
const auto it = std::max_element(res.scores.begin(), res.scores.end());
const int index = static_cast<int>(std::distance(res.scores.begin(), it));
return std::make_pair(res.moves[index], res.scores[index]);
}
SearchResult PIMCBot::Search(const ble::BridgeState& state) const {
// const auto legal_moves = state.LegalMoves();
const auto legal_moves = GetLegalMovesWithoutEquivalentCards(state);
const int num_legal_moves = static_cast<int>(legal_moves.size());
// std::cout << "num legal moves: " << num_legal_moves << std::endl;
SearchResult res{};
res.moves = legal_moves;
res.scores = std::vector<int>(num_legal_moves, 0);
// if (num_legal_moves == 1) {
// return res;
// }
// for (int i = 0; i < num_sample_; ++i) {
// auto resample_result = resampler_->Resample(state);
// if (!resample_result.success) {
// --i;
// continue;
// }
// // std::cout << "sampled deal " << i << std::endl;
// auto sampled_state = ConstructStateFromDeal(resample_result.result, state.ParentGame(), state);
// // std::cout << sampled_state->ToString() << std::endl;
// for (int j = 0; j < num_legal_moves; ++j) {
// const int score = Rollout(sampled_state, legal_moves[j]);
// // std::cout << score << std::endl;
// res.scores[j] += score;
// }
// // std::cout << "accumulate scores" << std::endl;
// }
const auto deals = ResampleMultipleDeals(resampler_, state, cfg_.num_worlds);
// std::cout << "Deals sampled in pimc:\n" << std::endl;
// for (const auto d : deals) {
// PrintArray(d);
// }
for (int i = 0; i < cfg_.num_worlds; ++i) {
auto sampled_state = ConstructStateFromDealAndOriginalState(
deals[i], state.ParentGame(), state);
// std::cout << sampled_state.ToString() << std::endl;
for (int j = 0; j < num_legal_moves; ++j) {
const int score = Rollout(sampled_state, legal_moves[j]);
// std::cout << score << std::endl;
res.scores[j] += score;
}
}
return res;
}
ble::BridgeMove PIMCBot::Step(const ble::BridgeState& state) {
if (state.IsInPhase(ble::Phase::kAuction)) {
if (bidding_bot_ == nullptr) {
SpielFatalError("Can't step in auction phase without a bidding bot.");
}
return bidding_bot_->Step(state);
}
SPIEL_CHECK_EQ(static_cast<int>(state.CurrentPhase()),
static_cast<int>(ble::Phase::kPlay));
// const auto legal_moves = state.LegalMoves();
const auto legal_moves = GetLegalMovesWithoutEquivalentCards(state);
if (const int num_legal_moves = static_cast<int>(legal_moves.size());
num_legal_moves == 1) {
if (!cfg_.search_with_one_legal_move) {
return legal_moves[0];
}
}
const SearchResult res = Search(state);
auto [move, score] = GetBestAction(res);
if (cfg_.verbose) {
PrintSearchResult(res);
}
return move;
}
void PrintSearchResult(const SearchResult& res) {
for (int i = 0; i < res.moves.size(); ++i) {
std::cout << "Move " << res.moves[i].ToString()
<< ", Score: " << res.scores[i] << "\n";
}
}
std::unique_ptr<PlayBot> MakePIMCBot(ble::Player player_id, PIMCConfig cfg) {
return std::make_unique<PIMCBot>(nullptr, player_id, cfg);
}
namespace {
class PIMCFactory : public BotFactory {
public:
~PIMCFactory() = default;
std::unique_ptr<PlayBot> Create(
std::shared_ptr<const ble::BridgeGame> game, ble::Player player,
const ble::GameParameters& bot_params) override {
const int num_worlds =
ble::ParameterValue<int>(bot_params, "num_worlds", 20);
const PIMCConfig cfg{num_worlds, false};
return MakePIMCBot(player, cfg);
}
};
REGISTER_PLAY_BOT("pimc", PIMCFactory);
} // namespace