3 #ifndef OSL_MOVE_PROBABILITY_FEATURE_H
4 #define OSL_MOVE_PROBABILITY_FEATURE_H
11 #include <boost/foreach.hpp>
16 namespace move_probability
34 const int a =
std::min(2, state.countEffect(player, to));
35 int d =
std::min(2,state.countEffect(
alt(player), to));
54 return (move.
see > 0) ? 0 : ((move.
see == 0) ? 1 : 2);
56 static int sign(
const NumEffectState& state,
Move move,
59 const Square king = state.kingSquare(
alt(player));
61 if (ry == 0)
return 0;
62 return ry > 0 ? 1 : -1;
73 return w[offset+index];
84 if (! state.
history->hasLastMove()
90 if (state.
history->hasLastMove(2)
94 return w[offset +
match];
106 int index = see / 128;
110 }
else if (see == 0) {
123 const int promote_index = to.
canPromote(player)
125 double sum = w[offset+see_index+promote_index*
SeeClass];
127 sum += w[offset+see_index+progress_index*
SeeClass];
151 * (2*PTYPE_SIZE*PTYPE_SIZE);
152 return w[offset+index];
163 || ! state.
history->hasLastMove(2)
178 || ! state.
history->hasLastMove(2)
179 || ! state.
history->lastMove(2).isNormal()
184 return w[index + offset];
209 const int from_to = move.
isDrop() ? 0
211 double sum = w[offset + index + from_to + 3];
213 sum += w[offset + index + 7];
214 sum += w[offset + index + state.
progress8()+8];
233 int to = move.
to().
x();
241 double sum = w[offset + index + from_to + 3];
243 sum += w[offset + index + 7];
244 sum += w[offset + index + state.
progress8()+8];
264 const Square my_king = state.
state->kingSquare(P).squareForBlack(P);
265 const Square op_king = state.
state->kingSquare(
alt(P)).squareForBlack(P);
266 const int from_to = move.
isDrop() ? 0
269 size_t index = ((to.
y()-my_king.
y()+8)*
PTYPE_SIZE + ptype)*16;
271 double sum = w[offset + index + from_to + 3];
273 sum += w[offset + index + 7];
274 sum += w[offset + index + state.
progress8()+8];
278 sum += w[offset +
ONE_DIM + index + from_to + 3];
280 sum += w[offset +
ONE_DIM + index + 7];
302 const int from_to = move.
isDrop() ? 0
304 int dx = to.
x() - my_king.
x(), fx = from_to;
311 double sum = w[offset + index + fx + 3];
313 sum += w[offset + index + 7];
314 sum += w[offset + index + state.
progress8()+8];
316 dx = to.
x() - op_king.
x(), fx = from_to;
323 sum += w[offset +
ONE_DIM + index + fx + 3];
325 sum += w[offset +
ONE_DIM + index + 7];
342 const NumEffectState& state = *state_info.
state;
344 const Ptype support = state.findCheapAttack(info.
player, move.
from()).ptype();
348 return w[index + offset];
359 Square to,
const PieceMask&
remove,
363 PieceMask pieces = state.piecesOnBoard(player)
364 & state.effectSetAt(to);
366 return state.selectCheapPiece(pieces);
370 const PieceMask& my_pin,
371 const PieceMask& op_pin,
373 std::pair<Ptype,Ptype>&
out)
375 out.first =
find(state, to, my_pin, turn).
ptype();
376 out.second =
find(state, to, op_pin,
alt(turn)).
ptype();
379 std::pair<Ptype,Ptype>&
out)
385 PieceMask my_pin = info.
pin[turn];
386 my_pin.set(info.
state->pieceAt(move.
from()).number());
392 std::pair<Ptype,Ptype> pair;
404 return w[index + offset];
419 const NumEffectState& state = *state_info.
state;
421 const CArray<bool,3> me = {{
426 const CArray<bool,3> op = {{
431 size_t index = ptype;
432 for (
int i=0; i<3; ++i) {
433 index *= 2; index += me[i];
434 index *= 2; index += op[i];
437 return w[index + offset];
450 const NumEffectState& state = *state_info.
state;
452 NumBitmapEffect effect=state.effectSetAt(move.
to());
454 effect.reset(state.pieceOnBoard(move.
from()).number()+8);
455 const CArray<mask_t,3> pieces = {{
456 effect.selectLong<
LANCE>() >> 8,
457 effect.selectLong<
BISHOP>() >> 8,
458 effect.selectLong<
ROOK>() >> 8
460 size_t index = ptype;
461 for (
int i=0; i<3; ++i) {
463 index += (pieces[i] & state.piecesOnBoard(info.
player).getMask(1)).any();
465 index += (pieces[i] & state.piecesOnBoard(
alt(info.
player)).getMask(1)).any();
468 return w[index + offset];
478 EffectSize = 9, EffectBase = AttackBase+AttackSize,
479 OpKingSize = 4, OpKingBase = EffectBase+EffectSize,
480 MyKingSize = 3, MyKingBase = OpKingBase+OpKingSize,
481 PromotionSize = 2, PromotionBase = MyKingBase+MyKingSize,
482 PinOpenSize = 4, PinOpenBase = PromotionBase + PromotionSize,
483 LastToSize = 4, LastToBase = PinOpenBase + PinOpenSize,
484 LastEffectChangedSize = 6, LastEffectChangedBase = LastToBase + LastToSize,
485 SquareDim = LastEffectChangedBase + LastEffectChangedSize,
493 const double *w,
Square position)
const
497 return w[offset + basic];
502 for (
size_t i=0; i<cache.size() && cache[i] >= 0; ++i)
503 sum += w[offset + cache[i]];
506 static void updateCache(
StateInfo& info);
511 template<
bool TestPromotable>
517 PromotionSize = TestPromotable ? 3 : 1,
518 DIM = PromotionSize * OneDim,
528 int basic = ptype*PatternCacheSize;
536 int dy = info.
player ==
BLACK ? black_dy : -black_dy;
540 sum += addOne(state, offset+basic, w, target);
542 sum += addOne(state, offset+basic_from, w, target);
545 target = to + Offset(-dx, dy);
547 sum += addOne(state, offset+basic, w, target);
549 sum += addOne(state, offset+basic_from, w, target);
552 static std::string
name(
int x,
int y)
554 return std::string(
"Pattern")
555 + (TestPromotable ?
"P" :
"")
556 +
"X" + (
char)(
'2'+x) +
"Y"+(
char)(
'2'+y);
572 mask_t p = state.longEffectAt<
LANCE>(position, player);
574 return state.hasEffectAt(player, state.pieceOf(p.takeOneBit()+offset).square());
575 p = state.longEffectAt<
BISHOP>(position, player);
577 return 2 + state.hasEffectAt(player, state.pieceOf(p.takeOneBit()+offset).square());
578 p = state.longEffectAt<
ROOK>(position, player);
580 return 4 + state.hasEffectAt(player, state.pieceOf(p.takeOneBit()+offset).square());
588 const int me = longPtype(*state.
state, from, move.
player);
609 + w[offset + move.
ptype()*PTYPE_SIZE+attack.
ptype()];
644 EFFECT_DIM = PTYPE_SIZE*2*8*9,
645 BasicSize = PTYPE2_DIM+EFFECT_DIM,
646 PawnSize = BasicSize*3,
655 const int dy = (player ==
BLACK) ? -1 : 1;
658 Piece piece = state.pieceAt(position);
662 piece = state.pieceAt(position + Offset(0, dy));
665 return std::make_pair(u, uu);
673 const std::pair<int,int> u = squareStatus(*state.
state, player, to, front);
680 offset += BasicSize*promotion;
683 const int index0 = (u.first*
PTYPE_SIZE*2+u.second)*2 + pawn_drop;
684 double sum = w[offset + index0];
688 sum += w[offset + index1*9+effect];
694 return matchPtype(state, move, offset, w);
697 return matchPtype(state, move, offset+PawnSize, w);
709 LongAttackSize = BasicAttack * OptionSize,
719 if (ptype ==
LANCE) index = 0;
720 else if (ptype ==
BISHOP) index = 1;
721 else if (ptype ==
ROOK) index = 2;
730 Square to,
const double *w,
int offset)
732 assert(state.
state->hasEffectByPiece(piece, to));
738 BOOST_FOREACH(
int index, cache) {
739 assert(index < LongAttackSize);
740 sum += w[index+offset];
746 return (moved*2 + has_support) * LongAttackSize;
756 sum += addPiece(state, piece, target, w, offset);
758 m = state.
state->longEffectAt(target,
alt(P));
762 sum += addPiece(state, piece, target, w, offset);
770 int a = state.
state->countEffect(P, target);
771 offset += ptypeSupport(move.
ptype(), a+move.
isDrop()>1);
772 return findAll(state, P, target, w, offset);
776 return findAll(state, move.
move, w, offset);
780 static void makeLongAttackOne(
StateInfo& info,
802 return findAll(state, move.
move, w, offset);
818 const NumEffectState& state = *info.
state;
821 int d = state.countEffect(
alt(move.
player), to);
824 && state.hasEffectByPiece(state.kingPiece(
alt(move.
player)), to))) {
828 const Piece opponent = state.findCheapAttack(
alt(move.
player), to);
849 while (state.
state->pieceAt(to).isEmpty())
852 if (! state.
state->pieceAt(to).isPiece())
863 directions &= directions-1;
864 sum += addOne(d, state, move, offset, w);
865 }
while (directions);
874 DIM = PatternCacheSize*(8+4+4+1)
887 while (state.
state->pieceAt(target).isEmpty())
889 if (state.
state->pieceAt(target).isOnBoardByOwner(move.
player)) {
891 if (state.
state->pieceAt(target).ptype() ==
LANCE) {
892 while (state.
state->pieceAt(target).isEmpty())
896 if (state.
state->pieceAt(target).isEdge())
903 int dx1 = abs(state.
state->kingSquare(move.
player).x()-x);
908 assert(! state.
state->pieceAt(target).isEdge());
912 for (
size_t i=0; i<cache.size() && cache[i] >= 0; ++i) {
913 sum += w[offset + y*PatternCacheSize + cache[i]];
914 sum += w[offset + (8+dx1)*PatternCacheSize + cache[i]];
915 sum += w[offset + (12+dx1)*PatternCacheSize + cache[i]];
917 sum += w[offset + 16*PatternCacheSize + cache[i]];
927 DIM = PatternCacheSize*2
934 int offset,
const double *w)
940 for (
size_t i=0; i<cache.size() && cache[i] >= 0; ++i) {
941 sum += w[offset + type + cache[i]];
945 template <Direction D,Ptype Type>
948 int offset,
const double *w)
950 const NumEffectState& state = *info.
state;
954 if (state.pieceAt(target).isEdge())
956 if (state.pieceAt(target).isPiece()
957 && (state.pieceAt(target).ptype() != Type
958 || state.pieceAt(target).owner() != state.turn())) {
961 while (state.pieceAt(target).isEmpty())
963 if (state.pieceAt(target).ptype() == Type
964 && state.pieceAt(target).owner() == state.turn()) {
967 while (state.pieceAt(target).isEmpty())
970 if (state.pieceAt(target).isEdge())
972 sum += addSquare(target, info, offset, w);
973 if (! state.pieceAt(target).isPiece())
978 if (state.pieceAt(target).isEdge())
980 while (state.pieceAt(target).isEmpty())
982 if (state.pieceAt(target).isEdge())
984 sum += addSquare(target, info, offset+PatternCacheSize, w);
992 sum += addOne<UR,BISHOP>(state, move.
move.
to(), offset, w);
993 sum += addOne<UL,BISHOP>(state, move.
move.
to(), offset, w);
994 sum += addOne<DR,BISHOP>(state, move.
move.
to(), offset, w);
995 sum += addOne<DL,BISHOP>(state, move.
move.
to(), offset, w);
1004 DIM = DirectionSize*3
1015 sum += BishopAttack::addOne<R,ROOK>(state, to, offset, w);
1016 sum += BishopAttack::addOne<L,ROOK>(state, to, offset, w);
1017 const bool pawn_drop = state.state->canDropPawnTo(
alt(move.
player), to.x());
1018 const int scale = pawn_drop ? 1 : 2;
1019 sum += BishopAttack::addOne<U,ROOK>(state, to, offset+DirectionSize*scale, w);
1020 sum += BishopAttack::addOne<D,ROOK>(state, to, offset+DirectionSize*scale, w);
1030 OpenRoadSize =
PTYPE_SIZE * PatternCacheSize, OpenRoadBase = AddEffectSize,
1031 KingMoveSize = PatternCacheSize, KingMoveBase = OpenRoadBase + OpenRoadSize,
1033 AddEffect8Size = PTYPE_SIZE*PatternCacheSize, AddEffect8Base = CaptureBase + CaptureSize,
1034 OtherMoveSize = 1, OtherMoveBase = AddEffect8Base + AddEffect8Size,
1035 DIM = OtherMoveBase + OtherMoveSize
1050 const NumEffectState& state)
1052 if (move.
to() == threatmate.
to()
1053 || state.hasEffectIf(move.
ptypeO(), move.
to(),
1060 if (! effect.hasEffect())
1062 if (effect.offset() == threatmate.
to()-threatmate.
from())
1063 return state.isEmptyBetween(threatmate.
from(), move.
to());
1067 const NumEffectState& state)
1070 (state, move.
ptypeO(), move.
to(), king))
1072 mask_t m = state.longEffectAt(move.
to(),
alt(state.turn()));
1074 const Piece piece = state.pieceOf
1086 const NumEffectState& state = *info.
state;
1091 if (isKingMove(move.
move)) {
1093 sum += w[offset + KingMoveBase + PatternAny];
1094 for (
size_t i=0; i<cache.size() && cache[i] >= 0; ++i) {
1095 sum += w[offset + KingMoveBase + cache[i]];
1099 if (isOpeningKingRoad(move.
move, king)) {
1101 int base = OpenRoadBase + move.
move.
ptype()*PatternCacheSize;
1102 sum += w[offset + base + PatternAny];
1103 for (
size_t i=0; i<cache.size() && cache[i] >= 0; ++i) {
1104 sum += w[offset + base + cache[i]];
1110 int base = move.
move.
ptype()*PatternCacheSize;
1111 sum += w[offset + base + PatternAny];
1112 for (
size_t i=0; i<cache.size() && cache[i] >= 0; ++i) {
1113 sum += w[offset + base + cache[i]];
1115 }
else if (isDefendingKing8(move.
move, king, state)) {
1117 int base = move.
move.
ptype()*PatternCacheSize
1119 sum += w[offset + base + PatternAny];
1120 for (
size_t i=0; i<cache.size() && cache[i] >= 0; ++i) {
1121 sum += w[offset + base + cache[i]];
1129 sum += w[offset + CaptureBase
1131 sum += w[offset + CaptureBase
1141 sum += w[offset + OtherMoveBase];
1173 static double match(
const NumEffectState& state,
Move move,
int see,
1175 int offset,
const double *w)
1177 const Square to = move.
to(), king = state.kingSquare(
alt(state.turn()));
1182 if (to != defense.
attack)
1187 offset += ATTACK_DIM;
1189 offset += ATTACK_DIM*2;
1198 sum += w[offset+1] * see/1024.0;
1199 sum += w[offset + a];
1200 sum += w[offset + b];
1201 sum += w[offset + c];
1202 sum += w[offset + a + b];
1203 sum += w[offset + a + c];
1204 sum += w[offset + b + c];
1210 sum += w[offset + a +
KING];
1211 sum += w[offset + b +
KING];
1213 sum += w[offset + a + b + c];
1236 if (info.
state->inCheck() || move.
see > -256)
1247 if (hasSafeCapture(info.
copy, move.
move))
1252 sum += w[offset + ptype_index + capture_index];
1253 sum += w[offset + capture_index];
1258 static bool hasSafeCapture(NumEffectState& state,
Move);
1302 if (state.
state->pieceAt(front).ptype() !=
PAWN)
1304 int king_x = abs(state.
state->kingSquare(
alt(info.
player)).x() - front.
x());
1308 stand_pawn =
std::min(2, stand_pawn);
1315 int index = (king_x * 3 + stand_pawn) * 2 + has_other;
1316 return w[offset + index];
1324 DIM = 9 * 3 * 2 * 2,
1334 int to_x = move.
to().
x();
1337 || last_move.
to().
x() != to_x
1338 || last_move.
from().
x() != to_x)
1344 int king_x = abs(state.
state->kingSquare(
alt(info.
player)).x() - to_x);
1353 int index = ((king_x * 3 + stand_pawn) * 2 + has_other) * 2 + follow_pawn_capture;
1354 return w[offset + index];
1376 const Square front = last_move.
to()-diff, front2 = front-diff;
1377 if (si.
state->pieceOnBoard(front).ptype() !=
PAWN
1380 const bool cover = si.
state->hasEffectIf
1383 threatened = si.
state->pieceAt(front2).ptype();
1387 const int ptype_index = moved*
PTYPE_SIZE+threatened;
1390 const int effect_index = (a*3+b)*2*PTYPE_SIZE*PTYPE_SIZE
1391 + (has_pawn ? pawn_index : 0);
1392 assert(effect_index >= 0);
1393 return w[offset + threatened]
1394 + w[offset + ptype_index]
1395 + w[offset + effect_index + ptype_index];
1418 double sum = w[offset + index];
1419 if (si.
history->hasLastMove(2)) {
1423 (*si.
state, my_last_move.
ptypeO(), my_last_move.
to(), king))
1424 sum += w[offset + index + 1];
1442 int dx = center.
x() - to.
x();
1443 const int dy = center.
y() - to.
y();
1444 if (abs(dx) >= 3 || abs(dy) >= 3)
1446 if ((king ==
BLACK && center.
x() > 5)
1447 || (king ==
WHITE && center.
x() >= 5))
1449 int sq_index = (dx+2)*5 + dy+2;
1455 return w[offset + index];
1461 + addOne(
alt(mi.player), si.
state->kingSquare(
alt(mi.player)), si, mi,
1470 BlockLastOne = 0, BlockFront = 1,
1471 BlockSideWide = 2, BlockSideOther = 3, BlockBack = 4,
1472 DIM = 5 * StandCount
1478 const NumEffectState& state,
1479 const CArray<Direction,3>& directions)
1482 BOOST_FOREACH(
Direction d, directions) {
1483 if ((ki.
liberty() & (1<<d)) == 0)
1487 if (! state.hasEffectIf(move.
ptypeO(), move.
to(), sq))
1494 const NumEffectState& state = *si.
state;
1510 sum += w[offset+BlockLastOne];
1513 const CArray<Direction,3> front3 = {{
UL,
U,
UR }};
1514 if (blockAll(ki, king, mi.
move, state, front3))
1515 sum += w[offset+BlockFront];
1516 const CArray<Direction,3> left3 = {{
UL,
L,
DL }};
1517 if (blockAll(ki, king, mi.
move, state, left3)) {
1520 sum += w[offset+(wide ? BlockSideWide : BlockSideOther)];
1522 const CArray<Direction,3> right3 = {{
UR,
R,
DR }};
1523 if (blockAll(ki, king, mi.
move, state, right3)) {
1526 sum += w[offset+ (wide ? BlockSideWide : BlockSideOther)];
1528 const CArray<Direction,3> back3 = {{
DL,
D,
DR }};
1529 if (blockAll(ki, king, mi.
move, state, back3))
1530 sum += w[offset+BlockBack];
1545 if (state.countEffect(
alt(state.turn()), target) > 1)
1549 Piece attacking = state.findCheapAttack(
alt(state.turn()), target);
1554 return state.countEffect(state.turn(), move.
to()) >= (1-move.
isDrop());
1558 const NumEffectState& state = *si.
state;
1559 PieceMask attacked = state.piecesOnBoard(mi.
player)
1561 & ~(state.effectedMask(mi.
player));
1562 attacked.clearBit<
PAWN>();
1565 while (attacked.any()) {
1566 Piece a = state.pieceOf(attacked.takeOneBit());
1570 PieceMask copy = attacked;
1571 while (copy.any()) {
1572 Piece b = state.pieceOf(copy.takeOneBit());
1576 sum += w[offset+index_a];
1577 sum += w[offset+b.
ptype()];
1578 sum += w[offset+index_a+b.
ptype()];
1604 sum += w[offset+1] * mi.
see/1024.0;
1625 || si.
state->inCheck()
1628 const NumEffectState& state = *si.
state;
1629 mask_t m = state.longEffectAt(move.
from(), state.turn());
1633 const Piece piece = state.pieceOf
1641 bool can_promote =
false;
1643 if (to == move.
to())
1645 while (state[to].isEmpty()) {
1647 && ! state.hasEffectAt(
alt(mi.
player), to))
1651 assert(state[to] != piece);
1657 && state[to].isOnBoardByOwner(
alt(mi.
player))
1658 && ! state.hasEffectAt(
alt(mi.
player), to)) {
1660 sum += w[offset+1]*mi.
see/1024.0;
1668 if (state.hasEffectIf(piece.
ptypeO(), to,
1671 sum += w[offset + index + state[to].ptype()];
1673 else if (can_promote) {
1675 sum += w[offset+1]*mi.
see/1024.0;
1683 sum += w[offset + index];
1701 const NumEffectState& state = *si.
state;
1706 || ! target.
isPiece() || state.inCheck()
1712 const int t1 = t0 + state.findCheapAttack(
alt(mi.
player), target.
square()).ptype()*2*PTYPE_SIZE*3;
1713 const int t2 = t1 + state.hasEffectAt(mi.
player, target.
square())*PTYPE_SIZE*3;
1716 sum += w[offset + t0];
1717 sum += w[offset + t1];
1718 sum += w[offset + t2];
1721 if (state.hasEffectIf(move.
ptypeO(), move.
to(),
1726 sum += w[offset + t0 + move.
ptype()];
1727 sum += w[offset + t1 + move.
ptype()];
1728 sum += w[offset + t2 + move.
ptype()];
1735 offset += PTYPE_SIZE;
1736 sum += w[offset + t0 + move.
ptype()];
1737 sum += w[offset + t1 + move.
ptype()];
1738 sum += w[offset + t2 + move.
ptype()];