My Project
move_probability/feature.h
Go to the documentation of this file.
1/* feature.h
2 */
3#ifndef OSL_MOVE_PROBABILITY_FEATURE_H
4#define OSL_MOVE_PROBABILITY_FEATURE_H
5
10#include <string>
11
12namespace osl
13{
14 namespace move_probability
15 {
16 class Feature
17 {
18 std::string my_name;
19 int dim;
20 public:
21 Feature(std::string n, size_t d) : my_name(n), dim(d)
22 {
23 assert(dim > 0);
24 }
25 virtual ~Feature();
26 std::string name() const { return my_name; }
27 virtual double match(const StateInfo&, const MoveInfo&, int offset, const double *) const=0;
28 size_t dimension() const { return dim; }
29
30 static int classifyEffect9(const NumEffectState& state, Player player, Square to)
31 {
32 const int a = std::min(2, state.countEffect(player, to));
33 int d = std::min(2,state.countEffect(alt(player), to));
34 if (a>d)
35 d += AdditionalEffect::hasEffect(state, to, alt(player));
36 return a*3 + d;
37 }
38 };
39
40 class CheckFeature : public Feature
41 {
42 public:
43 enum { CHECK_CLASS = 4, RELATIVE_Y_CLASS = 3 };
48 static int checkIndex(const MoveInfo& move)
49 {
50 if (move.open_check)
51 return 3;
52 return (move.see > 0) ? 0 : ((move.see == 0) ? 1 : 2);
53 }
54 static int sign(const NumEffectState& state, Move move,
55 Player player)
56 {
57 const Square king = state.kingSquare(alt(player));
58 int ry = (move.to().y() - king.y())*osl::sign(player);
59 if (ry == 0) return 0;
60 return ry > 0 ? 1 : -1;
61 }
62 double match(const StateInfo& state, const MoveInfo& move, int offset, const double *w) const
63 {
64 if (! move.check && ! move.open_check)
65 return 0;
66 const Player player = move.player;
67 int index = sign(*state.state, move.move, player)+1;
68 index = (index*2 + move.move.isDrop())*PTYPE_SIZE
69 + move.move.ptype();
70 index = index*CHECK_CLASS + checkIndex(move);
71 return w[offset+index];
72 }
73 };
74 class TakeBackFeature : public Feature
75 {
76 public:
77 TakeBackFeature() : Feature("TakeBack", 3)
78 {
79 }
80 double match(const StateInfo& state, const MoveInfo& move, int offset, const double *w) const
81 {
82 if (! state.history->hasLastMove()
83 || state.history->lastMove().to() != move.move.to())
84 return 0;
85 int match = 2;
86 if (move.see >= 0) {
87 --match;
88 if (state.history->hasLastMove(2)
89 && state.history->lastMove(2).to() == move.move.to())
90 --match;
91 }
92 return w[offset + match];
93 }
94 };
95 class SeeFeature : public Feature
96 {
97 public:
98 enum { SeeClass = 23, YClass = 3, ProgressClass = 8 };
100 {
101 }
102 static int seeIndex(int see)
103 {
104 int index = see / 128;
105 if (see > 0) {
106 index = std::min(10, index);
107 index += 12;
108 } else if (see == 0) {
109 index += 11;
110 } else {
111 index += 10;
112 index = std::max(0, index);
113 }
114 return index;
115 }
116 double match(const StateInfo& state, const MoveInfo& move, int offset, const double *w) const
117 {
118 const int see_index = seeIndex(move.see);
119 const Player player = move.player;
120 const Square to = move.move.to();
121 const int promote_index = to.canPromote(player)
122 ? 1 : (to.canPromote(alt(player)) ? 2 : 0);
123 double sum = w[offset+see_index+promote_index*SeeClass];
124 int progress_index = YClass + state.progress8();
125 sum += w[offset+see_index+progress_index*SeeClass];
126 return sum;
127 }
128 };
129
130 class CapturePtype : public Feature
131 {
132 public:
133 CapturePtype() : Feature("CapturePtype", PTYPE_SIZE*PTYPE_SIZE*2*3)
134 {
135 }
136 double match(const StateInfo& state, const MoveInfo& move, int offset, const double *w) const
137 {
138 const Ptype captured = move.move.capturePtype();
139 const Player player = move.player;
140 int index = (move.move.ptype())*PTYPE_SIZE + captured;
141 static_assert(PTYPE_EDGE == 1, "");
142 if (captured != PTYPE_EMPTY
143 && captured == state.threatened[alt(player)].ptype())
144 ++index;
145 if (move.see > 0)
146 index += PTYPE_SIZE*PTYPE_SIZE;
147 if (captured != PTYPE_EMPTY)
148 index += std::min(2, state.state->countPiecesOnStand(player, unpromote(captured)))
150 return w[offset+index];
151 }
152 };
153
155 {
156 public:
157 ContinueCapture() : Feature("ContinueCapture", 1) {}
158 double match(const StateInfo& state, const MoveInfo& move, int offset, const double *w) const
159 {
160 if (move.move.capturePtype() == PTYPE_EMPTY
161 || ! state.history->hasLastMove(2)
162 || state.history->lastMove(2).to() != move.move.from())
163 return 0;
164 return w[offset];
165 }
166 };
167
169 class DropCaptured : public Feature
170 {
171 public:
173 double match(const StateInfo& state, const MoveInfo& move, int offset, const double *w) const
174 {
175 if (! move.move.isDrop()
176 || ! state.history->hasLastMove(2)
177 || ! state.history->lastMove(2).isNormal()
178 || state.history->lastMove(2).capturePtype() != move.move.ptype())
179 return 0.0;
180 const size_t index = move.move.ptype() - PTYPE_BASIC_MIN;
181 assert(index < dimension());
182 return w[index + offset];
183 }
184 };
185
186 class SquareY : public Feature
187 {
188 public:
189 // PTYPE_SIZE, to [1,9], fromto [-3,3], drop|promote, progress8
190 enum {
191 DIM = 9*PTYPE_SIZE*16
192 };
193 SquareY() : Feature("SquareY", DIM)
194 {
195 }
196 static int fromTo(Square to, Square from) // [-3,3]
197 {
198 return std::max(-3, std::min(to.y() - from.y(), 3));
199 }
200 double match(const StateInfo& state, const MoveInfo& info, int offset, const double *w) const
201 {
202 const Move move = info.move;
203 const Player P = info.player;
204 const Square to = move.to().squareForBlack(P);
205 size_t index = ((to.y()-1)*PTYPE_SIZE + move.ptype())*16;
206 assert(index+16 <= dimension());
207 const int from_to = move.isDrop() ? 0
208 : fromTo(to, move.from().squareForBlack(P));
209 double sum = w[offset + index + from_to + 3];
210 if (move.isDrop() || move.isPromotion())
211 sum += w[offset + index + 7];
212 sum += w[offset + index + state.progress8()+8];
213 return sum;
214 }
215 };
216
217 class SquareX : public Feature
218 {
219 public:
220 // PTYPE_SIZE, to [1,5], fromto [-3,3], drop|promote, progress8
221 SquareX() : Feature("SquareX", 5*PTYPE_SIZE*16)
222 {
223 }
224 static int fromTo(Square to, Square from) // [-3,3]
225 {
226 return std::max(-3, std::min(to.x() - from.x(), 3));
227 }
228 double match(const StateInfo& state, const MoveInfo& info, int offset, const double *w) const
229 {
230 const Move move = info.move;
231 int to = move.to().x();
232 int from_to = move.isDrop() ? 0 : fromTo(move.to(), move.from());
233 if (to > 5) {
234 to = 10 - to;
235 from_to = -from_to;
236 }
237 size_t index = ((to-1)*PTYPE_SIZE + move.ptype())*16;
238 assert(index+16 <= dimension());
239 double sum = w[offset + index + from_to + 3];
240 if (move.isDrop() || move.isPromotion())
241 sum += w[offset + index + 7];
242 sum += w[offset + index + state.progress8()+8];
243 return sum;
244 }
245 };
246
247 class KingRelativeY : public Feature
248 {
249 public:
250 // PTYPE_SIZE, to [-8,8], fromto [-3,3], drop|promote, progress8
251 enum { ONE_DIM = 17*PTYPE_SIZE*16 };
252 KingRelativeY() : Feature("KingRelativeY", ONE_DIM*2)
253 {
254 }
255 double match(const StateInfo& state, const MoveInfo& info, int offset, const double *w) const
256 {
257 const Move move = info.move;
258 const Player P = info.player;
259 const Ptype ptype = move.ptype();
260
261 const Square to = move.to().squareForBlack(P);
262 const Square my_king = state.state->kingSquare(P).squareForBlack(P);
263 const Square op_king = state.state->kingSquare(alt(P)).squareForBlack(P);
264 const int from_to = move.isDrop() ? 0
265 : SquareY::fromTo(to, move.from().squareForBlack(P));
266
267 size_t index = ((to.y()-my_king.y()+8)*PTYPE_SIZE + ptype)*16;
268 assert(index+16 <= ONE_DIM);
269 double sum = w[offset + index + from_to + 3];
270 if (move.isDrop() || move.isPromotion())
271 sum += w[offset + index + 7];
272 sum += w[offset + index + state.progress8()+8];
273
274 index = ((to.y()-op_king.y()+8)*PTYPE_SIZE + ptype)*16;
275 assert(index+16 <= ONE_DIM);
276 sum += w[offset + ONE_DIM + index + from_to + 3];
277 if (move.isDrop() || move.isPromotion())
278 sum += w[offset + ONE_DIM + index + 7];
279 sum += w[offset + ONE_DIM + index + state.progress8()+8];
280 return sum;
281 }
282 };
283 class KingRelativeX : public Feature
284 {
285 public:
286 // PTYPE_SIZE, to [0,8], fromto [-3,3], drop|promote, progress8
287 enum { ONE_DIM = 9*PTYPE_SIZE*16 };
288 KingRelativeX() : Feature("KingRelativeX", ONE_DIM*2)
289 {
290 }
291 double match(const StateInfo& state, const MoveInfo& info, int offset, const double *w) const
292 {
293 const Move move = info.move;
294 const Player P = info.player;
295 const Ptype ptype = move.ptype();
296
297 const Square to = move.to();
298 const Square my_king = state.state->kingSquare(P);
299 const Square op_king = state.state->kingSquare(alt(P));
300 const int from_to = move.isDrop() ? 0
301 : SquareY::fromTo(to, move.from());
302 int dx = to.x() - my_king.x(), fx = from_to;
303 if (dx < 0) {
304 dx = -dx;
305 fx = -fx;
306 }
307 size_t index = (dx*PTYPE_SIZE + ptype)*16;
308 assert(index+16 <= ONE_DIM);
309 double sum = w[offset + index + fx + 3];
310 if (move.isDrop() || move.isPromotion())
311 sum += w[offset + index + 7];
312 sum += w[offset + index + state.progress8()+8];
313
314 dx = to.x() - op_king.x(), fx = from_to;
315 if (dx < 0) {
316 dx = -dx;
317 fx = -fx;
318 }
319 index = (dx*PTYPE_SIZE + ptype)*16;
320 assert(index+16 <= ONE_DIM);
321 sum += w[offset + ONE_DIM + index + fx + 3];
322 if (move.isDrop() || move.isPromotion())
323 sum += w[offset + ONE_DIM + index + 7];
324 sum += w[offset + ONE_DIM + index + state.progress8()+8];
325 return sum;
326 }
327 };
328
329 class FromEffect : public Feature
330 {
331 public:
333 {
334 }
335 double match(const StateInfo& state_info, const MoveInfo& info, int offset, const double *w) const
336 {
337 const Move move = info.move;
338 if (move.isDrop())
339 return 0;
340 const NumEffectState& state = *state_info.state;
341 const Ptype me = move.oldPtype();
342 const Ptype support = state.findCheapAttack(info.player, move.from()).ptype();
343 const Ptype attack = state.findCheapAttack(alt(info.player), move.from()).ptype();
344 const size_t index = (((me * PTYPE_SIZE) + support) * PTYPE_SIZE) + attack;
345 assert(index < dimension());
346 return w[index + offset];
347 }
348 };
349
350 class ToEffect : public Feature
351 {
352 public:
356 static const Piece find(const NumEffectState& state,
357 Square to, const PieceMask& remove,
358 Player player)
359 {
360 assert(to.isOnBoard());
361 PieceMask pieces = state.piecesOnBoard(player)
362 & state.effectSetAt(to);
363 pieces &= ~remove;
364 return state.selectCheapPiece(pieces);
365 }
366 static void supportAttack(const NumEffectState& state,
367 Square to,
368 const PieceMask& my_pin,
369 const PieceMask& op_pin,
370 Player turn,
371 std::pair<Ptype,Ptype>& out)
372 {
373 out.first = find(state, to, my_pin, turn).ptype(); // support
374 out.second = find(state, to, op_pin, alt(turn)).ptype(); // attack
375 }
376 static void supportAttack(const StateInfo& info, Square to, Move move,
377 std::pair<Ptype,Ptype>& out)
378 {
379 const Player turn = info.state->turn();
380 if (move.isDrop())
381 return supportAttack(*(info.state), to, info.pin[turn],
382 info.pin[alt(turn)], turn, out);
383 PieceMask my_pin = info.pin[turn];
384 my_pin.set(info.state->pieceAt(move.from()).number());
385 supportAttack(*(info.state), to, my_pin, info.pin[alt(turn)],
386 turn, out);
387 }
388 static size_t supportAttack(const StateInfo& info, Square to, Move move)
389 {
390 std::pair<Ptype,Ptype> pair;
391 supportAttack(info, to, move, pair);
392 return pair.first * PTYPE_SIZE + pair.second;
393 }
394 double match(const StateInfo& state, const MoveInfo& info, int offset, const double *w) const
395 {
396 const Move move = info.move;
397 const Ptype me = move.ptype(), captured = move.capturePtype();
398 const size_t position_index = supportAttack(state, move.to(), move);
399 const size_t index = ((me * PTYPE_SIZE) + captured)
400 * PTYPE_SIZE * PTYPE_SIZE + position_index;
401 assert(index < dimension());
402 return w[index + offset];
403 }
404 };
405
406 class FromEffectLong : public Feature
407 {
408 public:
409 FromEffectLong() : Feature("FromEffectLong", PTYPE_SIZE*8*8)
410 {
411 }
412 double match(const StateInfo& state_info, const MoveInfo& info, int offset, const double *w) const
413 {
414 const Move move = info.move;
415 if (move.isDrop())
416 return 0;
417 const NumEffectState& state = *state_info.state;
418 const Ptype ptype = move.oldPtype();
419 const CArray<bool,3> me = {{
420 state.longEffectAt<LANCE>(move.from(), info.player).any(),
421 state.longEffectAt<BISHOP>(move.from(), info.player).any(),
422 state.longEffectAt<ROOK>(move.from(), info.player).any(),
423 }};
424 const CArray<bool,3> op = {{
425 state.longEffectAt<LANCE>(move.from(), alt(info.player)).any(),
426 state.longEffectAt<BISHOP>(move.from(), alt(info.player)).any(),
427 state.longEffectAt<ROOK>(move.from(), alt(info.player)).any(),
428 }};
429 size_t index = ptype;
430 for (int i=0; i<3; ++i) {
431 index *= 2; index += me[i];
432 index *= 2; index += op[i];
433 }
434 assert(index < dimension());
435 return w[index + offset];
436 }
437 };
438
439 class ToEffectLong : public Feature
440 {
441 public:
442 ToEffectLong() : Feature("ToEffectLong", PTYPE_SIZE*8*8)
443 {
444 }
445 double match(const StateInfo& state_info, const MoveInfo& info, int offset, const double *w) const
446 {
447 const Move move = info.move;
448 const NumEffectState& state = *state_info.state;
449 const Ptype ptype = move.oldPtype();
450 NumBitmapEffect effect=state.effectSetAt(move.to());
451 if (! move.isDrop())
452 effect.reset(state.pieceOnBoard(move.from()).number()+8);
453 const CArray<mask_t,3> pieces = {{
454 effect.selectLong<LANCE>() >> 8,
455 effect.selectLong<BISHOP>() >> 8,
456 effect.selectLong<ROOK>() >> 8
457 }};
458 size_t index = ptype;
459 for (int i=0; i<3; ++i) {
460 index *= 2;
461 index += (pieces[i] & state.piecesOnBoard(info.player).getMask(1)).any();
462 index *= 2;
463 index += (pieces[i] & state.piecesOnBoard(alt(info.player)).getMask(1)).any();
464 }
465 assert(index < dimension());
466 return w[index + offset];
467 }
468 };
469
470 class PatternCommon : public Feature
471 {
472 public:
473 enum {
486 };
487 PatternCommon(const std::string& name, int dim) : Feature(name, dim)
488 {
489 }
490 double addOne(const StateInfo& state, int offset,
491 const double *w, Square position) const
492 {
493 if (! position.isOnBoardRegion() || state.state->pieceAt(position).isEdge()) {
494 size_t basic = ptypeOIndex(PTYPEO_EDGE) *SquareDim;
495 return w[offset + basic];
496 }
497 const StateInfo::pattern_square_t& cache
498 = state.pattern_cache[position.index()];
499 double sum = 0.0;
500 for (size_t i=0; i<cache.size() && cache[i] >= 0; ++i)
501 sum += w[offset + cache[i]];
502 return sum;
503 }
504 static void updateCache(StateInfo& info);
505 private:
506 static void updateCacheOne(Square target, StateInfo& info);
507 };
508
509 template<bool TestPromotable>
511 {
513 public:
514 enum {
515 PromotionSize = TestPromotable ? 3 : 1,
517 };
518 PatternBase(int x, int y)
519 : PatternCommon(name(x,y), DIM), dx(x), black_dy(y)
520 {
521 }
522 double match(const StateInfo& state, const MoveInfo& info, int offset, const double *w) const
523 {
524 const Move move = info.move;
525 const Ptype ptype = move.ptype();
526 int basic = ptype*PatternCacheSize;
527 int basic_from = (move.isPromotion() ? PTYPE_EDGE : PTYPE_EMPTY)
529 const Square to = move.to();
530 if (TestPromotable && to.canPromote(info.player))
531 offset += OneDim;
532 else if (TestPromotable && to.canPromote(alt(info.player)))
533 offset += 2*OneDim;
534 int dy = info.player == BLACK ? black_dy : -black_dy;
535 Square target = to + Offset(dx, dy);
536 double sum = 0.0;
537 if (move.from() != target)
538 sum += addOne(state, offset+basic, w, target);
539 else // move from here
540 sum += addOne(state, offset+basic_from, w, target);
541 if (dx == 0)
542 return sum;
543 target = to + Offset(-dx, dy);
544 if (move.from() != target)
545 sum += addOne(state, offset+basic, w, target);
546 else
547 sum += addOne(state, offset+basic_from, w, target);
548 return sum;
549 }
550 static std::string name(int x, int y)
551 {
552 return std::string("Pattern")
553 + (TestPromotable ? "P" : "")
554 + "X" + (char)('2'+x) + "Y"+(char)('2'+y);
555 }
556 };
557
560
562 {
563 public:
564 MoveFromOpposingSliders() : Feature("MoveFromOpposingSliders", 36*PTYPE_SIZE)
565 {
566 }
567 static int longPtype(const NumEffectState& state, Square position, Player player)
568 {
569 const int offset = PtypeFuns<LANCE>::indexNum*32;
570 mask_t p = state.longEffectAt<LANCE>(position, player);
571 if (p.any())
572 return state.hasEffectAt(player, state.pieceOf(p.takeOneBit()+offset).square());
573 p = state.longEffectAt<BISHOP>(position, player);
574 if (p.any())
575 return 2 + state.hasEffectAt(player, state.pieceOf(p.takeOneBit()+offset).square());
576 p = state.longEffectAt<ROOK>(position, player);
577 assert(p.any());
578 return 4 + state.hasEffectAt(player, state.pieceOf(p.takeOneBit()+offset).square());
579 }
580 double match(const StateInfo& state, const MoveInfo& move, int offset, const double *w) const
581 {
582 const Square from = move.move.from();
583 if (from.isPieceStand()
584 || ! state.pinByOpposingSliders(state.state->pieceOnBoard(from)))
585 return 0.0;
586 const int me = longPtype(*state.state, from, move.player);
587 const int op = longPtype(*state.state, from, alt(move.player));
588 return w[offset + (me*6+op)*PTYPE_SIZE+move.move.ptype()];
589 }
590 };
592 {
593 public:
594 AttackFromOpposingSliders() : Feature("AttackFromOpposingSliders", PTYPE_SIZE*PTYPE_SIZE*2)
595 {
596 }
597 double match(const StateInfo& state, const MoveInfo& info, int offset, const double *w) const
598 {
599 const Move move = info.move;
600 const Piece attack = state.state->findCheapAttack(alt(info.player), move.to());
601 if (! state.pinByOpposingSliders(attack))
602 return 0.0;
603 if (state.state->countEffect(alt(info.player), move.to()) == 1)
604 offset += PTYPE_SIZE*PTYPE_SIZE;
605 double sum = w[offset + PTYPE_EMPTY*PTYPE_SIZE+attack.ptype()]
606 + w[offset + move.ptype()*PTYPE_SIZE+PTYPE_EMPTY]
607 + w[offset + move.ptype()*PTYPE_SIZE+attack.ptype()];
608 if (info.see < 0)
609 sum += w[offset + PTYPE_EMPTY*PTYPE_SIZE+PTYPE_EMPTY]*info.see/1024.0;
610 return sum;
611 }
612 };
614 {
615 public:
616 AttackToOpposingSliders() : Feature("AttackToOpposingSliders", PTYPE_SIZE*PTYPE_SIZE*2)
617 {
618 }
619 double match(const StateInfo& state, const MoveInfo& info, int offset, const double *w) const
620 {
621 const Move move = info.move;
622 double sum = 0.0;
623 for (Piece piece: state.pin_by_opposing_sliders) {
624 if (! state.state->hasEffectIf(move.ptypeO(), move.to(),
625 piece.square()))
626 continue;
627 int base = (piece.owner() == info.player) ? PTYPE_SIZE*PTYPE_SIZE : 0;
628 sum += w[offset + base + PTYPE_EMPTY*PTYPE_SIZE+piece.ptype()]
629 + w[offset + base + move.ptype()*PTYPE_SIZE+PTYPE_EMPTY]
630 + w[offset + base + move.ptype()*PTYPE_SIZE+piece.ptype()];
631 if (info.see < 0)
632 sum += w[offset + base + PTYPE_EMPTY*PTYPE_SIZE+PTYPE_EMPTY]*info.see/1024.0;
633 }
634 return sum;
635 }
636 };
637 class PawnAttack : public Feature
638 {
639 public:
640 enum {
645 DIM = PawnSize*2
646 };
647 PawnAttack() : Feature("PawnAttack", DIM)
648 {
649 }
650 std::pair<int,int> squareStatus(const NumEffectState& state, Player player, Square to, Square& front) const
651 {
652 int u = 0, uu = 0;
653 const int dy = (player == BLACK) ? -1 : 1;
654 Square position = to + Offset(0, dy);
655 front = position;
656 Piece piece = state.pieceAt(position);
657 if (piece.isPiece())
658 u = piece.ptype() + ((piece.owner() == player) ? PTYPE_SIZE : 0);
659 assert(! piece.isEdge()); // pawn move
660 piece = state.pieceAt(position + Offset(0, dy));
661 if (piece.isPiece())
662 uu = piece.ptype() + ((piece.owner() == player) ? PTYPE_SIZE : 0);
663 return std::make_pair(u, uu);
664 }
665 double matchPtype(const StateInfo& state, const MoveInfo& move, int offset, const double *w) const
666 {
667 const Player player = move.player;
668 const Square to = move.move.to();
669
670 Square front;
671 const std::pair<int,int> u = squareStatus(*state.state, player, to, front);
672
673 int promotion = 0;
674 if (front.canPromote(player))
675 promotion = 1;
676 else if (front.canPromote(alt(player)))
677 promotion = 2;
678 offset += BasicSize*promotion;
679
680 bool pawn_drop = move.move.isDrop();
681 const int index0 = (u.first*PTYPE_SIZE*2+u.second)*2 + pawn_drop;
682 double sum = w[offset + index0];
683
684 const int effect = classifyEffect9(*state.state, player, front);
685 const int index1 = u.first*8 + move.move.to().squareForBlack(player).y()-2;
686 sum += w[offset + index1*9+effect];
687 return sum;
688 }
689 double match(const StateInfo& state, const MoveInfo& move, int offset, const double *w) const
690 {
691 if (move.move.ptype() == PAWN)
692 return matchPtype(state, move, offset, w);
693 if (move.move.ptype() == LANCE
694 && state.state->canDropPawnTo(move.player, move.move.to().x()))
695 return matchPtype(state, move, offset+PawnSize, w);
696 return 0.0;
697 }
698 };
699
700 class BlockLong : public Feature
701 {
702 public:
703 enum {
706 OptionSize = 8, // King8, HasSupport, Promotable, Shadowing,...
709 };
710 BlockLong() : Feature("BlockLong", DIM)
711 {
712 }
713 static int longAttackIndex(osl::PtypeO ptypeo) // [0,7]?
714 {
715 const Ptype ptype = getPtype(ptypeo);
716 int index;
717 if (ptype == LANCE) index = 0;
718 else if (ptype == BISHOP) index = 1;
719 else if (ptype == ROOK) index = 2;
720 else {
721 assert(ptype == PROOK || ptype == PBISHOP);
722 index = 3;
723 }
724 if (getOwner(ptypeo) == WHITE) index += 4;
725 return index;
726 }
727 static double addPiece(const StateInfo& state, Piece piece,
728 Square to, const double *w, int offset)
729 {
730 assert(state.state->hasEffectByPiece(piece, to));
731 const Direction d
734 cache = state.long_attack_cache[piece.number()][longToShort(d)];
735 double sum = 0.0;
736 for (int index: cache) {
737 assert(index < LongAttackSize);
738 sum += w[index+offset];
739 }
740 return sum;
741 }
742 static int ptypeSupport(Ptype moved, bool has_support)
743 {
744 return (moved*2 + has_support) * LongAttackSize;
745 }
746 static double findAll(const StateInfo& state, Player P,
747 Square target, const double *w, int offset)
748 {
749 mask_t m = state.state->longEffectAt(target, P);
750 double sum = 0.0;
751 while (m.any()) {
752 const Piece piece = state.state->pieceOf
753 (m.takeOneBit() +PtypeFuns<LANCE>::indexNum*32);
754 sum += addPiece(state, piece, target, w, offset);
755 }
756 m = state.state->longEffectAt(target, alt(P));
757 while (m.any()) {
758 const Piece piece = state.state->pieceOf
759 (m.takeOneBit()+PtypeFuns<LANCE>::indexNum*32);
760 sum += addPiece(state, piece, target, w, offset);
761 }
762 return sum;
763 }
764 static double findAll(const StateInfo& state, Move move, const double *w, int offset=0)
765 {
766 const Player P = move.player();
767 Square target = move.to();
768 int a = state.state->countEffect(P, target);
769 offset += ptypeSupport(move.ptype(), a+move.isDrop()>1);
770 return findAll(state, P, target, w, offset);
771 }
772 double match(const StateInfo& state, const MoveInfo& move, int offset, const double *w) const
773 {
774 return findAll(state, move.move, w, offset);
775 }
776 static void updateCache(StateInfo&);
777 private:
778 static void makeLongAttackOne(StateInfo& info,
779 Piece piece, Direction d);
780 };
781 class BlockLongFrom : public Feature
782 {
783 public:
784 enum {
786 };
787 BlockLongFrom() : Feature("BlockLongFrom", DIM)
788 {
789 }
790 static double findAll(const StateInfo& state, Move move, const double *w, int offset=0)
791 {
792 const Player P = move.player();
793 Square target = move.from();
794 return BlockLong::findAll(state, P, target, w, offset);
795 }
796 double match(const StateInfo& state, const MoveInfo& move, int offset, const double *w) const
797 {
798 if (move.move.isDrop())
799 return 0;
800 return findAll(state, move.move, w, offset);
801 }
802 };
803 class LongRecapture : public Feature
804 {
805 public:
806 enum {
808 };
809 LongRecapture() : Feature("LongRecapture", DIM)
810 {
811 }
812 double match(const StateInfo& info, const MoveInfo& move, int offset, const double *w) const
813 {
814 if (move.see >= 0)
815 return 0.0;
816 const NumEffectState& state = *info.state;
817 const Square to = move.move.to();
818 int a = state.countEffect(move.player, to)+move.move.isDrop()-1;
819 int d = state.countEffect(alt(move.player), to);
820 if (d == 1
821 || (d == 2 && a > 0
822 && state.hasEffectByPiece(state.kingPiece(alt(move.player)), to))) {
823 double sum = w[offset + (PTYPE_EMPTY)*BlockLong::LongAttackSize]
824 *move.see/1024.0;
825 offset += move.move.ptype() * BlockLong::LongAttackSize;
826 const Piece opponent = state.findCheapAttack(alt(move.player), to);
827 sum += BlockLong::findAll(info, move.player, opponent.square(), w, offset);
828 return sum;
829 }
830 return 0.0;
831 }
832 };
833 class AddEffectLong : public Feature
834 {
835 public:
836 enum {
838 };
839 AddEffectLong() : Feature("AddEffectLong", DIM)
840 {
841 }
842 static double addOne(Direction dir, const StateInfo& state, const MoveInfo& move, int offset, const double *w)
843 {
844 Offset diff = Board_Table.getOffset(move.player, dir);
845 Square to = move.move.to() + diff;
846 if (isLong(dir)) {
847 while (state.state->pieceAt(to).isEmpty())
848 to += diff;
849 }
850 if (! state.state->pieceAt(to).isPiece())
851 return 0.0;
852 return BlockLong::findAll(state, move.player, to, w, offset);
853 }
854 double match(const StateInfo& state, const MoveInfo& move, int offset, const double *w) const
855 {
856 offset += move.move.ptype()*BlockLong::LongAttackSize;
857 unsigned int directions = Ptype_Table.getMoveMask(move.move.ptype());
858 double sum = 0.0;
859 do {
860 Direction d = (Direction)(misc::BitOp::bsf(directions));
861 directions &= directions-1;
862 sum += addOne(d, state, move, offset, w);
863 } while (directions);
864 return sum;
865 }
866 };
867 class LanceAttack : public Feature
868 {
869 public:
870 enum {
872 DIM = PatternCacheSize*(8+4+4+1)
873 };
874 LanceAttack() : Feature("LanceAttack", DIM)
875 {
876 }
877 double match(const StateInfo& state, const MoveInfo& move, int offset, const double *w) const
878 {
879 if (move.move.ptype() != LANCE
880 || (! move.move.isDrop()
881 && move.move.capturePtype() == PTYPE_EMPTY))
882 return 0;
883 const Offset up = Board_Table.getOffset(move.player, U);
884 Square target = move.move.to() + up;
885 while (state.state->pieceAt(target).isEmpty())
886 target += up;
887 if (state.state->pieceAt(target).isOnBoardByOwner(move.player)) {
888 target += up;
889 if (state.state->pieceAt(target).ptype() == LANCE) {
890 while (state.state->pieceAt(target).isEmpty())
891 target += up;
892 }
893 }
894 if (state.state->pieceAt(target).isEdge())
895 target -= up;
896
897 int y = move.move.to().y(), x = move.move.to().x();
898 if (move.player == WHITE)
899 y = 10-y;
900 y -= 2;
901 int dx1 = abs(state.state->kingSquare(move.player).x()-x);
902 int dx2 = abs(state.state->kingSquare(alt(move.player)).x()-x);
903 dx1 = std::min(dx1, 3);
904 dx2 = std::min(dx2, 3);
905 bool pawn = state.state->canDropPawnTo(alt(move.player), x);
906 assert(! state.state->pieceAt(target).isEdge());
907 const StateInfo::pattern_square_t& cache
908 = state.pattern_cache[target.index()];
909 double sum = 0.0;
910 for (size_t i=0; i<cache.size() && cache[i] >= 0; ++i) {
911 sum += w[offset + y*PatternCacheSize + cache[i]];
912 sum += w[offset + (8+dx1)*PatternCacheSize + cache[i]];
913 sum += w[offset + (12+dx1)*PatternCacheSize + cache[i]];
914 if (! pawn)
915 sum += w[offset + 16*PatternCacheSize + cache[i]];
916 }
917 return sum;
918 }
919 };
920 class BishopAttack : public Feature
921 {
922 public:
923 enum {
925 DIM = PatternCacheSize*2 // square:2
926 };
927 BishopAttack() : Feature("BishopAttack", DIM)
928 {
929 }
930 static double addSquare(Square target,
931 const StateInfo& info,
932 int offset, const double *w)
933 {
934 int type = 0;
935 const StateInfo::pattern_square_t& cache
936 = info.pattern_cache[target.index()];
937 double sum = 0.0;
938 for (size_t i=0; i<cache.size() && cache[i] >= 0; ++i) {
939 sum += w[offset + type + cache[i]];
940 }
941 return sum;
942 }
943 template <Direction D,Ptype Type>
944 static
945 double addOne(const StateInfo& info, Square to,
946 int offset, const double *w)
947 {
948 const NumEffectState& state = *info.state;
950 Square target = to + diff;
951 double sum = 0.0;
952 if (state.pieceAt(target).isEdge())
953 return sum;
954 if (state.pieceAt(target).isPiece()
955 && (state.pieceAt(target).ptype() != Type
956 || state.pieceAt(target).owner() != state.turn())) {
957 ; // almost included in direct pattern
958 } else {
959 while (state.pieceAt(target).isEmpty())
960 target += diff;
961 if (state.pieceAt(target).ptype() == Type
962 && state.pieceAt(target).owner() == state.turn()) {
963 // extend additional effect by the same ptype
964 target += diff;
965 while (state.pieceAt(target).isEmpty())
966 target += diff;
967 }
968 if (state.pieceAt(target).isEdge())
969 target -= diff;
970 sum += addSquare(target, info, offset, w);
971 if (! state.pieceAt(target).isPiece())
972 return sum;
973 }
974 // shadowing
975 target += diff;
976 if (state.pieceAt(target).isEdge())
977 return sum;
978 while (state.pieceAt(target).isEmpty())
979 target += diff;
980 if (state.pieceAt(target).isEdge())
981 target -= diff;
982 sum += addSquare(target, info, offset+PatternCacheSize, w);
983 return sum;
984 }
985 double match(const StateInfo& state, const MoveInfo& move, int offset, const double *w) const
986 {
987 if (unpromote(move.move.ptype()) != BISHOP)
988 return 0;
989 double sum = 0.0;
990 sum += addOne<UR,BISHOP>(state, move.move.to(), offset, w);
991 sum += addOne<UL,BISHOP>(state, move.move.to(), offset, w);
992 sum += addOne<DR,BISHOP>(state, move.move.to(), offset, w);
993 sum += addOne<DL,BISHOP>(state, move.move.to(), offset, w);
994 return sum;
995 }
996 };
997 class RookAttack : public Feature
998 {
999 public:
1000 enum {
1002 DIM = DirectionSize*3
1004 RookAttack() : Feature("RookAttack", DIM)
1005 {
1006 }
1007 double match(const StateInfo& state, const MoveInfo& move, int offset, const double *w) const
1008 {
1009 if (unpromote(move.move.ptype()) != ROOK)
1010 return 0;
1011 const Square to = move.move.to();
1012 double sum = 0.0;
1013 sum += BishopAttack::addOne<R,ROOK>(state, to, offset, w);
1014 sum += BishopAttack::addOne<L,ROOK>(state, to, offset, w);
1015 const bool pawn_drop = state.state->canDropPawnTo(alt(move.player), to.x());
1016 const int scale = pawn_drop ? 1 : 2;
1017 sum += BishopAttack::addOne<U,ROOK>(state, to, offset+DirectionSize*scale, w);
1018 sum += BishopAttack::addOne<D,ROOK>(state, to, offset+DirectionSize*scale, w);
1019 return sum;
1020 }
1021 };
1023 {
1024 public:
1025 enum {
1035 BreakThreatmate() : Feature("BreakThreatmate", DIM)
1036 {
1037 }
1038 static bool isKingMove(Move move)
1039 {
1040 return move.ptype() == KING;
1041 }
1042 static bool isOpeningKingRoad(Move move, Square king)
1043 {
1044 return ! move.isDrop()
1045 && move.from().isNeighboring8(king);
1046 }
1047 static bool isDefendingThreatmate(Move move, Move threatmate,
1048 const NumEffectState& state)
1049 {
1050 if (move.to() == threatmate.to()
1051 || state.hasEffectIf(move.ptypeO(), move.to(),
1052 threatmate.to()))
1053 return true;
1054 if (threatmate.isDrop())
1055 return false;
1056 Offset32 offset32=Offset32(threatmate.from(),move.to());
1057 EffectContent effect=Ptype_Table.getEffect(move.ptypeO(),offset32);
1058 if (! effect.hasEffect())
1059 return false;
1060 if (effect.offset() == threatmate.to()-threatmate.from())
1061 return state.isEmptyBetween(threatmate.from(), move.to());
1062 return false;
1063 }
1064 static bool isDefendingKing8(Move move, Square king,
1065 const NumEffectState& state)
1066 {
1068 (state, move.ptypeO(), move.to(), king))
1069 return true;
1070 mask_t m = state.longEffectAt(move.to(), alt(state.turn()));
1071 while (m.any()) {
1072 const Piece piece = state.pieceOf
1073 (m.takeOneBit() +PtypeFuns<LANCE>::indexNum*32);
1075 (state, piece.ptypeO(), piece.square(), king))
1076 return true;
1077 }
1078 return false;
1079 }
1080 double match(const StateInfo& info, const MoveInfo& move, int offset, const double *w) const
1081 {
1082 if (! info.threatmate_move.isNormal())
1083 return 0;
1084 const NumEffectState& state = *info.state;
1085 const StateInfo::pattern_square_t& cache
1086 = info.pattern_cache[move.move.to().index()];
1087 const int PatternAny = ptypeOIndex(PTYPEO_EDGE)*PatternCommon::SquareDim;
1088 double sum = 0.0;
1089 if (isKingMove(move.move)) {
1090 // king move
1091 sum += w[offset + KingMoveBase + PatternAny];
1092 for (size_t i=0; i<cache.size() && cache[i] >= 0; ++i) {
1093 sum += w[offset + KingMoveBase + cache[i]];
1094 }
1095 } else {
1096 const Square king = state.kingSquare(move.player);
1097 if (isOpeningKingRoad(move.move, king)) {
1098 // open king road
1099 int base = OpenRoadBase + move.move.ptype()*PatternCacheSize;
1100 sum += w[offset + base + PatternAny];
1101 for (size_t i=0; i<cache.size() && cache[i] >= 0; ++i) {
1102 sum += w[offset + base + cache[i]];
1103 }
1104 }
1106 state)) {
1107 // add effect to threatmate-move-at
1108 int base = move.move.ptype()*PatternCacheSize;
1109 sum += w[offset + base + PatternAny];
1110 for (size_t i=0; i<cache.size() && cache[i] >= 0; ++i) {
1111 sum += w[offset + base + cache[i]];
1112 }
1113 } else if (isDefendingKing8(move.move, king, state)) {
1114 // add effect to king8
1115 int base = move.move.ptype()*PatternCacheSize
1117 sum += w[offset + base + PatternAny];
1118 for (size_t i=0; i<cache.size() && cache[i] >= 0; ++i) {
1119 sum += w[offset + base + cache[i]];
1120 }
1121 }
1122 const Piece captured = state.pieceOnBoard(move.move.to());
1123 // capture
1124 if (captured.isPiece()) {
1126 (state, captured.ptypeO(), captured.square(), king)) {
1127 sum += w[offset + CaptureBase
1128 + captured.ptype()*PTYPE_SIZE+move.move.ptype()];
1129 sum += w[offset + CaptureBase
1130 + captured.ptype()*PTYPE_SIZE];
1131 }
1132 else {
1133 sum += w[offset + CaptureBase + captured.ptype()*PTYPE_SIZE
1134 + PTYPE_EDGE];
1135 }
1136 }
1137 }
1138 if (sum == 0.0)
1139 sum += w[offset + OtherMoveBase];
1140 return sum;
1141 }
1142 };
1143
1144 class SendOff : public Feature
1145 {
1146 public:
1147 enum {
1149 };
1150 SendOff() : Feature("SendOff", DIM)
1151 {
1152 }
1153 double match(const StateInfo& info, const MoveInfo& move, int offset, const double *w) const
1154 {
1155 if (! info.sendoffs.isMember(move.move.to()))
1156 return 0;
1157 return w[offset + move.move.ptype()];
1158 }
1159 };
1160
1161 class LureDefender : public Feature
1162 {
1163 public:
1164 enum {
1167 };
1168 LureDefender() : Feature("LureDefender", DIM)
1169 {
1170 }
1171 static double match(const NumEffectState& state, Move move, int see,
1172 const StateInfo::pinned_gs_t& pinned_list,
1173 int offset, const double *w)
1174 {
1175 const Square to = move.to(), king = state.kingSquare(alt(state.turn()));
1176 const Offset up = Board_Table.getOffset(state.turn(), U);
1177 const int basic_a = move.ptype() * PTYPE_SIZE*PTYPE_SIZE;
1178 double sum = 0.0;
1179 for (PinnedGeneral defense: pinned_list) {
1180 if (to != defense.attack)
1181 continue;
1182 assert(defense.general.owner() != move.player());
1183 assert(defense.covered.owner() != move.player());
1184 if (defense.general.square() == move.to()+up)
1185 offset += ATTACK_DIM;
1186 else if (state.hasEffectIf(move.ptypeO(), move.to(), defense.general.square()))
1187 offset += ATTACK_DIM*2;
1188 int a = basic_a;
1189 if (defense.covered.square().canPromote(state.turn())
1190 && canPromote(move.ptype()))
1191 a = promote(move.ptype()) * PTYPE_SIZE*PTYPE_SIZE;
1192 const int b = defense.general.ptype() * PTYPE_SIZE;
1193 const int c = defense.covered.ptype();
1194 sum += w[offset];
1195 if (see < 0)
1196 sum += w[offset+1] * see/1024.0;
1197 sum += w[offset + a];
1198 sum += w[offset + b];
1199 sum += w[offset + c];
1200 sum += w[offset + a + b];
1201 sum += w[offset + a + c];
1202 sum += w[offset + b + c];
1203 if (defense.covered.square().canPromote(state.turn())) {
1204 sum += w[offset + a + PTYPE_EDGE];
1205 sum += w[offset + b + PTYPE_EDGE];
1206 }
1207 if (defense.covered.square().isNeighboring8(king)) {
1208 sum += w[offset + a + KING];
1209 sum += w[offset + b + KING];
1210 }
1211 sum += w[offset + a + b + c];
1212 break;
1213 }
1214 return sum;
1215 }
1216 double match(const StateInfo& info, const MoveInfo& move, int offset, const double *w) const
1217 {
1218 return match(*info.state, move.move, move.see,
1219 info.exchange_pins[alt(move.player)], offset, w);
1220 }
1221 };
1222
1224 {
1225 public:
1226 enum {
1228 };
1229 CheckmateIfCapture() : Feature("CheckmateIfCapture", DIM)
1230 {
1231 }
1232 double match(const StateInfo& info, const MoveInfo& move, int offset, const double *w) const
1233 {
1234 if (info.state->inCheck() || move.see > -256)
1235 return 0;
1236 const Square king = info.state->kingSquare(alt(move.player));
1237 if (move.move.capturePtype() != PTYPE_EMPTY
1238 && ! info.state->hasPieceOnStand<GOLD>(move.player)
1239 && ! info.state->hasPieceOnStand<SILVER>(move.player)
1240 && ! info.move_candidate_exists[alt(move.player)])
1241 return 0;
1243 (*info.state, move.move.ptypeO(), move.move.to(), king))
1244 return 0;
1245 if (hasSafeCapture(info.copy, move.move))
1246 return 0;
1247 int ptype_index = move.move.ptype()*PTYPE_SIZE;
1248 int capture_index = move.move.capturePtype();
1249 double sum = 0.0;
1250 sum += w[offset + ptype_index + capture_index];
1251 sum += w[offset + capture_index];
1252 sum += w[offset + ptype_index + PTYPE_EDGE];
1253 sum += w[offset + PTYPE_EDGE];
1254 return sum;
1255 }
1256 static bool hasSafeCapture(NumEffectState& state, Move);
1257 };
1259 {
1260 public:
1261 enum {
1263 };
1264 AttackKing8Long() : Feature("AttackKing8Long", DIM)
1265 {
1266 }
1267 double match(const StateInfo& state, const MoveInfo& info, int offset, const double *w) const
1268 {
1269 const Move move = info.move;
1270 double sum = 0.0;
1271 for (Piece piece: state.king8_long_pieces) {
1272 if (! state.state->hasEffectIf(move.ptypeO(), move.to(),
1273 piece.square()))
1274 continue;
1275 sum += w[offset + PTYPE_EMPTY*PTYPE_SIZE+piece.ptype()]
1276 + w[offset + move.ptype()*PTYPE_SIZE+PTYPE_EMPTY]
1277 + w[offset + move.ptype()*PTYPE_SIZE+piece.ptype()];
1278 if (state.pin_by_opposing_sliders.isMember(piece)
1279 && info.see < 0)
1280 sum += w[offset + PTYPE_EMPTY*PTYPE_SIZE+PTYPE_EDGE]*info.see/1024.0;
1281 }
1282 return sum;
1283 }
1284 };
1285 class OpposingPawn : public Feature
1286 {
1287 public:
1288 enum {
1289 DIM = /*king-x*/9 * /* stand-pawn */ 3 * /* others */ 2,
1290 };
1291 OpposingPawn() : Feature("OpposingPawn", DIM)
1292 {
1293 }
1294 double match(const StateInfo& state, const MoveInfo& info, int offset, const double *w) const
1295 {
1296 const Move move = info.move;
1297 if (move.ptype() != PAWN)
1298 return 0.0;
1299 const Square front = move.to() + Board_Table.getOffset(info.player, U);
1300 if (state.state->pieceAt(front).ptype() != PAWN)
1301 return 0.0;
1302 int king_x = abs(state.state->kingSquare(alt(info.player)).x() - front.x());
1303 int stand_pawn = state.state->countPiecesOnStand<PAWN>(info.player);
1304 if (move.isDrop())
1305 --stand_pawn;
1306 stand_pawn = std::min(2, stand_pawn);
1307 bool has_other = state.state->hasPieceOnStand<LANCE>(info.player)
1308 || state.state->hasPieceOnStand<KNIGHT>(info.player)
1309 || state.state->hasPieceOnStand<SILVER>(info.player)
1310 || state.state->hasPieceOnStand<GOLD>(info.player)
1311 || state.state->hasPieceOnStand<ROOK>(info.player)
1312 || state.state->hasPieceOnStand<BISHOP>(info.player);
1313 int index = (king_x * 3 + stand_pawn) * 2 + has_other;
1314 return w[offset + index];
1315 }
1316 };
1317
1319 {
1320 public:
1321 enum {
1322 DIM = /*king-x*/9 * /* stand-pawn */ 3 * /* others */ 2 * /* capturepawn */ 2,
1323 };
1324 DropAfterOpposingPawn() : Feature("DropAfterOpposingPawn", DIM)
1325 {
1326 }
1327 double match(const StateInfo& state, const MoveInfo& info, int offset, const double *w) const
1328 {
1329 const Move move = info.move;
1330 if (move.ptype() != PAWN || ! move.isDrop() || ! state.history->hasLastMove())
1331 return 0.0;
1332 int to_x = move.to().x();
1333 const Move last_move = state.history->lastMove();
1334 if (! last_move.isNormal() || last_move.isDrop()
1335 || last_move.to().x() != to_x
1336 || last_move.from().x() != to_x)
1337 return 0.0;
1338
1339 const Square front = move.to()+Board_Table.getOffset(info.player, U);
1340 if (! front.canPromote(info.player))
1341 return 0.0;
1342 int king_x = abs(state.state->kingSquare(alt(info.player)).x() - to_x);
1343 int stand_pawn = std::min(2, state.state->countPiecesOnStand<PAWN>(info.player)-1);
1344 bool has_other = state.state->hasPieceOnStand<LANCE>(info.player)
1345 || state.state->hasPieceOnStand<KNIGHT>(info.player)
1346 || state.state->hasPieceOnStand<SILVER>(info.player)
1347 || state.state->hasPieceOnStand<GOLD>(info.player)
1348 || state.state->hasPieceOnStand<ROOK>(info.player)
1349 || state.state->hasPieceOnStand<BISHOP>(info.player);
1350 bool follow_pawn_capture = last_move.capturePtype() == PAWN;
1351 int index = ((king_x * 3 + stand_pawn) * 2 + has_other) * 2 + follow_pawn_capture;
1352 return w[offset + index];
1353 }
1354 };
1355
1356 class CoverPawn : public Feature
1357 {
1358 public:
1359 enum {
1360 DIM = 9 * 2 * PTYPE_SIZE * PTYPE_SIZE
1362 CoverPawn() : Feature("CoverPawn", DIM)
1363 {
1364 }
1365 double match(const StateInfo& si, const MoveInfo& mi, int offset, const double *w) const
1366 {
1367 if (! si.history->hasLastMove() || si.state->inCheck()
1368 || mi.move.isCaptureOrPromotion())
1369 return 0.0;
1370 const Move last_move = si.history->lastMove();
1371 if (last_move.ptype() != PAWN)
1372 return 0.0;
1373 const Offset diff = Board_Table.getOffset(mi.player, U);
1374 const Square front = last_move.to()-diff, front2 = front-diff;
1375 if (si.state->pieceOnBoard(front).ptype() != PAWN // must be turn's pawn
1376 || si.state->pieceAt(front2).isOnBoardByOwner(alt(mi.player)))
1377 return 0.0;
1378 const bool cover = si.state->hasEffectIf
1379 (mi.move.ptypeO(), mi.move.to(), front);
1380 const Ptype moved = cover ? mi.move.ptype() : PTYPE_EDGE,
1381 threatened = si.state->pieceAt(front2).ptype();
1382 const int a = std::min(2,si.state->countEffect(alt(mi.player), front) - 1);
1383 assert(a >= 0);
1384 const int b = std::min(2,si.state->countEffect(mi.player, front));
1385 const int ptype_index = moved*PTYPE_SIZE+threatened;
1386 const bool has_pawn = si.state->hasPieceOnStand(alt(mi.player),PAWN);
1387 const int pawn_index = PTYPE_SIZE*PTYPE_SIZE;
1388 const int effect_index = (a*3+b)*2*PTYPE_SIZE*PTYPE_SIZE
1389 + (has_pawn ? pawn_index : 0);
1390 assert(effect_index >= 0);
1391 return w[offset + threatened]
1392 + w[offset + ptype_index]
1393 + w[offset + effect_index + ptype_index];
1394 }
1395 };
1397 {
1398 public:
1399 enum {
1401 DIM = StandCount * PTYPE_SIZE * 2
1403 SacrificeAttack() : Feature("SacrificeAttack", DIM)
1404 {
1405 }
1406 double match(const StateInfo& si, const MoveInfo& mi, int offset, const double *w) const
1407 {
1408 const Square king = si.state->kingSquare(alt(mi.player));
1409 if (mi.see >= 0
1411 (*si.state, mi.move.ptypeO(), mi.move.to(), king)))
1412 return 0.0;
1413 assert(PieceStand::order[6] == PAWN);
1414 int stand = mi.standIndex(*si.state);
1415 int index = (stand * PTYPE_SIZE + mi.move.ptype()) * 2;
1416 double sum = w[offset + index];
1417 if (si.history->hasLastMove(2)) {
1418 Move my_last_move = si.history->lastMove(2);
1419 if (my_last_move.isNormal()
1421 (*si.state, my_last_move.ptypeO(), my_last_move.to(), king))
1422 sum += w[offset + index + 1];
1423 }
1424 return sum;
1425 }
1426 };
1427 class King5x5Ptype : public Feature
1428 {
1429 public:
1430 enum {
1433 };
1434 King5x5Ptype() : Feature("King5x5Ptype", DIM)
1435 {
1436 }
1437 static double addOne(Player king, Square center, const StateInfo& si, const MoveInfo& mi, int offset, const double *w)
1438 {
1439 const Square to = mi.move.to();
1440 int dx = center.x() - to.x();
1441 const int dy = center.y() - to.y();
1442 if (abs(dx) >= 3 || abs(dy) >= 3)
1443 return 0.0;
1444 if ((king == BLACK && center.x() > 5)
1445 || (king == WHITE && center.x() >= 5))
1446 dx = -dx;
1447 int sq_index = (dx+2)*5 + dy+2;
1448 bool a = mi.move.isDrop() ? si.state->hasEffectAt(mi.player, to)
1449 : si.state->countEffect(mi.player,to) >= 2;
1450 bool d = si.state->hasEffectAt(alt(mi.player), to);
1451 int index = (sq_index*4 + a*2+d) * PTYPE_SIZE*PTYPE_SIZE
1452 + mi.move.capturePtype()*PTYPE_SIZE + mi.move.ptype();
1453 return w[offset + index];
1454 }
1455 double match(const StateInfo& si, const MoveInfo& mi, int offset, const double *w) const
1456 {
1457 return
1458 addOne(mi.player, si.state->kingSquare(mi.player), si, mi, offset, w)
1459 + addOne(alt(mi.player), si.state->kingSquare(alt(mi.player)), si, mi,
1460 offset+ONE_DIM, w);
1461 }
1462 };
1463 class KingBlockade : public Feature
1464 {
1465 public:
1466 enum {
1470 DIM = 5 * StandCount
1472 KingBlockade() : Feature("KingBlockade", DIM)
1473 {
1474 }
1475 static bool blockAll(const King8Info& ki, Square king, Move move,
1476 const NumEffectState& state,
1477 const CArray<Direction,3>& directions)
1478 {
1479 int liberty = 0;
1480 for (Direction d: directions) {
1481 if ((ki.liberty() & (1<<d)) == 0)
1482 continue;
1483 ++liberty;
1484 const Square sq = king + Board_Table.getOffset(alt(state.turn()), d);
1485 if (! state.hasEffectIf(move.ptypeO(), move.to(), sq))
1486 return false;
1487 }
1488 return liberty > 0;
1489 }
1490 double match(const StateInfo& si, const MoveInfo& mi, int offset, const double *w) const
1491 {
1492 const NumEffectState& state = *si.state;
1493 const King8Info ki = si.king8Info(alt(mi.player));
1494 const Square king = state.kingSquare(alt(mi.player));
1495 if (ki.libertyCount() == 0
1497 (state, mi.move.ptypeO(), mi.move.to(), king)))
1498 return 0.0;
1499 int stand = mi.standIndex(state);
1500 offset += stand*5;
1501 double sum = 0.0;
1502 if (ki.libertyCount() == 1) {
1503 const Square sq = king
1506 if (! state.hasEffectIf(mi.move.ptypeO(), mi.move.to(), sq))
1507 return 0.0;
1508 sum += w[offset+BlockLastOne];
1509 // fall through
1510 }
1511 const CArray<Direction,3> front3 = {{ UL, U, UR }};
1512 if (blockAll(ki, king, mi.move, state, front3))
1513 sum += w[offset+BlockFront];
1514 const CArray<Direction,3> left3 = {{ UL, L, DL }};
1515 if (blockAll(ki, king, mi.move, state, left3)) {
1516 const bool wide = (mi.player== WHITE && king.x() < 5)
1517 || (mi.player== BLACK && king.x() > 5);
1518 sum += w[offset+(wide ? BlockSideWide : BlockSideOther)];
1519 }
1520 const CArray<Direction,3> right3 = {{ UR, R, DR }};
1521 if (blockAll(ki, king, mi.move, state, right3)) {
1522 const bool wide = (mi.player== BLACK && king.x() < 5)
1523 || (mi.player== WHITE && king.x() > 5);
1524 sum += w[offset+ (wide ? BlockSideWide : BlockSideOther)];
1525 }
1526 const CArray<Direction,3> back3 = {{ DL, D, DR }};
1527 if (blockAll(ki, king, mi.move, state, back3))
1528 sum += w[offset+BlockBack];
1529 return sum;
1530 }
1531 };
1532 class CoverFork : public Feature
1533 {
1534 public:
1535 enum {
1538 CoverFork() : Feature("CoverFork", DIM)
1539 {
1540 }
1541 static bool defending(const NumEffectState& state, Move move, Square target)
1542 {
1543 if (state.countEffect(alt(state.turn()), target) > 1)
1544 return false;
1545 if (state.hasEffectIf(move.ptypeO(), move.to(), target))
1546 return true;
1547 Piece attacking = state.findCheapAttack(alt(state.turn()), target);
1549 if (o.zero()
1550 || ! Board_Table.isBetween(move.to(), attacking.square(), target))
1551 return false;
1552 return state.countEffect(state.turn(), move.to()) >= (1-move.isDrop());
1553 }
1554 double match(const StateInfo& si, const MoveInfo& mi, int offset, const double *w) const
1555 {
1556 const NumEffectState& state = *si.state;
1557 PieceMask attacked = state.piecesOnBoard(mi.player)
1558 & state.effectedMask(alt(mi.player))
1559 & ~(state.effectedMask(mi.player));
1560 attacked.clearBit<PAWN>();
1561 offset += mi.move.ptype()*PTYPE_SIZE*PTYPE_SIZE;
1562 double sum = 0.0;
1563 while (attacked.any()) {
1564 Piece a = state.pieceOf(attacked.takeOneBit());
1565 if (! defending(state, mi.move, a.square()))
1566 continue;
1567 int index_a = a.ptype()*PTYPE_SIZE;
1568 PieceMask copy = attacked;
1569 while (copy.any()) {
1570 Piece b = state.pieceOf(copy.takeOneBit());
1571 if (! defending(state, mi.move, b.square()))
1572 continue;
1573 sum += w[offset];
1574 sum += w[offset+index_a];
1575 sum += w[offset+b.ptype()];
1576 sum += w[offset+index_a+b.ptype()];
1577 }
1578 }
1579 return sum;
1580 }
1581 };
1583 {
1584 public:
1585 enum {
1588 ThreatmateByCapture() : Feature("ThreatmateByCapture", DIM)
1589 {
1590 }
1591 double match(const StateInfo& si, const MoveInfo& mi, int offset, const double *w) const
1592 {
1593 const Move move = mi.move;
1594 const Ptype captured = move.capturePtype();
1595 if (captured == PTYPE_EMPTY
1597 & 1<<(captured-PTYPE_BASIC_MIN)) == 0)
1598 return 0.0;
1599 double sum = 0.0;
1600 sum += w[offset];
1601 if (mi.see < 0)
1602 sum += w[offset+1] * mi.see/1024.0;
1603 sum += w[offset+captured];
1604 sum += w[offset+move.ptype()*PTYPE_SIZE];
1605 sum += w[offset+move.ptype()*PTYPE_SIZE+captured];
1606 return sum;
1607 }
1608 };
1609
1611 {
1612 public:
1613 enum {
1616 PromotionBySacrifice() : Feature("PromotionBySacrifice", DIM)
1617 {
1618 }
1619 double match(const StateInfo& si, const MoveInfo& mi, int offset, const double *w) const
1620 {
1621 const Move move = mi.move;
1622 if (mi.see >= 0 || move.isDrop()
1623 || si.state->inCheck()
1624 || si.threatmate_move.isNormal())
1625 return 0.0;
1626 const NumEffectState& state = *si.state;
1627 mask_t m = state.longEffectAt(move.from(), state.turn());
1628 m &= ~mask_t::makeDirect(PtypeFuns<LANCE>::indexMask);
1629 double sum = 0.0;
1630 while (m.any()) {
1631 const Piece piece = state.pieceOf
1632 (m.takeOneBit() +PtypeFuns<LANCE>::indexNum*32);
1633 assert(piece.ptype() != LANCE);
1634 if (piece.isPromoted()
1635 || piece.square().canPromote(mi.player))
1636 continue;
1638 assert(! o.zero());
1639 bool can_promote = false;
1640 Square to = move.from()+o;
1641 if (to == move.to())
1642 continue;
1643 while (state[to].isEmpty()) {
1644 if (to.canPromote(mi.player)
1645 && ! state.hasEffectAt(alt(mi.player), to))
1646 can_promote = true;
1647 to += o;
1648 }
1649 assert(state[to] != piece);
1650 int index = 0;
1651 if (piece.ptype() == ROOK)
1652 index += PTYPE_SIZE*PTYPE_SIZE;
1653 index += move.ptype()*PTYPE_SIZE;
1654 if (to.canPromote(mi.player)
1655 && state[to].isOnBoardByOwner(alt(mi.player))
1656 && ! state.hasEffectAt(alt(mi.player), to)) {
1657 sum += w[offset];
1658 sum += w[offset+1]*mi.see/1024.0;
1659 if (mi.check)
1660 sum += w[offset+2];
1661 if (state.hasEffectAt(alt(mi.player), piece.square())) {
1662 sum += w[offset+3];
1663 if (mi.check)
1664 sum += w[offset+4];
1665 }
1666 if (state.hasEffectIf(piece.ptypeO(), to,
1667 state.kingSquare(alt(mi.player))))
1668 sum += w[offset+5];
1669 sum += w[offset + index + state[to].ptype()];
1670 }
1671 else if (can_promote) {
1672 sum += w[offset];
1673 sum += w[offset+1]*mi.see/1024.0;
1674 if (mi.check)
1675 sum += w[offset+2];
1676 if (state.hasEffectAt(alt(mi.player), piece.square())) {
1677 sum += w[offset+3];
1678 if (mi.check)
1679 sum += w[offset+4];
1680 }
1681 sum += w[offset + index];
1682 }
1683 }
1684 return sum;
1685 }
1686 };
1687
1689 {
1690 public:
1691 enum {
1692 DIM =(2*PTYPE_SIZE * PTYPE_SIZE) * 3 * PTYPE_SIZE
1694 EscapeThreatened() : Feature("EscapeThreatened", DIM)
1695 {
1696 }
1697 double match(const StateInfo& si, const MoveInfo& mi, int offset, const double *w) const
1698 {
1699 const NumEffectState& state = *si.state;
1700 const Move move = mi.move;
1701 const Piece target = si.threatened[mi.player];
1702 if (mi.see > 0 || mi.check || mi.open_check
1703 || ! move.isNormal()
1704 || ! target.isPiece() || state.inCheck()
1707 (state, move.ptypeO(), move.to(), state.kingSquare(alt(mi.player))))
1708 return 0.0;
1709 const int t0 = target.ptype()*PTYPE_SIZE*2*PTYPE_SIZE*3;
1710 const int t1 = t0 + state.findCheapAttack(alt(mi.player), target.square()).ptype()*2*PTYPE_SIZE*3;
1711 const int t2 = t1 + state.hasEffectAt(mi.player, target.square())*PTYPE_SIZE*3;
1712 double sum = 0.0;
1713 if (! move.isDrop() && state[move.from()] == target) {
1714 sum += w[offset + t0];
1715 sum += w[offset + t1];
1716 sum += w[offset + t2];
1717 return sum;
1718 }
1719 if (state.hasEffectIf(move.ptypeO(), move.to(),
1720 target.square())) {
1721 if (move.isDrop()
1722 || ! state.hasEffectIf(move.oldPtypeO(), move.from(),
1723 target.square())) {
1724 sum += w[offset + t0 + move.ptype()];
1725 sum += w[offset + t1 + move.ptype()];
1726 sum += w[offset + t2 + move.ptype()];
1727 return sum;
1728 }
1729 }
1730 // not related move
1731 offset += PTYPE_SIZE;
1732 if (move.isDrop())
1733 offset += PTYPE_SIZE;
1734 sum += w[offset + t0 + move.ptype()];
1735 sum += w[offset + t1 + move.ptype()];
1736 sum += w[offset + t2 + move.ptype()];
1737 return sum;
1738 }
1739 };
1740 class BookMove : public Feature
1741 {
1742 public:
1743 enum {
1744 DIM = 2
1746 BookMove() : Feature("BookMove", DIM)
1747 {
1748 }
1749 double match(const StateInfo& si, const MoveInfo& mi, int offset, const double *w) const
1750 {
1751 if (! si.bookmove[0].isNormal())
1752 return 0.0;
1753 if (mi.move == si.bookmove[0] || mi.move == si.bookmove[1])
1754 return w[offset];
1755 return w[offset+1];
1756 }
1757 };
1758 }
1759}
1760#endif /* OSL_MOVE_PROBABILITY_FEATURE_H */
1761// ;;; Local Variables:
1762// ;;; mode:c++
1763// ;;; c-basic-offset:2
1764// ;;; End:
const Offset getOffset(Direction dir) const
Definition boardTable.h:47
const Offset getShortOffsetNotKnight(Offset32 offset32) const
Longの利きの可能性のあるoffsetの場合は, 反復に使う offsetを Knight以外のShortの利きのoffsetの場合はそれ自身を返す.
Definition boardTable.h:119
bool isBetween(Square t, Square p0, Square p1) const
p0, p1の間にtがあるかどうか.
Definition boardTable.h:172
Direction getLongDirection(Offset32 offset32) const
Definition boardTable.h:71
static size_t size()
Definition container.h:76
const Offset offset() const
返り値が0なら長い利きがない, 0以外なら辿るのに必要なoffset (2005/3/25 に仕様変更 - 長い利きだが隣の場合もoffsetを返す)
bool hasEffect() const
短い利きがあるか,間がemptyなら長い利きがある
bool isMember(const T &e, const_iterator first, const_iterator last) const
Definition container.h:257
圧縮していない moveの表現 .
PtypeO ptypeO() const
移動後のPtype, i.e., 成る手だった場合成った後
bool isPromotion() const
Ptype ptype() const
Player player() const
PtypeO oldPtypeO() const
移動前のPtypeO, i.e., 成る手だった場合成る前
bool isDrop() const
Ptype capturePtype() const
bool isNormal() const
INVALID でも PASS でもない.
bool isCaptureOrPromotion() const
Ptype oldPtype() const
移動前のPtype, i.e., 成る手だった場合成る前
const Square to() const
const Square from() const
利きを持つ局面
const NumBitmapEffect effectSetAt(Square sq) const
const Piece selectCheapPiece(PieceMask effect) const
利きの中から安そうな駒を選ぶ
const PieceMask effectedMask(Player pl) const
pl からの利きが(1つ以上)ある駒一覧
int countEffect(Player player, Square target) const
利きの数を数える.
bool hasEffectByPiece(Piece attack, Square target) const
駒attack が target に利きを持つか (旧hasEffectToと統合)
bool hasEffectAt(Square target) const
対象とするマスにあるプレイヤーの利きがあるかどうか.
const Piece findCheapAttack(Player P, Square square) const
bool hasEffectIf(PtypeO ptypeo, Square attacker, Square target) const
attackerにptypeoの駒がいると仮定した場合にtargetに利きがあるかどうか を stateをupdateしないで確かめる.
bool inCheck(Player P) const
Pの玉が王手状態
const mask_t longEffectAt(Square target) const
const PieceMask & piecesOnBoard(Player p) const
差が uniqになるような座標の差分.
Definition offset32.h:17
座標の差分
Definition basic_type.h:430
bool zero() const
Definition basic_type.h:502
駒番号のビットセット.
Definition pieceMask.h:21
const mask_t getMask(int num) const
Definition pieceMask.h:59
void set(int num)
Definition pieceMask.h:48
void clearBit()
unpromote(PTYPE) の駒のbit を消す
Definition pieceMask.h:74
bool any() const
Definition pieceMask.h:57
void reset(int num)
Definition pieceMask.h:54
static const CArray< Ptype, 7 > order
持駒の表示で良く使われる順番.
PtypeO ptypeO() const
Definition basic_type.h:824
Ptype ptype() const
Definition basic_type.h:821
bool isPromoted() const
promoteした駒かどうかをチェックする
Definition basic_type.h:898
const Square square() const
Definition basic_type.h:832
bool isEmpty() const
Definition basic_type.h:913
bool isEdge() const
Definition basic_type.h:919
Player owner() const
Definition basic_type.h:963
bool isPiece() const
Definition basic_type.h:953
bool isOnBoardByOwner() const
piece がプレイヤーPの持ち物でかつボード上にある駒の場合は true.
Definition basic_type.h:852
int number() const
Definition basic_type.h:828
const EffectContent getEffect(PtypeO ptypeo, Square from, Square to) const
fromにいるptypeoがtoに利きを持つか?
Definition ptypeTable.h:112
int getMoveMask(Ptype ptype) const
Definition ptypeTable.h:84
const Piece pieceOnBoard(Square sq) const
bool hasPieceOnStand(Player player, Ptype ptype) const
const Piece kingPiece() const
Definition simpleState.h:83
Player turn() const
bool canDropPawnTo(Player player, int x) const
xの筋に歩を打てる
const Piece pieceOf(int num) const
Definition simpleState.h:76
bool isEmptyBetween(Square from, Square to, Offset offset, bool pieceExistsAtTo=false) const
Square kingSquare() const
Definition simpleState.h:94
int countPiecesOnStand(Player pl, Ptype ptype) const
持駒の枚数を数える
const Piece pieceAt(Square sq) const
unsigned int index() const
Definition basic_type.h:572
bool isPieceStand() const
Definition basic_type.h:576
int y() const
将棋としてのY座標を返す.
Definition basic_type.h:567
bool isNeighboring8(Square to) const
bool canPromote() const
Definition basic_type.h:659
const Square squareForBlack(Player player) const
Definition basic_type.h:598
bool isOnBoard() const
盤面上を表すかどうかの判定. 1<=x() && x()<=9 && 1<=y() && y()<=9 Squareの内部表現に依存する.
Definition basic_type.h:583
bool isOnBoardRegion() const
squareがONBOARD_MINとONBOARD_MAXの間にある
Definition basic_type.h:641
int x() const
将棋としてのX座標を返す.
Definition basic_type.h:563
unsigned int square
Definition basic_type.h:533
敵玉の8近傍の状態を表す.
Definition king8Info.h:29
unsigned int liberty() const
8-15 bit 目を 0-7bitにshiftして返す
Definition king8Info.h:54
unsigned int libertyCount() const
libertyの数
Definition king8Info.h:82
bool hasLastMove(size_t last=1) const
Definition moveStack.h:27
const Move lastMove(size_t last=1) const
Definition moveStack.h:28
現在の定義 (2005/3/4以降)
const mask_t selectLong() const
static bool hasEffect(const NumEffectState &state, PtypeO ptypeo, Square from, Square target)
ptypeo の駒がfromからtargetの8近傍に直接の利きを持つか
static double addOne(Direction dir, const StateInfo &state, const MoveInfo &move, int offset, const double *w)
double match(const StateInfo &state, const MoveInfo &move, int offset, const double *w) const
double match(const StateInfo &state, const MoveInfo &info, int offset, const double *w) const
double match(const StateInfo &state, const MoveInfo &info, int offset, const double *w) const
double match(const StateInfo &state, const MoveInfo &info, int offset, const double *w) const
double match(const StateInfo &state, const MoveInfo &move, int offset, const double *w) const
static double addSquare(Square target, const StateInfo &info, int offset, const double *w)
static double addOne(const StateInfo &info, Square to, int offset, const double *w)
static double findAll(const StateInfo &state, Move move, const double *w, int offset=0)
double match(const StateInfo &state, const MoveInfo &move, int offset, const double *w) const
static void makeLongAttackOne(StateInfo &info, Piece piece, Direction d)
Definition feature_.cc:147
static void updateCache(StateInfo &)
Definition feature_.cc:113
static double findAll(const StateInfo &state, Move move, const double *w, int offset=0)
static int longAttackIndex(osl::PtypeO ptypeo)
static double findAll(const StateInfo &state, Player P, Square target, const double *w, int offset)
static double addPiece(const StateInfo &state, Piece piece, Square to, const double *w, int offset)
double match(const StateInfo &state, const MoveInfo &move, int offset, const double *w) const
static int ptypeSupport(Ptype moved, bool has_support)
double match(const StateInfo &si, const MoveInfo &mi, int offset, const double *w) const
static bool isDefendingThreatmate(Move move, Move threatmate, const NumEffectState &state)
static bool isOpeningKingRoad(Move move, Square king)
double match(const StateInfo &info, const MoveInfo &move, int offset, const double *w) const
static bool isDefendingKing8(Move move, Square king, const NumEffectState &state)
double match(const StateInfo &state, const MoveInfo &move, int offset, const double *w) const
static int sign(const NumEffectState &state, Move move, Player player)
double match(const StateInfo &state, const MoveInfo &move, int offset, const double *w) const
static int checkIndex(const MoveInfo &move)
static bool hasSafeCapture(NumEffectState &state, Move)
Definition feature_.cc:205
double match(const StateInfo &info, const MoveInfo &move, int offset, const double *w) const
double match(const StateInfo &state, const MoveInfo &move, int offset, const double *w) const
double match(const StateInfo &si, const MoveInfo &mi, int offset, const double *w) const
static bool defending(const NumEffectState &state, Move move, Square target)
double match(const StateInfo &si, const MoveInfo &mi, int offset, const double *w) const
double match(const StateInfo &state, const MoveInfo &info, int offset, const double *w) const
double match(const StateInfo &state, const MoveInfo &move, int offset, const double *w) const
double match(const StateInfo &si, const MoveInfo &mi, int offset, const double *w) const
virtual double match(const StateInfo &, const MoveInfo &, int offset, const double *) const =0
static int classifyEffect9(const NumEffectState &state, Player player, Square to)
double match(const StateInfo &state_info, const MoveInfo &info, int offset, const double *w) const
double match(const StateInfo &state_info, const MoveInfo &info, int offset, const double *w) const
double match(const StateInfo &si, const MoveInfo &mi, int offset, const double *w) const
static double addOne(Player king, Square center, const StateInfo &si, const MoveInfo &mi, int offset, const double *w)
double match(const StateInfo &si, const MoveInfo &mi, int offset, const double *w) const
static bool blockAll(const King8Info &ki, Square king, Move move, const NumEffectState &state, const CArray< Direction, 3 > &directions)
double match(const StateInfo &state, const MoveInfo &info, int offset, const double *w) const
double match(const StateInfo &state, const MoveInfo &info, int offset, const double *w) const
double match(const StateInfo &state, const MoveInfo &move, int offset, const double *w) const
double match(const StateInfo &info, const MoveInfo &move, int offset, const double *w) const
static double match(const NumEffectState &state, Move move, int see, const StateInfo::pinned_gs_t &pinned_list, int offset, const double *w)
double match(const StateInfo &info, const MoveInfo &move, int offset, const double *w) const
static int longPtype(const NumEffectState &state, Square position, Player player)
double match(const StateInfo &state, const MoveInfo &move, int offset, const double *w) const
double match(const StateInfo &state, const MoveInfo &info, int offset, const double *w) const
double match(const StateInfo &state, const MoveInfo &info, int offset, const double *w) const
static std::string name(int x, int y)
PatternCommon(const std::string &name, int dim)
static void updateCacheOne(Square target, StateInfo &info)
Definition feature_.cc:25
double addOne(const StateInfo &state, int offset, const double *w, Square position) const
static void updateCache(StateInfo &info)
Definition feature_.cc:14
double matchPtype(const StateInfo &state, const MoveInfo &move, int offset, const double *w) const
double match(const StateInfo &state, const MoveInfo &move, int offset, const double *w) const
std::pair< int, int > squareStatus(const NumEffectState &state, Player player, Square to, Square &front) const
double match(const StateInfo &si, const MoveInfo &mi, int offset, const double *w) const
double match(const StateInfo &state, const MoveInfo &move, int offset, const double *w) const
double match(const StateInfo &si, const MoveInfo &mi, int offset, const double *w) const
double match(const StateInfo &state, const MoveInfo &move, int offset, const double *w) const
double match(const StateInfo &info, const MoveInfo &move, int offset, const double *w) const
static int fromTo(Square to, Square from)
double match(const StateInfo &state, const MoveInfo &info, int offset, const double *w) const
static int fromTo(Square to, Square from)
double match(const StateInfo &state, const MoveInfo &info, int offset, const double *w) const
double match(const StateInfo &state, const MoveInfo &move, int offset, const double *w) const
double match(const StateInfo &si, const MoveInfo &mi, int offset, const double *w) const
double match(const StateInfo &state_info, const MoveInfo &info, int offset, const double *w) const
static const Piece find(const NumEffectState &state, Square to, const PieceMask &remove, Player player)
static size_t supportAttack(const StateInfo &info, Square to, Move move)
double match(const StateInfo &state, const MoveInfo &info, int offset, const double *w) const
static void supportAttack(const NumEffectState &state, Square to, const PieceMask &my_pin, const PieceMask &op_pin, Player turn, std::pair< Ptype, Ptype > &out)
static void supportAttack(const StateInfo &info, Square to, Move move, std::pair< Ptype, Ptype > &out)
PatternBase< true > PatternPromotion
Ptype
駒の種類を4ビットでコード化する
Definition basic_type.h:84
@ ROOK
Definition basic_type.h:100
@ BISHOP
Definition basic_type.h:99
@ PROOK
Definition basic_type.h:92
@ PAWN
Definition basic_type.h:95
@ PTYPE_EDGE
Definition basic_type.h:86
@ KING
Definition basic_type.h:93
@ KNIGHT
Definition basic_type.h:97
@ PTYPE_EMPTY
Definition basic_type.h:85
@ SILVER
Definition basic_type.h:98
@ PTYPE_BASIC_MIN
Definition basic_type.h:103
@ GOLD
Definition basic_type.h:94
@ PBISHOP
Definition basic_type.h:91
@ LANCE
Definition basic_type.h:96
const PtypeTable Ptype_Table
Definition tables.cc:97
const int PTYPE_SIZE
Definition basic_type.h:107
Ptype getPtype(PtypeO ptypeO)
Definition basic_type.h:217
const int PTYPEO_SIZE
Definition basic_type.h:308
bool canPromote(Ptype ptype)
ptypeがpromote可能な型かどうかのチェック promote済みの場合はfalseを返す
Definition basic_type.h:147
constexpr Direction longToShort(Direction d)
Definition basic_type.h:380
Ptype unpromote(Ptype ptype)
ptypeがpromote後の型の時に,promote前の型を返す. promoteしていない型の時はそのまま返す
Definition basic_type.h:157
const BoardTable Board_Table
Definition tables.cc:95
Player getOwner(PtypeO ptypeO)
Definition basic_type.h:256
Direction
Definition basic_type.h:310
unsigned int ptypeOIndex(PtypeO ptypeo)
Definition basic_type.h:205
Offset32Base< 8, 9 > Offset32
Definition offset32.h:63
constexpr int sign(Player player)
Definition basic_type.h:23
Player
Definition basic_type.h:8
@ WHITE
Definition basic_type.h:10
@ BLACK
Definition basic_type.h:9
PtypeO
Player + Ptype [-15, 15] PtypeO の O は Owner の O.
Definition basic_type.h:199
constexpr bool isLong(Direction d)
Definition basic_type.h:350
constexpr Player alt(Player player)
Definition basic_type.h:13
Ptype promote(Ptype ptype)
promote可能なptypeに対して,promote後の型を返す promote不可のptypeを与えてはいけない.
Definition basic_type.h:173
PtypeO captured(PtypeO ptypeO)
unpromoteすると共に,ownerを反転する.
Definition basic_type.h:264
bool isMember(Square position) const
Definition square8.h:22
static bool hasEffect(const NumEffectState &, Square target, Player attack)
target に attack の追加利きが一つでもあるか. 相手の影利きが先にある場合は対象としない.
static int bsf(Integer mask)
Definition mask.h:138
int standIndex(const NumEffectState &state) const
Definition moveInfo.h:22
CArray< Piece, 2 > threatened
Definition stateInfo.h:26
unsigned int possible_threatmate_ptype
Definition stateInfo.h:43
const NumEffectState * state
Definition stateInfo.h:22
CArray< bool, 2 > move_candidate_exists
Definition stateInfo.h:39
CArray< pinned_gs_t, 2 > exchange_pins
Definition stateInfo.h:38
bool pinByOpposingSliders(Piece p) const
Definition stateInfo.h:83
CArray< pattern_square_t, Square::SIZE > pattern_cache
Definition stateInfo.h:30
King8Info king8Info(Player pl) const
Definition stateInfo.h:88
CArray< PieceMask, 2 > pin
Definition stateInfo.h:34
CArray2d< long_attack_t, 40, 8 > long_attack_cache
Definition stateInfo.h:28