/*
 
    Texel - A UCI chess engine.
 
    Copyright (C) 2012-2013  Peter Ă–sterlund, peterosterlund2@gmail.com
 
 
 
    This program is free software: you can redistribute it and/or modify
 
    it under the terms of the GNU General Public License as published by
 
    the Free Software Foundation, either version 3 of the License, or
 
    (at your option) any later version.
 
 
 
    This program is distributed in the hope that it will be useful,
 
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
    GNU General Public License for more details.
 
 
 
    You should have received a copy of the GNU General Public License
 
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
*/
 
 
 
/*
 
 * history.hpp
 
 *
 
 *  Created on: Feb 25, 2012
 
 *      Author: petero
 
 */
 
 
 
#ifndef HISTORY_HPP_
 
#define HISTORY_HPP_
 
 
 
#include "piece.hpp"
 
#include "position.hpp"
 
 
 
/**
 
 * Implements the relative history heuristic.
 
 */
 
class History {
 
public:
 
    History();
 
 
 
    /** Clear all history information. */
 
    void init();
 
 
 
    /** Rescale the history counters, so that future updates have more weight. */
 
    void reScale();
 
 
 
    /** Record move as a success. */
 
    void addSuccess(const Position& pos, const Move& m, int depth);
 
 
 
    /** Record move as a failure. */
 
    void addFail(const Position& pos, const Move& m, int depth);
 
 
 
    /** Get a score between 0 and 49, depending of the success/fail ratio of the move. */
 
    int getHistScore(const Position& pos, const Move& m) const;
 
 
 
private:
 
    static int depthWeight(int depth);
 
 
 
    static int depthTable[6];
 
 
 
    struct Entry {
 
        RelaxedShared<int> countSuccess;
 
        RelaxedShared<int> countFail;
 
        mutable RelaxedShared<int> score;
 
    };
 
    Entry ht[Piece::nPieceTypes][64];
 
};
 
 
 
 
 
inline
 
History::History() {
 
    init();
 
}
 
 
 
inline int
 
History::depthWeight(int depth) {
 
    return depthTable[clamp(depth, 0, (int)COUNT_OF(depthTable)-1)];
 
}
 
 
 
inline void
 
History::addSuccess(const Position& pos, const Move& m, int depth) {
 
    int p = pos.getPiece(m.from());
 
    int cnt = depthWeight(depth);
 
    Entry& e = ht[p][m.to()];
 
    int val = e.countSuccess + cnt;
 
    if (val + e.countFail > 1300) {
 
        val /= 2;
 
        e.countFail = e.countFail / 2;
 
    }
 
    e.countSuccess = val;
 
    e.score = -1;
 
}
 
 
 
inline void
 
History::addFail(const Position& pos, const Move& m, int depth) {
 
    int p = pos.getPiece(m.from());
 
    int cnt = depthWeight(depth);
 
    Entry& e = ht[p][m.to()];
 
    int val = e.countFail + cnt;
 
    if (val + e.countSuccess > 1300) {
 
        val /= 2;
 
        e.countSuccess = e.countSuccess / 2;
 
    }
 
    e.countFail = val;
 
    e.score = -1;
 
}
 
 
 
inline int
 
History::getHistScore(const Position& pos, const Move& m) const {
 
    int p = pos.getPiece(m.from());
 
    const Entry& e = ht[p][m.to()];
 
    int ret = e.score;
 
    if (ret >= 0)
 
        return ret;
 
    int succ = e.countSuccess;
 
    int fail = e.countFail;
 
    if (succ + fail > 0) {
 
        ret = succ * 49 / (succ + fail);
 
    } else
 
        ret = 0;
 
    e.score = ret;
 
    return ret;
 
}
 
 
 
#endif /* HISTORY_HPP_ */