All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
simplePredictor.cc
Go to the documentation of this file.
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>
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) ?
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 }
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>
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) ?
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 }
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>
194  if (getProbability<Turn>(state) > threshold)
195  return true;
196  return false;
197 }
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>
207  if (getProbability27<Turn>(state) > threshold)
208  return true;
209  return false;
210 }
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 }