feature.h
Go to the documentation of this file.
00001 /* feature.h
00002  */
00003 #ifndef OSL_MOVE_PROBABILITY_FEATURE_H
00004 #define OSL_MOVE_PROBABILITY_FEATURE_H
00005 
00006 #include "osl/move_probability/moveInfo.h"
00007 #include "osl/move_probability/stateInfo.h"
00008 #include "osl/effect_util/additionalEffect.h"
00009 #include "osl/effect_util/neighboring8Direct.h"
00010 #include "osl/neighboring8.h"
00011 #include <boost/foreach.hpp>
00012 #include <string>
00013 
00014 namespace osl
00015 {
00016   namespace move_probability
00017   {
00018     class Feature
00019     {
00020       std::string my_name;
00021       int dim;
00022     public:
00023       Feature(std::string n, size_t d) : my_name(n), dim(d)
00024       {
00025         assert(dim > 0);
00026       }
00027       virtual ~Feature();
00028       std::string name() const { return my_name; }
00029       virtual double match(const StateInfo&, const MoveInfo&, int offset, const double *) const=0;
00030       size_t dimension() const { return dim; }
00031 
00032       static int classifyEffect9(const NumEffectState& state, Player player, Square to)
00033       {
00034         const int a = std::min(2, state.countEffect(player, to));
00035         int d = std::min(2,state.countEffect(alt(player), to));
00036         if (a>d)
00037           d += AdditionalEffect::hasEffect(state, to, alt(player));
00038         return a*3 + d;
00039       }
00040     };
00041 
00042     class CheckFeature : public Feature
00043     {
00044     public:
00045       enum { CHECK_CLASS = 4, RELATIVE_Y_CLASS = 3 };
00046       CheckFeature()
00047         : Feature("Check", CHECK_CLASS*PTYPE_SIZE*2*RELATIVE_Y_CLASS)
00048       {
00049       }
00050       static int checkIndex(const MoveInfo& move) 
00051       {
00052         if (move.open_check)
00053           return 3;
00054         return (move.see > 0) ? 0 : ((move.see == 0) ? 1 : 2);
00055       }
00056       static int sign(const NumEffectState& state, Move move,
00057                       Player player)
00058       {
00059         const Square king = state.kingSquare(alt(player));
00060         int ry = (move.to().y() - king.y())*playerToMul(player);
00061         if (ry == 0) return 0;
00062         return ry > 0 ? 1 : -1;
00063       }
00064       double match(const StateInfo& state, const MoveInfo& move, int offset, const double *w) const
00065       {
00066         if (! move.check && ! move.open_check)
00067           return 0;
00068         const Player player = move.player;
00069         int index = sign(*state.state, move.move, player)+1;
00070         index = (index*2 + move.move.isDrop())*PTYPE_SIZE
00071           + move.move.ptype();
00072         index = index*CHECK_CLASS + checkIndex(move);
00073         return w[offset+index];
00074       }
00075     };
00076     class TakeBackFeature : public Feature
00077     {
00078     public:
00079       TakeBackFeature() : Feature("TakeBack", 3)
00080       {
00081       }
00082       double match(const StateInfo& state, const MoveInfo& move, int offset, const double *w) const
00083       {
00084         if (! state.history->hasLastMove()
00085             || state.history->lastMove().to() != move.move.to())
00086           return 0;
00087         int match = 2;
00088         if (move.see >= 0) {
00089           --match;
00090           if (state.history->hasLastMove(2)
00091               && state.history->lastMove(2).to() == move.move.to())
00092             --match;
00093         }
00094         return w[offset + match];
00095       }
00096     };
00097     class SeeFeature : public Feature
00098     {
00099     public:
00100       enum { SeeClass = 23, YClass = 3, ProgressClass = 8 };
00101       SeeFeature() : Feature("SeeFeature", SeeClass*(3+ProgressClass))
00102       {
00103       }
00104       static int seeIndex(int see)
00105       {
00106         int index = see / 128;
00107         if (see > 0) {
00108           index = std::min(10, index);
00109           index += 12;
00110         } else if (see == 0) {
00111           index += 11;
00112         } else {
00113           index += 10;
00114           index = std::max(0, index);
00115         }
00116         return index;
00117       }
00118       double match(const StateInfo& state, const MoveInfo& move, int offset, const double *w) const
00119       {
00120         const int see_index = seeIndex(move.see);
00121         const Player player = move.player;
00122         const Square to = move.move.to();
00123         const int promote_index = to.canPromote(player) 
00124           ? 1 : (to.canPromote(alt(player)) ? 2 : 0);
00125         double sum = w[offset+see_index+promote_index*SeeClass];
00126         int progress_index = YClass + state.progress8();
00127         sum += w[offset+see_index+progress_index*SeeClass];
00128         return sum;
00129       }
00130     };
00131 
00132     class CapturePtype : public Feature
00133     {
00134     public:
00135       CapturePtype() : Feature("CapturePtype", PTYPE_SIZE*PTYPE_SIZE*2*3)
00136       {
00137       }
00138       double match(const StateInfo& state, const MoveInfo& move, int offset, const double *w) const
00139       {
00140         const Ptype captured = move.move.capturePtype();
00141         const Player player = move.player;
00142         int index = (move.move.ptype())*PTYPE_SIZE + captured;
00143         BOOST_STATIC_ASSERT(PTYPE_EDGE == 1);
00144         if (captured != PTYPE_EMPTY
00145             && captured == state.threatened[alt(player)].ptype())
00146           ++index;
00147         if (move.see > 0)
00148           index += PTYPE_SIZE*PTYPE_SIZE;
00149         if (captured != PTYPE_EMPTY)
00150           index += std::min(2, state.state->countPiecesOnStand(player, unpromote(captured)))
00151             * (2*PTYPE_SIZE*PTYPE_SIZE);
00152         return w[offset+index];
00153       }
00154     };
00155 
00156     class ContinueCapture : public Feature
00157     {
00158     public:
00159       ContinueCapture() : Feature("ContinueCapture", 1) {}
00160       double match(const StateInfo& state, const MoveInfo& move, int offset, const double *w) const
00161       {
00162         if (move.move.capturePtype() == PTYPE_EMPTY
00163             || ! state.history->hasLastMove(2)
00164             || state.history->lastMove(2).to() != move.move.from())
00165           return 0;
00166         return w[offset];
00167       }
00168     };
00169 
00171     class DropCaptured : public Feature
00172     {
00173     public:
00174       DropCaptured() : Feature("DropCaptured", PTYPE_SIZE - PTYPE_BASIC_MIN) {}
00175       double match(const StateInfo& state, const MoveInfo& move, int offset, const double *w) const
00176       {
00177         if (! move.move.isDrop()
00178             || ! state.history->hasLastMove(2)
00179             || ! state.history->lastMove(2).isNormal()
00180             || state.history->lastMove(2).capturePtype() != move.move.ptype())
00181           return 0.0;
00182         const size_t index = move.move.ptype() - PTYPE_BASIC_MIN;
00183         assert(index < dimension());      
00184         return w[index + offset];
00185       }
00186     };
00187 
00188     class SquareY : public Feature
00189     {
00190     public:
00191       // PTYPE_SIZE, to [1,9], fromto [-3,3], drop|promote, progress8
00192       enum {
00193         DIM = 9*PTYPE_SIZE*16
00194       };
00195       SquareY() : Feature("SquareY", DIM)
00196       {
00197       }
00198       static int fromTo(Square to, Square from) // [-3,3]
00199       {
00200         return std::max(-3, std::min(to.y() - from.y(), 3));
00201       }
00202       double match(const StateInfo& state, const MoveInfo& info, int offset, const double *w) const
00203       {
00204         const Move move = info.move;
00205         const Player P = info.player;
00206         const Square to = move.to().squareForBlack(P);
00207         size_t index = ((to.y()-1)*PTYPE_SIZE + move.ptype())*16;
00208         assert(index+16 <= dimension());
00209         const int from_to = move.isDrop() ? 0 
00210           : fromTo(to, move.from().squareForBlack(P));
00211         double sum = w[offset + index + from_to + 3];
00212         if (move.isDrop() || move.isPromotion())
00213           sum += w[offset + index + 7];
00214         sum += w[offset + index + state.progress8()+8];
00215         return sum;
00216       }
00217     };
00218 
00219     class SquareX : public Feature
00220     {
00221     public:
00222       // PTYPE_SIZE, to [1,5], fromto [-3,3], drop|promote, progress8
00223       SquareX() : Feature("SquareX", 5*PTYPE_SIZE*16)
00224       {
00225       }
00226       static int fromTo(Square to, Square from) // [-3,3]
00227       {
00228         return std::max(-3, std::min(to.x() - from.x(), 3));
00229       }
00230       double match(const StateInfo& state, const MoveInfo& info, int offset, const double *w) const
00231       {
00232         const Move move = info.move;
00233         int to = move.to().x();
00234         int from_to = move.isDrop() ? 0 : fromTo(move.to(), move.from());
00235         if (to > 5) {
00236           to = 10 - to;
00237           from_to = -from_to;
00238         }
00239         size_t index = ((to-1)*PTYPE_SIZE + move.ptype())*16;
00240         assert(index+16 <= dimension());
00241         double sum = w[offset + index + from_to + 3];
00242         if (move.isDrop() || move.isPromotion())
00243           sum += w[offset + index + 7];
00244         sum += w[offset + index + state.progress8()+8];
00245         return sum;
00246       }
00247     };
00248 
00249     class KingRelativeY : public Feature
00250     {
00251     public:
00252       // PTYPE_SIZE, to [-8,8], fromto [-3,3], drop|promote, progress8
00253       enum { ONE_DIM = 17*PTYPE_SIZE*16 };
00254       KingRelativeY() : Feature("KingRelativeY", ONE_DIM*2)
00255       {
00256       }
00257       double match(const StateInfo& state, const MoveInfo& info, int offset, const double *w) const
00258       {
00259         const Move move = info.move;
00260         const Player P = info.player;
00261         const Ptype ptype = move.ptype();
00262 
00263         const Square to = move.to().squareForBlack(P);
00264         const Square my_king = state.state->kingSquare(P).squareForBlack(P);
00265         const Square op_king = state.state->kingSquare(alt(P)).squareForBlack(P);
00266         const int from_to = move.isDrop() ? 0 
00267           : SquareY::fromTo(to, move.from().squareForBlack(P));
00268 
00269         size_t index = ((to.y()-my_king.y()+8)*PTYPE_SIZE + ptype)*16;
00270         assert(index+16 <= ONE_DIM);
00271         double sum = w[offset + index + from_to + 3];
00272         if (move.isDrop() || move.isPromotion())
00273           sum += w[offset + index + 7];
00274         sum += w[offset + index + state.progress8()+8];
00275 
00276         index = ((to.y()-op_king.y()+8)*PTYPE_SIZE + ptype)*16;
00277         assert(index+16 <= ONE_DIM);
00278         sum += w[offset + ONE_DIM + index + from_to + 3];
00279         if (move.isDrop() || move.isPromotion())
00280           sum += w[offset + ONE_DIM + index + 7];
00281         sum += w[offset + ONE_DIM + index + state.progress8()+8];
00282         return sum;
00283       }
00284     };
00285     class KingRelativeX : public Feature
00286     {
00287     public:
00288       // PTYPE_SIZE, to [0,8], fromto [-3,3], drop|promote, progress8
00289       enum { ONE_DIM = 9*PTYPE_SIZE*16 };
00290       KingRelativeX() : Feature("KingRelativeX", ONE_DIM*2)
00291       {
00292       }
00293       double match(const StateInfo& state, const MoveInfo& info, int offset, const double *w) const
00294       {
00295         const Move move = info.move;
00296         const Player P = info.player;
00297         const Ptype ptype = move.ptype();
00298 
00299         const Square to = move.to();
00300         const Square my_king = state.state->kingSquare(P);
00301         const Square op_king = state.state->kingSquare(alt(P));
00302         const int from_to = move.isDrop() ? 0 
00303           : SquareY::fromTo(to, move.from());
00304         int dx = to.x() - my_king.x(), fx = from_to;
00305         if (dx < 0) {
00306           dx = -dx;
00307           fx = -fx;
00308         }
00309         size_t index = (dx*PTYPE_SIZE + ptype)*16;
00310         assert(index+16 <= ONE_DIM);
00311         double sum = w[offset + index + fx + 3];
00312         if (move.isDrop() || move.isPromotion())
00313           sum += w[offset + index + 7];
00314         sum += w[offset + index + state.progress8()+8];
00315 
00316         dx = to.x() - op_king.x(), fx = from_to;
00317         if (dx < 0) {
00318           dx = -dx;
00319           fx = -fx;
00320         }
00321         index = (dx*PTYPE_SIZE + ptype)*16;
00322         assert(index+16 <= ONE_DIM);
00323         sum += w[offset + ONE_DIM + index + fx + 3];
00324         if (move.isDrop() || move.isPromotion())
00325           sum += w[offset + ONE_DIM + index + 7];
00326         sum += w[offset + ONE_DIM + index + state.progress8()+8];
00327         return sum;
00328       }
00329     };
00330 
00331     class FromEffect : public Feature
00332     {
00333     public:
00334       FromEffect() : Feature("FromEffect", PTYPE_SIZE*PTYPE_SIZE*PTYPE_SIZE)
00335       {
00336       }
00337       double match(const StateInfo& state_info, const MoveInfo& info, int offset, const double *w) const
00338       {
00339         const Move move = info.move;
00340         if (move.isDrop())
00341           return 0;
00342         const NumEffectState& state = *state_info.state;
00343         const Ptype me = move.oldPtype();
00344         const Ptype support = state.findCheapAttack(info.player, move.from()).ptype();
00345         const Ptype attack = state.findCheapAttack(alt(info.player), move.from()).ptype();
00346         const size_t index = (((me * PTYPE_SIZE) + support) * PTYPE_SIZE) + attack;
00347         assert(index < dimension());
00348         return w[index + offset];
00349       }
00350     };
00351 
00352     class ToEffect : public Feature
00353     {
00354     public:
00355       ToEffect() : Feature("ToEffect", PTYPE_SIZE*PTYPE_SIZE*PTYPE_SIZE*PTYPE_SIZE)
00356       {
00357       }
00358       static const Piece find(const NumEffectState& state, 
00359                               Square to, const PieceMask& remove,
00360                               Player player)
00361       {
00362         assert(to.isOnBoard());
00363         PieceMask pieces = state.piecesOnBoard(player)
00364           & state.effectSetAt(to);
00365         pieces &= ~remove;
00366         return state.selectCheapPiece(pieces);
00367       }
00368       static void supportAttack(const NumEffectState& state, 
00369                                 Square to, 
00370                                 const PieceMask& my_pin,
00371                                 const PieceMask& op_pin,
00372                                 Player turn,
00373                                 std::pair<Ptype,Ptype>& out) 
00374       {
00375         out.first  = find(state, to, my_pin, turn).ptype(); // support
00376         out.second = find(state, to, op_pin, alt(turn)).ptype(); // attack
00377       }
00378       static void supportAttack(const StateInfo& info, Square to, Move move,
00379                                 std::pair<Ptype,Ptype>& out)
00380       {
00381         const Player turn = info.state->turn();
00382         if (move.isDrop())
00383           return supportAttack(*(info.state), to, info.pin[turn],
00384                                info.pin[alt(turn)], turn, out);
00385         PieceMask my_pin = info.pin[turn];
00386         my_pin.set(info.state->pieceAt(move.from()).number());
00387         supportAttack(*(info.state), to, my_pin, info.pin[alt(turn)],
00388                       turn, out);
00389       }
00390       static size_t supportAttack(const StateInfo& info, Square to, Move move)
00391       {
00392         std::pair<Ptype,Ptype> pair;
00393         supportAttack(info, to, move, pair);
00394         return pair.first * PTYPE_SIZE + pair.second;
00395       }
00396       double match(const StateInfo& state, const MoveInfo& info, int offset, const double *w) const
00397       {
00398         const Move move = info.move;
00399         const Ptype me = move.ptype(), captured = move.capturePtype();
00400         const size_t position_index = supportAttack(state, move.to(), move);
00401         const size_t index = ((me * PTYPE_SIZE) + captured)
00402           * PTYPE_SIZE * PTYPE_SIZE + position_index;
00403         assert(index < dimension());
00404         return w[index + offset];
00405       }
00406     };
00407 
00408     class FromEffectLong : public Feature
00409     {
00410     public:
00411       FromEffectLong() : Feature("FromEffectLong", PTYPE_SIZE*8*8)
00412       {
00413       }
00414       double match(const StateInfo& state_info, const MoveInfo& info, int offset, const double *w) const
00415       {
00416         const Move move = info.move;
00417         if (move.isDrop())
00418           return 0;
00419         const NumEffectState& state = *state_info.state;
00420         const Ptype ptype = move.oldPtype();
00421         const CArray<bool,3> me = {{
00422             state.longEffectAt<LANCE>(move.from(), info.player).any(),
00423             state.longEffectAt<BISHOP>(move.from(), info.player).any(),
00424             state.longEffectAt<ROOK>(move.from(), info.player).any(),
00425           }};
00426         const CArray<bool,3> op = {{
00427             state.longEffectAt<LANCE>(move.from(), alt(info.player)).any(),
00428             state.longEffectAt<BISHOP>(move.from(), alt(info.player)).any(),
00429             state.longEffectAt<ROOK>(move.from(), alt(info.player)).any(),
00430           }};
00431         size_t index = ptype;
00432         for (int i=0; i<3; ++i) {
00433           index *= 2; index += me[i];
00434           index *= 2; index += op[i];
00435         }
00436         assert(index < dimension());
00437         return w[index + offset];
00438       }
00439     };
00440 
00441     class ToEffectLong : public Feature
00442     {
00443     public:
00444       ToEffectLong() : Feature("ToEffectLong", PTYPE_SIZE*8*8)
00445       {
00446       }
00447       double match(const StateInfo& state_info, const MoveInfo& info, int offset, const double *w) const
00448       {
00449         const Move move = info.move;
00450         const NumEffectState& state = *state_info.state;
00451         const Ptype ptype = move.oldPtype();
00452         NumBitmapEffect effect=state.effectSetAt(move.to());
00453         if (! move.isDrop())
00454           effect.reset(state.pieceOnBoard(move.from()).number()+8);
00455         const CArray<mask_t,3> pieces = {{
00456             effect.selectLong<LANCE>() >> 8, 
00457             effect.selectLong<BISHOP>() >> 8, 
00458             effect.selectLong<ROOK>() >> 8
00459           }};
00460         size_t index = ptype;
00461         for (int i=0; i<3; ++i) {
00462           index *= 2;
00463           index += (pieces[i] & state.piecesOnBoard(info.player).getMask(1)).any();
00464           index *= 2;
00465           index += (pieces[i] & state.piecesOnBoard(alt(info.player)).getMask(1)).any();
00466         }
00467         assert(index < dimension());
00468         return w[index + offset];
00469       }
00470     };
00471 
00472     class PatternCommon : public Feature
00473     {
00474     public:
00475       enum {
00476         SupportSize = PTYPE_SIZE,
00477         AttackSize = PTYPE_SIZE, AttackBase = SupportSize, // 32
00478         EffectSize = 9, EffectBase = AttackBase+AttackSize,
00479         OpKingSize = 4, OpKingBase = EffectBase+EffectSize,
00480         MyKingSize = 3, MyKingBase = OpKingBase+OpKingSize, // 48
00481         PromotionSize = 2, PromotionBase = MyKingBase+MyKingSize,
00482         PinOpenSize = 4, PinOpenBase = PromotionBase + PromotionSize,
00483         LastToSize = 4, LastToBase = PinOpenBase + PinOpenSize,
00484         LastEffectChangedSize = 6, LastEffectChangedBase = LastToBase + LastToSize,
00485         SquareDim = LastEffectChangedBase + LastEffectChangedSize, // 64
00486         PatternCacheSize = PTYPEO_SIZE*SquareDim,
00487         OneDim = PTYPE_SIZE*PatternCacheSize,
00488       };
00489       PatternCommon(const std::string& name, int dim) : Feature(name, dim)
00490       {
00491       }
00492       double addOne(const StateInfo& state, int offset, 
00493                     const double *w, Square position) const
00494       {
00495         if (! position.isOnBoardRegion() || state.state->pieceAt(position).isEdge()) {
00496           size_t basic = ptypeOIndex(PTYPEO_EDGE) *SquareDim;
00497           return w[offset + basic];
00498         } 
00499         const StateInfo::pattern_square_t& cache
00500           = state.pattern_cache[position.index()];
00501         double sum = 0.0;
00502         for (size_t i=0; i<cache.size() && cache[i] >= 0; ++i)
00503           sum += w[offset + cache[i]];
00504         return sum;
00505       }
00506       static void updateCache(StateInfo& info);
00507     private:
00508       static void updateCacheOne(Square target, StateInfo& info);
00509     };
00510 
00511     template<bool TestPromotable>
00512     class PatternBase : public PatternCommon
00513     {
00514       int dx, black_dy;
00515     public:
00516       enum {
00517         PromotionSize = TestPromotable ? 3 : 1,
00518         DIM = PromotionSize * OneDim,
00519       };
00520       PatternBase(int x, int y)
00521         : PatternCommon(name(x,y), DIM), dx(x), black_dy(y)
00522       {
00523       }
00524       double match(const StateInfo& state, const MoveInfo& info, int offset, const double *w) const
00525       {
00526         const Move move = info.move;
00527         const Ptype ptype = move.ptype();
00528         int basic = ptype*PatternCacheSize;
00529         int basic_from = (move.isPromotion() ? PTYPE_EDGE : PTYPE_EMPTY)
00530           *PatternCacheSize;
00531         const Square to = move.to();
00532         if (TestPromotable && to.canPromote(info.player))
00533           offset += OneDim;
00534         else if (TestPromotable && to.canPromote(alt(info.player)))
00535           offset += 2*OneDim;
00536         int dy = info.player == BLACK ? black_dy : -black_dy;
00537         Square target = to + Offset(dx, dy);
00538         double sum = 0.0;
00539         if (move.from() != target)
00540           sum += addOne(state, offset+basic, w, target);
00541         else // move from here
00542           sum += addOne(state, offset+basic_from, w, target);
00543         if (dx == 0) 
00544           return sum;
00545         target = to + Offset(-dx, dy);
00546         if (move.from() != target)
00547           sum += addOne(state, offset+basic, w, target);
00548         else
00549           sum += addOne(state, offset+basic_from, w, target);
00550         return sum;
00551       }
00552       static std::string name(int x, int y)
00553       {
00554         return std::string("Pattern")
00555           + (TestPromotable ? "P" : "")
00556           + "X" + (char)('2'+x) + "Y"+(char)('2'+y);
00557       }
00558     };
00559 
00560     typedef PatternBase<false> Pattern;
00561     typedef PatternBase<true> PatternPromotion;
00562 
00563     class MoveFromOpposingSliders : public Feature
00564     {
00565     public:
00566       MoveFromOpposingSliders() : Feature("MoveFromOpposingSliders", 36*PTYPE_SIZE)
00567       {
00568       }
00569       static int longPtype(const NumEffectState& state, Square position, Player player)
00570       {
00571         const int offset = PtypeFuns<LANCE>::indexNum*32;
00572         mask_t p = state.longEffectAt<LANCE>(position, player);
00573         if (p.any()) 
00574           return state.hasEffectAt(player, state.pieceOf(p.takeOneBit()+offset).square());
00575         p = state.longEffectAt<BISHOP>(position, player);
00576         if (p.any()) 
00577           return 2 + state.hasEffectAt(player, state.pieceOf(p.takeOneBit()+offset).square());
00578         p = state.longEffectAt<ROOK>(position, player);
00579         assert(p.any());
00580         return 4 + state.hasEffectAt(player, state.pieceOf(p.takeOneBit()+offset).square());
00581       }
00582       double match(const StateInfo& state, const MoveInfo& move, int offset, const double *w) const
00583       {
00584         const Square from = move.move.from();
00585         if (from.isPieceStand() 
00586             || ! state.pinByOpposingSliders(state.state->pieceOnBoard(from)))
00587           return 0.0;
00588         const int me = longPtype(*state.state, from, move.player);
00589         const int op = longPtype(*state.state, from, alt(move.player));
00590         return w[offset + (me*6+op)*PTYPE_SIZE+move.move.ptype()];
00591       }
00592     };
00593     class AttackFromOpposingSliders : public Feature
00594     {
00595     public:
00596       AttackFromOpposingSliders() : Feature("AttackFromOpposingSliders", PTYPE_SIZE*PTYPE_SIZE*2)
00597       {
00598       }
00599       double match(const StateInfo& state, const MoveInfo& info, int offset, const double *w) const
00600       {
00601         const Move move = info.move;
00602         const Piece attack = state.state->findCheapAttack(alt(info.player), move.to());
00603         if (! state.pinByOpposingSliders(attack))
00604           return 0.0;
00605         if (state.state->countEffect(alt(info.player), move.to()) == 1)
00606           offset += PTYPE_SIZE*PTYPE_SIZE;
00607         double sum = w[offset + PTYPE_EMPTY*PTYPE_SIZE+attack.ptype()]
00608           + w[offset + move.ptype()*PTYPE_SIZE+PTYPE_EMPTY]
00609           + w[offset + move.ptype()*PTYPE_SIZE+attack.ptype()];
00610         if (info.see < 0)
00611           sum += w[offset + PTYPE_EMPTY*PTYPE_SIZE+PTYPE_EMPTY]*info.see/1024.0;
00612         return sum;
00613       }
00614     };
00615     class AttackToOpposingSliders : public Feature
00616     {
00617     public:
00618       AttackToOpposingSliders() : Feature("AttackToOpposingSliders", PTYPE_SIZE*PTYPE_SIZE*2)
00619       {
00620       }
00621       double match(const StateInfo& state, const MoveInfo& info, int offset, const double *w) const
00622       {
00623         const Move move = info.move;
00624         double sum = 0.0;
00625         BOOST_FOREACH(Piece piece, state.pin_by_opposing_sliders) {
00626           if (! state.state->hasEffectIf(move.ptypeO(), move.to(),
00627                                              piece.square())) 
00628             continue;
00629           int base = (piece.owner() == info.player) ? PTYPE_SIZE*PTYPE_SIZE : 0;
00630           sum += w[offset + base + PTYPE_EMPTY*PTYPE_SIZE+piece.ptype()]
00631             + w[offset + base + move.ptype()*PTYPE_SIZE+PTYPE_EMPTY]
00632             + w[offset + base + move.ptype()*PTYPE_SIZE+piece.ptype()];
00633           if (info.see < 0)
00634             sum += w[offset + base + PTYPE_EMPTY*PTYPE_SIZE+PTYPE_EMPTY]*info.see/1024.0;
00635         }
00636         return sum;
00637       }
00638     };
00639     class PawnAttack : public Feature
00640     {
00641     public:
00642       enum { 
00643         PTYPE2_DIM = PTYPE_SIZE*2*PTYPE_SIZE*2*2,
00644         EFFECT_DIM = PTYPE_SIZE*2*8*9,
00645         BasicSize = PTYPE2_DIM+EFFECT_DIM,
00646         PawnSize = BasicSize*3,
00647         DIM = PawnSize*2
00648       };
00649       PawnAttack() : Feature("PawnAttack", DIM) 
00650       {
00651       }
00652       std::pair<int,int> squareStatus(const NumEffectState& state, Player player, Square to, Square& front) const
00653       {
00654         int u = 0, uu = 0;
00655         const int dy = (player == BLACK) ? -1 : 1;
00656         Square position = to + Offset(0, dy);
00657         front = position;
00658         Piece piece = state.pieceAt(position);
00659         if (piece.isPiece()) 
00660           u = piece.ptype() + ((piece.owner() == player) ? PTYPE_SIZE : 0);
00661         assert(! piece.isEdge());       // pawn move 
00662         piece = state.pieceAt(position + Offset(0, dy));
00663         if (piece.isPiece()) 
00664           uu = piece.ptype() + ((piece.owner() == player) ? PTYPE_SIZE : 0);
00665         return std::make_pair(u, uu);
00666       } 
00667       double matchPtype(const StateInfo& state, const MoveInfo& move, int offset, const double *w) const
00668       {
00669         const Player player = move.player;
00670         const Square to = move.move.to();
00671 
00672         Square front;
00673         const std::pair<int,int> u = squareStatus(*state.state, player, to, front);
00674 
00675         int promotion = 0;
00676         if (front.canPromote(player))
00677           promotion = 1;
00678         else if (front.canPromote(alt(player)))
00679           promotion = 2;
00680         offset += BasicSize*promotion;
00681 
00682         bool pawn_drop = move.move.isDrop();
00683         const int index0 = (u.first*PTYPE_SIZE*2+u.second)*2 + pawn_drop;
00684         double sum = w[offset + index0];
00685 
00686         const int effect = classifyEffect9(*state.state, player, front);
00687         const int index1 = u.first*8 + move.move.to().squareForBlack(player).y()-2;
00688         sum += w[offset + index1*9+effect];
00689         return sum;
00690       }
00691       double match(const StateInfo& state, const MoveInfo& move, int offset, const double *w) const
00692       {
00693         if (move.move.ptype() == PAWN)
00694           return matchPtype(state, move, offset, w);
00695         if (move.move.ptype() == LANCE
00696             && state.state->canDropPawnTo(move.player, move.move.to().x()))
00697           return matchPtype(state, move, offset+PawnSize, w);
00698         return 0.0;
00699       }
00700     };
00701 
00702     class BlockLong : public Feature
00703     {
00704     public:
00705       enum {
00706         AttackPtype = 8,
00707         BasicAttack = AttackPtype*osl::PTYPEO_SIZE,
00708         OptionSize = 8, // King8, HasSupport, Promotable, Shadowing,...
00709         LongAttackSize = BasicAttack * OptionSize,
00710         DIM = PTYPE_SIZE * 2 * LongAttackSize
00711       };
00712       BlockLong() : Feature("BlockLong", DIM)
00713       {
00714       }
00715       static int longAttackIndex(osl::PtypeO ptypeo) // [0,7]?
00716       {
00717         const Ptype ptype = getPtype(ptypeo);
00718         int index;
00719         if (ptype == LANCE) index = 0;
00720         else if (ptype == BISHOP) index = 1;
00721         else if (ptype == ROOK) index = 2;
00722         else {
00723           assert(ptype == PROOK || ptype == PBISHOP);
00724           index = 3;
00725         }
00726         if (getOwner(ptypeo) == WHITE) index += 4;
00727         return index;
00728       }
00729       static double addPiece(const StateInfo& state, Piece piece,
00730                              Square to, const double *w, int offset)
00731       {
00732         assert(state.state->hasEffectByPiece(piece, to));
00733         const Direction d
00734           = Board_Table.getLongDirection<BLACK>(piece.square(), to);
00735         const StateInfo::long_attack_t&
00736           cache = state.long_attack_cache[piece.number()][longToShort(d)];
00737         double sum = 0.0;
00738         BOOST_FOREACH(int index, cache) {
00739           assert(index < LongAttackSize);
00740           sum += w[index+offset];
00741         }
00742         return sum;
00743       }
00744       static int ptypeSupport(Ptype moved, bool has_support)
00745       {
00746         return (moved*2 + has_support) * LongAttackSize;
00747       }
00748       static double findAll(const StateInfo& state, Player P,
00749                             Square target, const double *w, int offset)
00750       {
00751         mask_t m = state.state->longEffectAt(target, P);
00752         double sum = 0.0;
00753         while (m.any()) {
00754           const Piece piece = state.state->pieceOf
00755             (m.takeOneBit() +PtypeFuns<LANCE>::indexNum*32);
00756           sum += addPiece(state, piece, target, w, offset);
00757         }
00758         m = state.state->longEffectAt(target, alt(P));
00759         while (m.any()) {
00760           const Piece piece = state.state->pieceOf
00761             (m.takeOneBit()+PtypeFuns<LANCE>::indexNum*32);
00762           sum += addPiece(state, piece, target, w, offset);
00763         }
00764         return sum;
00765       }
00766       static double findAll(const StateInfo& state, Move move, const double *w, int offset=0)
00767       {
00768         const Player P = move.player();
00769         Square target = move.to();
00770         int a = state.state->countEffect(P, target);
00771         offset += ptypeSupport(move.ptype(), a+move.isDrop()>1);
00772         return findAll(state, P, target, w, offset);
00773       }
00774       double match(const StateInfo& state, const MoveInfo& move, int offset, const double *w) const
00775       {
00776         return findAll(state, move.move, w, offset);
00777       }
00778       static void updateCache(StateInfo&);
00779     private:
00780       static void makeLongAttackOne(StateInfo& info,
00781                                     Piece piece, Direction d);
00782     };
00783     class BlockLongFrom : public Feature
00784     {
00785     public:
00786       enum {
00787         DIM = BlockLong::LongAttackSize
00788       };
00789       BlockLongFrom() : Feature("BlockLongFrom", DIM)
00790       {
00791       }
00792       static double findAll(const StateInfo& state, Move move, const double *w, int offset=0)
00793       {
00794         const Player P = move.player();
00795         Square target = move.from();
00796         return BlockLong::findAll(state, P, target, w, offset);
00797       }
00798       double match(const StateInfo& state, const MoveInfo& move, int offset, const double *w) const
00799       {
00800         if (move.move.isDrop())
00801           return 0;
00802         return findAll(state, move.move, w, offset);
00803       }
00804     };
00805     class LongRecapture : public Feature
00806     {
00807     public:
00808       enum {
00809         DIM = BlockLong::LongAttackSize * PTYPE_SIZE
00810       };
00811       LongRecapture() : Feature("LongRecapture", DIM)
00812       {
00813       }
00814       double match(const StateInfo& info, const MoveInfo& move, int offset, const double *w) const
00815       {
00816         if (move.see >= 0)
00817           return 0.0;
00818         const NumEffectState& state = *info.state;
00819         const Square to = move.move.to();
00820         int a = state.countEffect(move.player, to)+move.move.isDrop()-1;
00821         int d = state.countEffect(alt(move.player), to);
00822         if (d == 1
00823             || (d == 2 && a > 0
00824                 && state.hasEffectByPiece(state.kingPiece(alt(move.player)), to))) {
00825           double sum = w[offset + (PTYPE_EMPTY)*BlockLong::LongAttackSize]
00826             *move.see/1024.0;
00827           offset += move.move.ptype() * BlockLong::LongAttackSize;
00828           const Piece opponent = state.findCheapAttack(alt(move.player), to);
00829           sum += BlockLong::findAll(info, move.player, opponent.square(), w, offset);
00830           return sum;
00831         }
00832         return 0.0;
00833       }
00834     };
00835     class AddEffectLong : public Feature
00836     {
00837     public:
00838       enum {
00839         DIM = PTYPE_SIZE*BlockLong::LongAttackSize
00840       };
00841       AddEffectLong() : Feature("AddEffectLong", DIM)
00842       {
00843       }
00844       static double addOne(Direction dir, const StateInfo& state, const MoveInfo& move, int offset, const double *w)
00845       {
00846         Offset diff = Board_Table.getOffset(move.player, dir);
00847         Square to = move.move.to() + diff;
00848         if (isLong(dir)) {
00849           while (state.state->pieceAt(to).isEmpty())
00850             to += diff;
00851         }
00852         if (! state.state->pieceAt(to).isPiece())
00853           return 0.0;
00854         return BlockLong::findAll(state, move.player, to, w, offset);
00855       }
00856       double match(const StateInfo& state, const MoveInfo& move, int offset, const double *w) const
00857       {
00858         offset += move.move.ptype()*BlockLong::LongAttackSize;
00859         unsigned int directions = Ptype_Table.getMoveMask(move.move.ptype());
00860         double sum = 0.0;
00861         do {
00862           Direction d = (Direction)(misc::BitOp::bsf(directions));
00863           directions &= directions-1;
00864           sum += addOne(d, state, move, offset, w);
00865         } while (directions);
00866         return sum;
00867       }
00868     };
00869     class LanceAttack : public Feature
00870     {
00871     public:
00872       enum {
00873         PatternCacheSize = PatternCommon::PatternCacheSize,
00874         DIM = PatternCacheSize*(8+4+4+1)
00875       };
00876       LanceAttack() : Feature("LanceAttack", DIM)
00877       {
00878       }
00879       double match(const StateInfo& state, const MoveInfo& move, int offset, const double *w) const
00880       {
00881         if (move.move.ptype() != LANCE 
00882             || (! move.move.isDrop()
00883                 && move.move.capturePtype() == PTYPE_EMPTY))
00884           return 0;
00885         const Offset up = Board_Table.getOffset(move.player, U);
00886         Square target = move.move.to() + up;
00887         while (state.state->pieceAt(target).isEmpty())
00888           target += up;
00889         if (state.state->pieceAt(target).isOnBoardByOwner(move.player)) {
00890           target += up;
00891           if (state.state->pieceAt(target).ptype() == LANCE) {
00892             while (state.state->pieceAt(target).isEmpty())
00893               target += up;
00894           }
00895         }
00896         if (state.state->pieceAt(target).isEdge()) 
00897           target -= up;
00898 
00899         int y = move.move.to().y(), x = move.move.to().x();
00900         if (move.player == WHITE)
00901           y = 10-y;
00902         y -= 2;
00903         int dx1 = abs(state.state->kingSquare(move.player).x()-x);
00904         int dx2 = abs(state.state->kingSquare(alt(move.player)).x()-x);
00905         dx1 = std::min(dx1, 3);
00906         dx2 = std::min(dx2, 3);
00907         bool pawn = state.state->canDropPawnTo(alt(move.player), x);
00908         assert(! state.state->pieceAt(target).isEdge());
00909         const StateInfo::pattern_square_t& cache
00910           = state.pattern_cache[target.index()];
00911         double sum = 0.0;
00912         for (size_t i=0; i<cache.size() && cache[i] >= 0; ++i) {
00913           sum += w[offset + y*PatternCacheSize + cache[i]];
00914           sum += w[offset + (8+dx1)*PatternCacheSize + cache[i]];
00915           sum += w[offset + (12+dx1)*PatternCacheSize + cache[i]];
00916           if (! pawn)
00917             sum += w[offset + 16*PatternCacheSize + cache[i]];
00918         }
00919         return sum;
00920       }
00921     };
00922     class BishopAttack : public Feature
00923     {
00924     public:
00925       enum {
00926         PatternCacheSize = PatternCommon::PatternCacheSize,
00927         DIM = PatternCacheSize*2        // square:2
00928       };
00929       BishopAttack() : Feature("BishopAttack", DIM)
00930       {
00931       }
00932       static double addSquare(Square target, 
00933                               const StateInfo& info,
00934                               int offset, const double *w)
00935       {
00936         int type = 0;
00937         const StateInfo::pattern_square_t& cache
00938           = info.pattern_cache[target.index()];
00939         double sum = 0.0;
00940         for (size_t i=0; i<cache.size() && cache[i] >= 0; ++i) {
00941           sum += w[offset + type + cache[i]];
00942         }
00943         return sum;
00944       }
00945       template <Direction D,Ptype Type>
00946       static
00947       double addOne(const StateInfo& info, Square to, 
00948                     int offset, const double *w)
00949       {
00950         const NumEffectState& state = *info.state;
00951         const Offset diff = DirectionPlayerTraits<D,BLACK>::offset();
00952         Square target = to + diff;
00953         double sum = 0.0;
00954         if (state.pieceAt(target).isEdge())
00955           return sum;
00956         if (state.pieceAt(target).isPiece()
00957             && (state.pieceAt(target).ptype() != Type
00958                 || state.pieceAt(target).owner() != state.turn())) {
00959           ; // almost included in direct pattern
00960         } else {
00961           while (state.pieceAt(target).isEmpty())
00962             target += diff;
00963           if (state.pieceAt(target).ptype() == Type
00964               && state.pieceAt(target).owner() == state.turn()) {
00965             // extend additional effect by the same ptype
00966             target += diff;
00967             while (state.pieceAt(target).isEmpty())
00968               target += diff;
00969           }
00970           if (state.pieceAt(target).isEdge()) 
00971             target -= diff;
00972           sum += addSquare(target, info, offset, w);
00973           if (! state.pieceAt(target).isPiece())
00974             return sum;
00975         }
00976         // shadowing
00977         target += diff;
00978         if (state.pieceAt(target).isEdge())
00979           return sum;
00980         while (state.pieceAt(target).isEmpty())
00981           target += diff;
00982         if (state.pieceAt(target).isEdge()) 
00983           target -= diff;
00984         sum += addSquare(target, info, offset+PatternCacheSize, w);
00985         return sum;
00986       }
00987       double match(const StateInfo& state, const MoveInfo& move, int offset, const double *w) const
00988       {
00989         if (unpromote(move.move.ptype()) != BISHOP)
00990           return 0;
00991         double sum = 0.0;
00992         sum += addOne<UR,BISHOP>(state, move.move.to(), offset, w);
00993         sum += addOne<UL,BISHOP>(state, move.move.to(), offset, w);
00994         sum += addOne<DR,BISHOP>(state, move.move.to(), offset, w);
00995         sum += addOne<DL,BISHOP>(state, move.move.to(), offset, w);
00996         return sum;
00997       }
00998     };
00999     class RookAttack : public Feature
01000     {
01001     public:
01002       enum {
01003         DirectionSize = BishopAttack::DIM,
01004         DIM = DirectionSize*3
01005       };
01006       RookAttack() : Feature("RookAttack", DIM)
01007       {
01008       }
01009       double match(const StateInfo& state, const MoveInfo& move, int offset, const double *w) const
01010       {
01011         if (unpromote(move.move.ptype()) != ROOK)
01012           return 0;
01013         const Square to = move.move.to();
01014         double sum = 0.0;
01015         sum += BishopAttack::addOne<R,ROOK>(state, to, offset, w);
01016         sum += BishopAttack::addOne<L,ROOK>(state, to, offset, w);
01017         const bool pawn_drop = state.state->canDropPawnTo(alt(move.player), to.x());
01018         const int scale = pawn_drop ? 1 : 2;
01019         sum += BishopAttack::addOne<U,ROOK>(state, to, offset+DirectionSize*scale, w);
01020         sum += BishopAttack::addOne<D,ROOK>(state, to, offset+DirectionSize*scale, w);
01021         return sum;
01022       }
01023     };
01024     class BreakThreatmate : public Feature
01025     {
01026     public:
01027       enum {
01028         PatternCacheSize = PatternCommon::PatternCacheSize,
01029         AddEffectSize = PTYPE_SIZE * PatternCacheSize,
01030         OpenRoadSize = PTYPE_SIZE * PatternCacheSize, OpenRoadBase = AddEffectSize,
01031         KingMoveSize = PatternCacheSize, KingMoveBase = OpenRoadBase + OpenRoadSize,
01032         CaptureSize = PTYPE_SIZE*PTYPE_SIZE, CaptureBase = KingMoveBase + KingMoveSize,
01033         AddEffect8Size = PTYPE_SIZE*PatternCacheSize, AddEffect8Base = CaptureBase + CaptureSize,
01034         OtherMoveSize = 1, OtherMoveBase = AddEffect8Base + AddEffect8Size,     // should be penalized
01035         DIM = OtherMoveBase + OtherMoveSize
01036       };
01037       BreakThreatmate() : Feature("BreakThreatmate", DIM)
01038       {
01039       }
01040       static bool isKingMove(Move move) 
01041       {
01042         return move.ptype() == KING;
01043       }
01044       static bool isOpeningKingRoad(Move move, Square king) 
01045       {
01046         return ! move.isDrop()
01047           && Neighboring8::isNeighboring8(move.from(), king);
01048       }
01049       static bool isDefendingThreatmate(Move move, Move threatmate,
01050                                         const NumEffectState& state) 
01051       {
01052         if (move.to() == threatmate.to()
01053             || state.hasEffectIf(move.ptypeO(), move.to(),
01054                                      threatmate.to()))
01055           return true;
01056         if (threatmate.isDrop())
01057           return false;
01058         Offset32 offset32=Offset32(threatmate.from(),move.to());
01059         EffectContent effect=Ptype_Table.getEffect(move.ptypeO(),offset32);
01060         if (! effect.hasEffect())
01061           return false;
01062         if (effect.offset() == threatmate.to()-threatmate.from())
01063           return state.isEmptyBetween(threatmate.from(), move.to());
01064         return false;
01065       }
01066       static bool isDefendingKing8(Move move, Square king,
01067                                    const NumEffectState& state)
01068       {
01069         if (Neighboring8Direct::hasEffect
01070             (state, move.ptypeO(), move.to(), king))
01071           return true;
01072         mask_t m = state.longEffectAt(move.to(), alt(state.turn()));
01073         while (m.any()) {
01074           const Piece piece = state.pieceOf
01075             (m.takeOneBit() +PtypeFuns<LANCE>::indexNum*32);
01076           if (Neighboring8Direct::hasEffect
01077               (state, piece.ptypeO(), piece.square(), king))
01078             return true;
01079         }
01080         return false;
01081       }
01082       double match(const StateInfo& info, const MoveInfo& move, int offset, const double *w) const
01083       {
01084         if (! info.threatmate_move.isNormal())
01085           return 0;
01086         const NumEffectState& state = *info.state;
01087         const StateInfo::pattern_square_t& cache
01088           = info.pattern_cache[move.move.to().index()];
01089         const int PatternAny = ptypeOIndex(PTYPEO_EDGE)*PatternCommon::SquareDim;
01090         double sum = 0.0;
01091         if (isKingMove(move.move)) {
01092           // king move
01093           sum += w[offset + KingMoveBase + PatternAny];
01094           for (size_t i=0; i<cache.size() && cache[i] >= 0; ++i) {
01095             sum += w[offset + KingMoveBase + cache[i]];
01096           }
01097         } else {
01098           const Square king = state.kingSquare(move.player);
01099           if (isOpeningKingRoad(move.move, king)) {
01100             // open king road
01101             int base = OpenRoadBase + move.move.ptype()*PatternCacheSize;
01102             sum += w[offset + base + PatternAny];
01103             for (size_t i=0; i<cache.size() && cache[i] >= 0; ++i) {
01104               sum += w[offset + base + cache[i]];
01105             }
01106           } 
01107           if (isDefendingThreatmate(move.move, info.threatmate_move,
01108                                     state)) {
01109             // add effect to threatmate-move-at
01110             int base = move.move.ptype()*PatternCacheSize;
01111             sum += w[offset + base + PatternAny];
01112             for (size_t i=0; i<cache.size() && cache[i] >= 0; ++i) {
01113               sum += w[offset + base + cache[i]];
01114             }
01115           } else if (isDefendingKing8(move.move, king, state)) {
01116             // add effect to king8
01117             int base = move.move.ptype()*PatternCacheSize
01118               + AddEffect8Base;
01119             sum += w[offset + base + PatternAny];
01120             for (size_t i=0; i<cache.size() && cache[i] >= 0; ++i) {
01121               sum += w[offset + base + cache[i]];
01122             }
01123           }
01124           const Piece captured = state.pieceOnBoard(move.move.to());
01125           // capture
01126           if (captured.isPiece()) {
01127             if (Neighboring8Direct::hasEffect
01128                 (state, captured.ptypeO(), captured.square(), king)) {
01129               sum += w[offset + CaptureBase
01130                        + captured.ptype()*PTYPE_SIZE+move.move.ptype()];
01131               sum += w[offset + CaptureBase
01132                        + captured.ptype()*PTYPE_SIZE];
01133             }
01134             else {
01135               sum += w[offset + CaptureBase + captured.ptype()*PTYPE_SIZE
01136                        + PTYPE_EDGE];
01137             }
01138           }
01139         }
01140         if (sum == 0.0)
01141           sum += w[offset + OtherMoveBase];
01142         return sum;
01143       }
01144     };
01145 
01146     class SendOff : public Feature
01147     {
01148     public:
01149       enum {
01150         DIM = PTYPE_SIZE,
01151       };
01152       SendOff() : Feature("SendOff", DIM)
01153       {
01154       }
01155       double match(const StateInfo& info, const MoveInfo& move, int offset, const double *w) const
01156       {
01157         if (! info.sendoffs.isMember(move.move.to()))
01158           return 0;
01159         return w[offset + move.move.ptype()];
01160       }
01161     };
01162 
01163     class LureDefender : public Feature
01164     {
01165     public:
01166       enum {
01167         ATTACK_DIM = PTYPE_SIZE*PTYPE_SIZE*PTYPE_SIZE,
01168         DIM = ATTACK_DIM*3,
01169       };
01170       LureDefender() : Feature("LureDefender", DIM)
01171       {
01172       }
01173       static double match(const NumEffectState& state, Move move, int see,
01174                           const StateInfo::pinned_gs_t& pinned_list,
01175                           int offset, const double *w)
01176       {
01177         const Square to = move.to(), king = state.kingSquare(alt(state.turn()));
01178         const Offset up = Board_Table.getOffset(state.turn(), U);
01179         const int basic_a = move.ptype() * PTYPE_SIZE*PTYPE_SIZE;
01180         double sum = 0.0;
01181         BOOST_FOREACH(PinnedGeneral defense, pinned_list) {
01182           if (to != defense.attack) 
01183             continue;
01184           assert(defense.general.owner() != move.player());
01185           assert(defense.covered.owner() != move.player());
01186           if (defense.general.square() == move.to()+up)
01187             offset += ATTACK_DIM;
01188           else if (state.hasEffectIf(move.ptypeO(), move.to(), defense.general.square()))
01189             offset += ATTACK_DIM*2;
01190           int a = basic_a;
01191           if (defense.covered.square().canPromote(state.turn())
01192               && canPromote(move.ptype()))
01193             a = promote(move.ptype()) * PTYPE_SIZE*PTYPE_SIZE;
01194           const int b = defense.general.ptype() * PTYPE_SIZE;
01195           const int c = defense.covered.ptype();
01196           sum += w[offset];
01197           if (see < 0)
01198             sum += w[offset+1] * see/1024.0;
01199           sum += w[offset + a];
01200           sum += w[offset + b];
01201           sum += w[offset + c];
01202           sum += w[offset + a + b];
01203           sum += w[offset + a + c];
01204           sum += w[offset + b + c];
01205           if (defense.covered.square().canPromote(state.turn())) {
01206             sum += w[offset + a + PTYPE_EDGE];
01207             sum += w[offset + b + PTYPE_EDGE];
01208           }
01209           if (Neighboring8::isNeighboring8(defense.covered.square(), king)) {
01210             sum += w[offset + a + KING];
01211             sum += w[offset + b + KING];
01212           }
01213           sum += w[offset + a + b + c];
01214           break;
01215         }
01216         return sum;
01217       }
01218       double match(const StateInfo& info, const MoveInfo& move, int offset, const double *w) const
01219       {
01220         return match(*info.state, move.move, move.see,
01221                      info.exchange_pins[alt(move.player)], offset, w);
01222       }
01223     };
01224 
01225     class CheckmateIfCapture : public Feature
01226     {
01227     public:
01228       enum {
01229         DIM = PTYPE_SIZE*PTYPE_SIZE,
01230       };
01231       CheckmateIfCapture() : Feature("CheckmateIfCapture", DIM)
01232       {
01233       }
01234       double match(const StateInfo& info, const MoveInfo& move, int offset, const double *w) const
01235       {
01236         if (info.state->inCheck() || move.see > -256)
01237           return 0;
01238         const Square king = info.state->kingSquare(alt(move.player));
01239         if (move.move.capturePtype() != PTYPE_EMPTY
01240             && ! info.state->hasPieceOnStand<GOLD>(move.player)
01241             && ! info.state->hasPieceOnStand<SILVER>(move.player)
01242             && ! info.move_candidate_exists[alt(move.player)])
01243           return 0;
01244         if (! Neighboring8Direct::hasEffect
01245             (*info.state, move.move.ptypeO(), move.move.to(), king))
01246           return 0;
01247         if (hasSafeCapture(info.copy, move.move))
01248           return 0;
01249         int ptype_index = move.move.ptype()*PTYPE_SIZE;
01250         int capture_index = move.move.capturePtype();
01251         double sum = 0.0;
01252         sum += w[offset + ptype_index + capture_index];
01253         sum += w[offset + capture_index];
01254         sum += w[offset + ptype_index + PTYPE_EDGE];
01255         sum += w[offset + PTYPE_EDGE];
01256         return sum;
01257       }
01258       static bool hasSafeCapture(NumEffectState& state, Move);
01259     };
01260     class AttackKing8Long : public Feature
01261     {
01262     public:
01263       enum {
01264         DIM = PTYPE_SIZE*PTYPE_SIZE,
01265       };
01266       AttackKing8Long() : Feature("AttackKing8Long", DIM)
01267       {
01268       }
01269       double match(const StateInfo& state, const MoveInfo& info, int offset, const double *w) const
01270       {
01271         const Move move = info.move;
01272         double sum = 0.0;
01273         BOOST_FOREACH(Piece piece, state.king8_long_pieces) {
01274           if (! state.state->hasEffectIf(move.ptypeO(), move.to(),
01275                                              piece.square())) 
01276             continue;
01277           sum += w[offset + PTYPE_EMPTY*PTYPE_SIZE+piece.ptype()]
01278             + w[offset + move.ptype()*PTYPE_SIZE+PTYPE_EMPTY]
01279             + w[offset + move.ptype()*PTYPE_SIZE+piece.ptype()];
01280           if (state.pin_by_opposing_sliders.isMember(piece)
01281               && info.see < 0)
01282             sum += w[offset + PTYPE_EMPTY*PTYPE_SIZE+PTYPE_EDGE]*info.see/1024.0;
01283         }
01284         return sum;
01285       }
01286     };
01287     class OpposingPawn : public Feature
01288     {
01289     public:
01290       enum {
01291         DIM = /*king-x*/9 * /* stand-pawn */ 3 * /* others */ 2,
01292       };
01293       OpposingPawn() : Feature("OpposingPawn", DIM)
01294       {
01295       }
01296       double match(const StateInfo& state, const MoveInfo& info, int offset, const double *w) const
01297       {
01298         const Move move = info.move;
01299         if (move.ptype() != PAWN)
01300           return 0.0;
01301         const Square front = move.to() + Board_Table.getOffset(info.player, U);
01302         if (state.state->pieceAt(front).ptype() != PAWN)
01303           return 0.0;
01304         int king_x = abs(state.state->kingSquare(alt(info.player)).x() - front.x());
01305         int stand_pawn = state.state->countPiecesOnStand<PAWN>(info.player);
01306         if (move.isDrop())
01307           --stand_pawn;
01308         stand_pawn = std::min(2, stand_pawn);
01309         bool has_other = state.state->hasPieceOnStand<LANCE>(info.player)
01310           || state.state->hasPieceOnStand<KNIGHT>(info.player)
01311           || state.state->hasPieceOnStand<SILVER>(info.player)
01312           || state.state->hasPieceOnStand<GOLD>(info.player)
01313           || state.state->hasPieceOnStand<ROOK>(info.player)
01314           || state.state->hasPieceOnStand<BISHOP>(info.player);
01315         int index = (king_x * 3 + stand_pawn) * 2 + has_other;
01316         return w[offset + index];
01317       }
01318     };
01319 
01320     class DropAfterOpposingPawn : public Feature
01321     {
01322     public:
01323       enum {
01324         DIM = /*king-x*/9 * /* stand-pawn */ 3 * /* others */ 2 * /* capturepawn */ 2,
01325       };
01326       DropAfterOpposingPawn() : Feature("DropAfterOpposingPawn", DIM)
01327       {
01328       }
01329       double match(const StateInfo& state, const MoveInfo& info, int offset, const double *w) const
01330       {
01331         const Move move = info.move;
01332         if (move.ptype() != PAWN || ! move.isDrop() || ! state.history->hasLastMove())
01333           return 0.0;
01334         int to_x = move.to().x();
01335         const Move last_move = state.history->lastMove();
01336         if (! last_move.isNormal() || last_move.isDrop()
01337             || last_move.to().x() != to_x
01338             || last_move.from().x() != to_x)
01339           return 0.0;
01340       
01341         const Square front = move.to()+Board_Table.getOffset(info.player, U);
01342         if (! front.canPromote(info.player))
01343           return 0.0;
01344         int king_x = abs(state.state->kingSquare(alt(info.player)).x() - to_x);
01345         int stand_pawn = std::min(2, state.state->countPiecesOnStand<PAWN>(info.player)-1);
01346         bool has_other = state.state->hasPieceOnStand<LANCE>(info.player)
01347           || state.state->hasPieceOnStand<KNIGHT>(info.player)
01348           || state.state->hasPieceOnStand<SILVER>(info.player)
01349           || state.state->hasPieceOnStand<GOLD>(info.player)
01350           || state.state->hasPieceOnStand<ROOK>(info.player)
01351           || state.state->hasPieceOnStand<BISHOP>(info.player);
01352         bool follow_pawn_capture = last_move.capturePtype() == PAWN;
01353         int index = ((king_x * 3 + stand_pawn) * 2 + has_other) * 2 + follow_pawn_capture;
01354         return w[offset + index];
01355       }
01356     };
01357 
01358     class CoverPawn : public Feature
01359     {
01360     public:
01361       enum {
01362         DIM = 9 * 2 * PTYPE_SIZE * PTYPE_SIZE
01363       };
01364       CoverPawn() : Feature("CoverPawn", DIM)
01365       {
01366       }
01367       double match(const StateInfo& si, const MoveInfo& mi, int offset, const double *w) const
01368       {
01369         if (! si.history->hasLastMove() || si.state->inCheck()
01370             || mi.move.isCaptureOrPromotion())
01371           return 0.0;
01372         const Move last_move = si.history->lastMove();
01373         if (last_move.ptype() != PAWN)
01374           return 0.0;
01375         const Offset diff = Board_Table.getOffset(mi.player, U);
01376         const Square front = last_move.to()-diff, front2 = front-diff;
01377         if (si.state->pieceOnBoard(front).ptype() != PAWN // must be turn's pawn
01378             || si.state->pieceAt(front2).isOnBoardByOwner(alt(mi.player)))
01379           return 0.0;
01380         const bool cover = si.state->hasEffectIf
01381           (mi.move.ptypeO(), mi.move.to(), front);
01382         const Ptype moved = cover ? mi.move.ptype() : PTYPE_EDGE,
01383           threatened = si.state->pieceAt(front2).ptype();
01384         const int a = std::min(2,si.state->countEffect(alt(mi.player), front) - 1);
01385         assert(a >= 0);
01386         const int b = std::min(2,si.state->countEffect(mi.player, front));
01387         const int ptype_index = moved*PTYPE_SIZE+threatened;
01388         const bool has_pawn = si.state->hasPieceOnStand(alt(mi.player),PAWN);
01389         const int pawn_index = PTYPE_SIZE*PTYPE_SIZE;
01390         const int effect_index = (a*3+b)*2*PTYPE_SIZE*PTYPE_SIZE
01391           + (has_pawn ? pawn_index : 0);
01392         assert(effect_index >= 0);
01393         return w[offset + threatened]
01394           + w[offset + ptype_index]
01395           + w[offset + effect_index + ptype_index];
01396       }
01397     };
01398     class SacrificeAttack : public Feature
01399     {
01400     public:
01401       enum {
01402         StandCount = 64,
01403         DIM = StandCount * PTYPE_SIZE * 2
01404       };
01405       SacrificeAttack() : Feature("SacrificeAttack", DIM)
01406       {
01407       }
01408       double match(const StateInfo& si, const MoveInfo& mi, int offset, const double *w) const
01409       {
01410         const Square king = si.state->kingSquare(alt(mi.player));
01411         if (mi.see >= 0
01412             || (! Neighboring8Direct::hasEffect
01413                 (*si.state, mi.move.ptypeO(), mi.move.to(), king)))
01414           return 0.0;
01415         assert(PieceStand::order[6] == PAWN);
01416         int stand = mi.standIndex(*si.state);
01417         int index = (stand * PTYPE_SIZE + mi.move.ptype()) * 2;
01418         double sum = w[offset + index];
01419         if (si.history->hasLastMove(2)) {
01420           Move my_last_move = si.history->lastMove(2);
01421           if (Neighboring8Direct::hasEffect
01422               (*si.state, my_last_move.ptypeO(), my_last_move.to(), king))
01423             sum += w[offset + index + 1];
01424         }
01425         return sum;
01426       }
01427     };
01428     class King5x5Ptype : public Feature
01429     {
01430     public:
01431       enum {
01432         ONE_DIM = 25 * 4 * PTYPE_SIZE * PTYPE_SIZE,
01433         DIM = 2 * ONE_DIM,
01434       };
01435       King5x5Ptype() : Feature("King5x5Ptype", DIM)
01436       {
01437       }
01438       static double addOne(Player king, Square center, const StateInfo& si, const MoveInfo& mi, int offset, const double *w)
01439       {
01440         const Square to = mi.move.to();
01441         int dx = center.x() - to.x();
01442         const int dy = center.y() - to.y();
01443         if (abs(dx) >= 3 || abs(dy) >= 3)
01444           return 0.0;
01445         if ((king == BLACK && center.x() > 5)
01446             || (king == WHITE && center.x() >= 5))
01447           dx = -dx;
01448         int sq_index = (dx+2)*5 + dy+2;
01449         bool a = mi.move.isDrop() ? si.state->hasEffectAt(mi.player, to)
01450           : si.state->countEffect(mi.player,to) >= 2;
01451         bool d = si.state->hasEffectAt(alt(mi.player), to);
01452         int index = (sq_index*4 + a*2+d) * PTYPE_SIZE*PTYPE_SIZE
01453           + mi.move.capturePtype()*PTYPE_SIZE + mi.move.ptype();
01454         return w[offset + index];
01455       }
01456       double match(const StateInfo& si, const MoveInfo& mi, int offset, const double *w) const
01457       {
01458         return
01459           addOne(mi.player, si.state->kingSquare(mi.player), si, mi, offset, w)
01460           + addOne(alt(mi.player), si.state->kingSquare(alt(mi.player)), si, mi,
01461                    offset+ONE_DIM, w);
01462       }
01463     };
01464     class KingBlockade : public Feature
01465     {
01466     public:
01467       enum {
01468         StandCount = SacrificeAttack::StandCount,
01469         BlockLastOne = 0, BlockFront = 1, 
01470         BlockSideWide = 2, BlockSideOther = 3, BlockBack = 4,
01471         DIM = 5 * StandCount
01472       };
01473       KingBlockade() : Feature("KingBlockade", DIM)
01474       {
01475       }
01476       static bool blockAll(const King8Info& ki, Square king, Move move,
01477                            const NumEffectState& state,
01478                            const CArray<Direction,3>& directions)
01479       {
01480         int liberty = 0;
01481         BOOST_FOREACH(Direction d, directions) {
01482           if ((ki.liberty() & (1<<d)) == 0)
01483             continue;
01484           ++liberty;
01485           const Square sq = king + Board_Table.getOffset(alt(state.turn()), d);
01486           if (! state.hasEffectIf(move.ptypeO(), move.to(), sq))
01487             return false;
01488         }
01489         return liberty > 0;
01490       }
01491       double match(const StateInfo& si, const MoveInfo& mi, int offset, const double *w) const
01492       {
01493         const NumEffectState& state = *si.state;
01494         const King8Info ki = si.king8Info(alt(mi.player));
01495         const Square king = state.kingSquare(alt(mi.player));
01496         if (ki.libertyCount() == 0
01497             || (! Neighboring8Direct::hasEffect
01498                 (state, mi.move.ptypeO(), mi.move.to(), king)))
01499           return 0.0;
01500         int stand = mi.standIndex(state);
01501         offset += stand*5;
01502         double sum = 0.0;
01503         if (ki.libertyCount() == 1) {
01504           const Square sq = king
01505             + Board_Table.getOffset(alt(mi.player),
01506                                     (Direction)misc::BitOp::bsf(ki.liberty()));
01507           if (! state.hasEffectIf(mi.move.ptypeO(), mi.move.to(), sq))
01508             return 0.0;
01509           sum += w[offset+BlockLastOne];
01510           // fall through
01511         }
01512         const CArray<Direction,3> front3 = {{ UL, U, UR }};
01513         if (blockAll(ki, king, mi.move, state, front3))
01514           sum += w[offset+BlockFront];
01515         const CArray<Direction,3> left3 = {{ UL, L, DL }};
01516         if (blockAll(ki, king, mi.move, state, left3)) {
01517           const bool wide = (mi.player== WHITE && king.x() < 5)
01518             || (mi.player== BLACK && king.x() > 5);
01519           sum += w[offset+(wide ? BlockSideWide : BlockSideOther)];
01520         }
01521         const CArray<Direction,3> right3 = {{ UR, R, DR }};
01522         if (blockAll(ki, king, mi.move, state, right3)) {
01523           const bool wide = (mi.player== BLACK && king.x() < 5)
01524             || (mi.player== WHITE && king.x() > 5);
01525           sum += w[offset+ (wide ? BlockSideWide : BlockSideOther)];
01526         }
01527         const CArray<Direction,3> back3 = {{ DL, D, DR }};
01528         if (blockAll(ki, king, mi.move, state, back3))
01529           sum += w[offset+BlockBack];
01530         return sum;
01531       }    
01532     };
01533     class CoverFork : public Feature
01534     {
01535     public:
01536       enum {
01537         DIM = PTYPE_SIZE * PTYPE_SIZE * PTYPE_SIZE
01538       };
01539       CoverFork() : Feature("CoverFork", DIM)
01540       {
01541       }
01542       static bool defending(const NumEffectState& state, Move move, Square target)
01543       {
01544         if (state.countEffect(alt(state.turn()), target) > 1)
01545           return false;
01546         if (state.hasEffectIf(move.ptypeO(), move.to(), target))
01547           return true;
01548         Piece attacking = state.findCheapAttack(alt(state.turn()), target);
01549         Offset o = Board_Table.getShortOffsetNotKnight(Offset32(move.to(), target));
01550         if (o.zero()
01551             || ! Board_Table.isBetween(move.to(), attacking.square(), target))
01552           return false;
01553         return state.countEffect(state.turn(), move.to()) >= (1-move.isDrop());
01554       }
01555       double match(const StateInfo& si, const MoveInfo& mi, int offset, const double *w) const
01556       {
01557         const NumEffectState& state = *si.state;
01558         PieceMask attacked = state.piecesOnBoard(mi.player)
01559           & state.effectedMask(alt(mi.player))
01560           & ~(state.effectedMask(mi.player));
01561         attacked.clearBit<PAWN>();
01562         offset += mi.move.ptype()*PTYPE_SIZE*PTYPE_SIZE;
01563         double sum = 0.0;
01564         while (attacked.any()) {
01565           Piece a = state.pieceOf(attacked.takeOneBit());
01566           if (! defending(state, mi.move, a.square()))
01567             continue;
01568           int index_a = a.ptype()*PTYPE_SIZE;
01569           PieceMask copy = attacked;
01570           while (copy.any()) {
01571             Piece b = state.pieceOf(copy.takeOneBit());
01572             if (! defending(state, mi.move, b.square()))
01573               continue;
01574             sum += w[offset];
01575             sum += w[offset+index_a];
01576             sum += w[offset+b.ptype()];
01577             sum += w[offset+index_a+b.ptype()];
01578           }
01579         }
01580         return sum;
01581       }
01582     };
01583     class ThreatmateByCapture : public Feature
01584     {
01585     public:
01586       enum {
01587         DIM = PTYPE_SIZE * PTYPE_SIZE
01588       };
01589       ThreatmateByCapture() : Feature("ThreatmateByCapture", DIM)
01590       {
01591       }
01592       double match(const StateInfo& si, const MoveInfo& mi, int offset, const double *w) const
01593       {
01594         const Move move = mi.move;
01595         const Ptype captured = move.capturePtype();
01596         if (captured == PTYPE_EMPTY
01597             || (si.possible_threatmate_ptype
01598                 & 1<<(captured-PTYPE_BASIC_MIN)) == 0)
01599           return 0.0;
01600         double sum = 0.0;
01601         sum += w[offset];
01602         if (mi.see < 0)
01603           sum += w[offset+1] * mi.see/1024.0;
01604         sum += w[offset+captured];
01605         sum += w[offset+move.ptype()*PTYPE_SIZE];
01606         sum += w[offset+move.ptype()*PTYPE_SIZE+captured];
01607         return sum;
01608       }
01609     };
01610 
01611     class PromotionBySacrifice : public Feature
01612     {
01613     public:
01614       enum {
01615         DIM = 2*PTYPE_SIZE * PTYPE_SIZE
01616       };
01617       PromotionBySacrifice() : Feature("PromotionBySacrifice", DIM)
01618       {
01619       }
01620       double match(const StateInfo& si, const MoveInfo& mi, int offset, const double *w) const
01621       {
01622         const Move move = mi.move;
01623         if (mi.see >= 0 || move.isDrop()
01624             || si.state->inCheck()
01625             || si.threatmate_move.isNormal())
01626           return 0.0;
01627         const NumEffectState& state = *si.state;
01628         mask_t m = state.longEffectAt(move.from(), state.turn());
01629         m &= ~mask_t::makeDirect(PtypeFuns<LANCE>::indexMask);
01630         double sum = 0.0;
01631         while (m.any()) {
01632           const Piece piece = state.pieceOf
01633             (m.takeOneBit() +PtypeFuns<LANCE>::indexNum*32);
01634           assert(piece.ptype() != LANCE);
01635           if (piece.isPromoted()
01636               || piece.square().canPromote(mi.player))
01637             continue;
01638           Offset o = Board_Table.getShortOffsetNotKnight(Offset32(move.from(), piece.square()));
01639           assert(! o.zero());
01640           bool can_promote = false;
01641           Square to = move.from()+o;
01642           if (to == move.to())
01643             continue;
01644           while (state[to].isEmpty()) {
01645             if (to.canPromote(mi.player)
01646                 && ! state.hasEffectAt(alt(mi.player), to))
01647               can_promote = true;
01648             to += o;
01649           }
01650           assert(state[to] != piece);
01651           int index = 0;
01652           if (piece.ptype() == ROOK)
01653             index += PTYPE_SIZE*PTYPE_SIZE;
01654           index += move.ptype()*PTYPE_SIZE;
01655           if (to.canPromote(mi.player)
01656               && state[to].isOnBoardByOwner(alt(mi.player))
01657               && ! state.hasEffectAt(alt(mi.player), to)) {
01658             sum += w[offset];
01659             sum += w[offset+1]*mi.see/1024.0;
01660             if (mi.check)
01661               sum += w[offset+2];
01662             if (state.hasEffectAt(alt(mi.player), piece.square())) {
01663               sum += w[offset+3];
01664               if (mi.check)
01665                 sum += w[offset+4];
01666             }
01667             if (state.hasEffectIf(piece.ptypeO(), to,
01668                                   state.kingSquare(alt(mi.player))))
01669               sum += w[offset+5];
01670             sum += w[offset + index + state[to].ptype()];
01671           }
01672           else if (can_promote) {
01673             sum += w[offset];
01674             sum += w[offset+1]*mi.see/1024.0;
01675             if (mi.check)
01676               sum += w[offset+2];
01677             if (state.hasEffectAt(alt(mi.player), piece.square())) {
01678               sum += w[offset+3];
01679               if (mi.check)
01680                 sum += w[offset+4];
01681             }
01682             sum += w[offset + index];
01683           }
01684         }
01685         return sum;
01686       }
01687     };
01688 
01689     class EscapeThreatened : public Feature
01690     {
01691     public:
01692       enum {
01693         DIM =(2*PTYPE_SIZE * PTYPE_SIZE) * 3 * PTYPE_SIZE
01694       };
01695       EscapeThreatened() : Feature("EscapeThreatened", DIM)
01696       {
01697       }
01698       double match(const StateInfo& si, const MoveInfo& mi, int offset, const double *w) const
01699       {
01700         const NumEffectState& state = *si.state;
01701         const Move move = mi.move;
01702         const Piece target = si.threatened[mi.player];
01703         if (mi.see > 0 || mi.check || mi.open_check
01704             || ! move.isNormal()
01705             || ! target.isPiece() || state.inCheck()
01706             || si.threatmate_move.isNormal()
01707             || Neighboring8Direct::hasEffect
01708             (state, move.ptypeO(), move.to(), state.kingSquare(alt(mi.player))))
01709           return 0.0;
01710         const int t0 = target.ptype()*PTYPE_SIZE*2*PTYPE_SIZE*3;
01711         const int t1 = t0 + state.findCheapAttack(alt(mi.player), target.square()).ptype()*2*PTYPE_SIZE*3;
01712         const int t2 = t1 + state.hasEffectAt(mi.player, target.square())*PTYPE_SIZE*3;
01713         double sum = 0.0;
01714         if (! move.isDrop() && state[move.from()] == target) {
01715           sum += w[offset + t0];
01716           sum += w[offset + t1];
01717           sum += w[offset + t2];
01718           return sum;
01719         }
01720         if (state.hasEffectIf(move.ptypeO(), move.to(),
01721                               target.square())) {
01722           if (move.isDrop()
01723               || ! state.hasEffectIf(move.oldPtypeO(), move.from(),
01724                                      target.square())) {
01725             sum += w[offset + t0 + move.ptype()];
01726             sum += w[offset + t1 + move.ptype()];
01727             sum += w[offset + t2 + move.ptype()];
01728             return sum;
01729           }
01730         }
01731         // not related move
01732         offset += PTYPE_SIZE;
01733         if (move.isDrop())
01734           offset += PTYPE_SIZE;
01735         sum += w[offset + t0 + move.ptype()];
01736         sum += w[offset + t1 + move.ptype()];
01737         sum += w[offset + t2 + move.ptype()];
01738         return sum;
01739       }
01740     };
01741     class BookMove : public Feature
01742     {
01743     public:
01744       enum {
01745         DIM = 2
01746       };
01747       BookMove() : Feature("BookMove", DIM)
01748       {
01749       }
01750       double match(const StateInfo& si, const MoveInfo& mi, int offset, const double *w) const
01751       {
01752         if (! si.bookmove[0].isNormal())
01753           return 0.0;
01754         if (mi.move == si.bookmove[0] || mi.move == si.bookmove[1])
01755           return w[offset];
01756         return w[offset+1];
01757       }
01758     };
01759   }
01760 }
01761 #endif /* OSL_MOVE_PROBABILITY_FEATURE_H */
01762 // ;;; Local Variables:
01763 // ;;; mode:c++
01764 // ;;; c-basic-offset:2
01765 // ;;; End:
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines