simplePredictor.cc Source File

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
simplePredictor.cc
Go to the documentation of this file.
1 #include "osl/enter_king/simplePredictor.h"
2 #include "osl/enter_king/enterKingUtil.h"
3 #include <math.h>
4
5 namespace {
6 // 入玉に必要な点数と現在の点数、調べた行の点数と枚数から
7 // 入玉に必要な駒の数を返す
8 // cur_points にpoints_on_row を足す前に呼ぶ
9 int calcNumPiecesNeeded(const int cur_points, const int points_on_row,
10 const int num_pieces_on_row, const int threshold) {
11 if (points_on_row == num_pieces_on_row)
12 return threshold - cur_points;
13 const int points_needed = threshold - cur_points;
14 const int num_major = (points_on_row - num_pieces_on_row) / 4;
15 if (points_needed <= 5 * num_major)
16 return (points_needed + 4) / 5;
17 else
18 return num_major + (points_needed - 5 * num_major);
19 }
20 }
21
22 // Turn が入玉できる確率を返す
23 template <osl::Player Turn>
24 double osl::enter_king::SimplePredictor::getProbability(const osl::state::NumEffectState& state) {
25 // 確率計算用のパラメータ
26 // 最後にexp() で確率に戻す
27 static const double normal_penalty = log(0.9);
28 static const double strong_penalty = log(0.8);
29 static const double weak_penalty = log(0.95);
30 static const double lower_bound = log(0.05);
31 double prob = 0.0;
32
33 const osl::Square myKingSquare = state.kingSquare<Turn>();
34 const int my_king_y = myKingSquare.y();
35 const int enemyCampMin = (Turn==osl::BLACK) ? 1 : 7;
36 const int enemyCampMax = enemyCampMin + 2;
37 const int winning_threshold = (Turn==osl::BLACK) ?
38 winning_threshold_black : winning_threshold_white;
39
40 // 玉のy軸を見て入玉からの距離でペナルティをかける
41 if (my_king_y < enemyCampMin || my_king_y > enemyCampMax) {
42 prob += ((Turn==osl::BLACK)? (my_king_y - enemyCampMax) :
43 (enemyCampMin - my_king_y)) * weak_penalty;
44 }
45
46 // 敵陣にある駒の点数と枚数を計算
47 int num_pieces = 0;
48 int cur_piece_points = osl::enter_king::countPiecePointsInRange<Turn>(state, num_pieces, 1, 9, enemyCampMin, enemyCampMax);
49
50 // 敵陣に駒が少ない時にペナルティ
51 if (num_pieces == 0) prob += 2 * strong_penalty;
52 else if (num_pieces < 3) prob += normal_penalty;
53
54 // 自玉の前方にある敵からの利きの数を計算
55 // 相手の利きが多い時は入玉しにくいのでペナルティ
56 const int opp_effect_kingfront = osl::enter_king::countEffectInFrontOf(state, alt(Turn), myKingSquare, Turn);
57 prob += (opp_effect_kingfront / 4) * strong_penalty;
58
59 // ボーナス
60 // 王の前方に敵からの利きがない, 敵陣に8枚以上の駒がある
61 if (opp_effect_kingfront == 0 && prob < normal_penalty)
62 prob -= normal_penalty;
63 if (num_pieces > 7 && prob < weak_penalty)
64 prob -= weak_penalty;
65
66 if (prob < lower_bound) return 0.0;
67 // 持駒を点数に加える
68 // 入玉に必要な点数以上なら確率を返す
69 cur_piece_points += osl::enter_king::countPiecePointsOnStand(state, Turn);
70 if (cur_piece_points >= winning_threshold)
71 return exp(prob);
72
73 // 不足している点数を補うため、中段や自陣にある駒を敵陣へ持っていく
74 // そのためのコスト(枚数)でペナルティをかける
75 const int direction = (Turn==osl::BLACK)? 1:-1;
76 const int base_y = (Turn==osl::BLACK)? enemyCampMax : enemyCampMin;
77 double pos_penalty = weak_penalty;
78 for (int yi = 1; yi <= 6; yi++) {
79 if (yi == 5) pos_penalty = normal_penalty;
80 int num_pieces_on_row = 0;
81 // ある行の駒の点数と枚数を計算
82 const int points_on_row = osl::enter_king::countPiecePointsOnRow<Turn>(state, num_pieces_on_row, base_y + direction * yi);
83 // 必要な点数に達したら、必要な枚数だけペナルティをかけて確率を返す
84 if (cur_piece_points + points_on_row >= winning_threshold) {
85 prob += calcNumPiecesNeeded(cur_piece_points, points_on_row, num_pieces_on_row, winning_threshold) * pos_penalty;
86 return exp(prob);
87 }
88 // まだ点数が不足しているので、点数や確率を更新して次の行へ
89 cur_piece_points += points_on_row;
90 prob += num_pieces_on_row * pos_penalty;
91 if (prob < lower_bound) return 0.0;
92 }
93 // 駒の点数が足りないので0.0 を返す
94 // 敵陣に駒があれば補えるかもしれない
95 return 0.0;
96 }
97 double osl::enter_king::SimplePredictor::getProbability(const osl::state::NumEffectState& state, const osl::Player Turn) {
98 if (Turn == osl::BLACK)
99 return getProbability<osl::BLACK>(state);
100 else
101 return getProbability<osl::WHITE>(state);
102 }
103
104 // Turn が入玉できる確率を返す
105 // 宣言法への対応
106 template <osl::Player Turn>
107 double osl::enter_king::SimplePredictor::getProbability27(const osl::state::NumEffectState& state) {
108 // 確率計算用のパラメータ
109 // 最後にexp() で確率に戻す
110 static const double normal_penalty = log(0.9);
111 static const double strong_penalty = log(0.8);
112 static const double weak_penalty = log(0.95);
113 static const double lower_bound = log(0.05);
114 double prob = 0.0;
115
116 const osl::Square myKingSquare = state.kingSquare<Turn>();
117 const int my_king_y = myKingSquare.y();
118 const int enemyCampMin = (Turn==osl::BLACK) ? 1 : 7;
119 const int enemyCampMax = enemyCampMin + 2;
120 const int winning_threshold = (Turn==osl::BLACK) ?
121 winning_threshold_black_27 : winning_threshold_white_27;
122
123 // 玉のy軸を見て入玉からの距離でペナルティをかける
124 if (my_king_y < enemyCampMin || my_king_y > enemyCampMax) {
125 const int dist = (Turn==osl::BLACK)? (my_king_y - enemyCampMax) : (enemyCampMin - my_king_y);
126 prob += dist * normal_penalty;
127 }
128
129 // 敵陣にある駒の点数と枚数を計算 (王は除外)
130 int num_pieces = 0;
131 int cur_piece_points = osl::enter_king::countPiecePointsInRange<Turn>(state, num_pieces, 1, 9, enemyCampMin, enemyCampMax);
132
133 // 敵陣に駒が少ない時にペナルティ
134 // 宣言法では敵陣に王以外に10枚の駒が必要
135 if (num_pieces == 0) prob += 2 * strong_penalty;
136 else if (num_pieces < 10)
137 prob += ((12 - num_pieces) / 3) * normal_penalty;
138
139 // 自玉の前方にある敵からの利きの数を計算
140 // 相手の利きが多い時は入玉しにくいのでペナルティ
141 const int opp_effect_kingfront = osl::enter_king::countEffectInFrontOf(state, alt(Turn), myKingSquare, Turn);
142 prob += (opp_effect_kingfront / 4) * strong_penalty;
143
144 // ボーナス
145 // 王の前方に敵からの利きがない
146 if (opp_effect_kingfront == 0 && prob < normal_penalty)
147 prob -= normal_penalty;
148
149 if (prob < lower_bound) return 0.0;
150 // 持駒を点数に加える
151 // 入玉に必要な点数以上なら確率を返す
152 cur_piece_points += osl::enter_king::countPiecePointsOnStand(state, Turn);
153 if (cur_piece_points >= winning_threshold)
154 return exp(prob);
155
156 // 不足している点数を補うため、中段や自陣にある駒を敵陣へ持っていく
157 // そのためのコスト(枚数)でペナルティをかける
158 const int direction = (Turn==osl::BLACK)? 1:-1;
159 const int base_y = (Turn==osl::BLACK)? enemyCampMax : enemyCampMin;
160 double pos_penalty = weak_penalty;
161 for (int yi = 1; yi <= 6; yi++) {
162 if (yi == 5) pos_penalty = normal_penalty;
163 int num_pieces_on_row = 0;
164 // ある行の駒の点数と枚数を計算
165 const int points_on_row = osl::enter_king::countPiecePointsOnRow<Turn>(state, num_pieces_on_row, base_y + direction * yi);
166 // 必要な点数に達したら、必要な枚数だけペナルティをかけて確率を返す
167 if (cur_piece_points + points_on_row >= winning_threshold) {
168 prob += calcNumPiecesNeeded(cur_piece_points, points_on_row, num_pieces_on_row, winning_threshold) * pos_penalty;
169 return exp(prob);
170 }
171 // まだ点数が不足しているので、点数や確率を更新して次の行へ
172 cur_piece_points += points_on_row;
173 prob += num_pieces_on_row * pos_penalty;
174 if (prob < lower_bound) return 0.0;
175 }
176 // 自分の駒だけでは点数が足りない
177 // 5点以内なら取れるかもしれない
178 if (winning_threshold - cur_piece_points <= 5)
179 prob += (winning_threshold - cur_piece_points) * strong_penalty;
180 else return 0.0;
181 if (prob < lower_bound) return 0.0;
182 return exp(prob);
183 }
184 double osl::enter_king::SimplePredictor::getProbability27(const osl::state::NumEffectState& state, const osl::Player Turn) {
185 if (Turn == osl::BLACK)
186 return getProbability27<osl::BLACK>(state);
187 else
188 return getProbability27<osl::WHITE>(state);
189 }
190
191 // 入玉の予測を行う関数. 確率がthreshold を超えていたらtrue そうでないならfalse
192 template <osl::Player Turn>
193 bool osl::enter_king::SimplePredictor::predict(const osl::state::NumEffectState& state, double threshold) {
194 if (getProbability<Turn>(state) > threshold)
195 return true;
196 return false;
197 }
198 bool osl::enter_king::SimplePredictor::predict(const osl::state::NumEffectState& state,
199 osl::Player Turn, double threshold) {
200 if (getProbability(state, Turn) > threshold)
201 return true;
202 return false;
203 }
204 // 入玉の予測を行う関数. 確率がthreshold を超えていたらtrue そうでないならfalse
205 template <osl::Player Turn>
206 bool osl::enter_king::SimplePredictor::predict27(const osl::state::NumEffectState& state, double threshold) {
207 if (getProbability27<Turn>(state) > threshold)
208 return true;
209 return false;
210 }
211 bool osl::enter_king::SimplePredictor::predict27(const osl::state::NumEffectState& state,
212 osl::Player Turn, double threshold) {
213 if (getProbability27(state, Turn) > threshold)
214 return true;
215 return false;
216 }
217
218 namespace osl {
219 namespace enter_king {
220 template
221 double SimplePredictor::getProbability<osl::BLACK>
222 (const osl::state::NumEffectState& state);
223 template
224 double SimplePredictor::getProbability<osl::WHITE>
225 (const osl::state::NumEffectState& state);
226
227 template
228 double SimplePredictor::getProbability27<osl::BLACK>
229 (const osl::state::NumEffectState& state);
230 template
231 double SimplePredictor::getProbability27<osl::WHITE>
232 (const osl::state::NumEffectState& state);
233
234 template
235 bool SimplePredictor::predict<osl::BLACK>
236 (const osl::state::NumEffectState& state, double threshold);
237 template
238 bool SimplePredictor::predict<osl::WHITE>
239 (const osl::state::NumEffectState& state, double threshold);
240
241 template
242 bool SimplePredictor::predict27<osl::BLACK>
243 (const osl::state::NumEffectState& state, double threshold);
244 template
245 bool SimplePredictor::predict27<osl::WHITE>
246 (const osl::state::NumEffectState& state, double threshold);
247 }
248 }