135 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			135 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
import Journal from './Journal';
 | 
						|
 | 
						|
const DEFAULT_EPSILON = 0.01;
 | 
						|
 | 
						|
function create_key(steps: number[]): string {
 | 
						|
    return steps.join(':');
 | 
						|
}
 | 
						|
 | 
						|
class Daemon {
 | 
						|
    /**
 | 
						|
     * @type {Number}
 | 
						|
     */
 | 
						|
    base;
 | 
						|
 | 
						|
    /**
 | 
						|
     * @type {Number}
 | 
						|
     */
 | 
						|
    humanCount;
 | 
						|
 | 
						|
    /**
 | 
						|
     * @type {Number}
 | 
						|
     */
 | 
						|
    robotCount;
 | 
						|
 | 
						|
    /**
 | 
						|
     * @type {Number}
 | 
						|
     */
 | 
						|
    epsilon;
 | 
						|
 | 
						|
    /**
 | 
						|
     * @type {Object}
 | 
						|
     */
 | 
						|
    weights = {};
 | 
						|
 | 
						|
    constructor(
 | 
						|
        base: number,
 | 
						|
        humanCount: number,
 | 
						|
        robotCount: number,
 | 
						|
        epsilon: number = DEFAULT_EPSILON
 | 
						|
    ) {
 | 
						|
        this.base = base;
 | 
						|
        this.humanCount = humanCount;
 | 
						|
        this.robotCount = robotCount;
 | 
						|
        this.epsilon = epsilon;
 | 
						|
    }
 | 
						|
 | 
						|
    get power(): number {
 | 
						|
        return this.humanCount + this.robotCount;
 | 
						|
    }
 | 
						|
 | 
						|
    predict(journal: Journal): number {
 | 
						|
        const steps = this._getStepSlice(journal);
 | 
						|
 | 
						|
        const proposals: number[] = [];
 | 
						|
        for (let i = 0; i < this.base; ++i) {
 | 
						|
            const weight = this._getWeight([...steps, i]);
 | 
						|
            proposals.push(weight);
 | 
						|
        }
 | 
						|
 | 
						|
        const maxWeight = Math.max(...proposals);
 | 
						|
 | 
						|
        return proposals.indexOf(maxWeight);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @param {Journal} journal
 | 
						|
     * @param {Number} humanValue
 | 
						|
     */
 | 
						|
    adjust(journal, humanValue) {
 | 
						|
        const steps = this._getStepSlice(journal);
 | 
						|
        const adjustmentWeight = this._getAdjustmentWeight(journal.length);
 | 
						|
        this._adjustWeight([...steps, humanValue], adjustmentWeight);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @param {Journal} journal
 | 
						|
     *
 | 
						|
     * @returns {Number[]}
 | 
						|
     */
 | 
						|
    private _getStepSlice(journal) {
 | 
						|
        return journal.getLastMovements(this.humanCount, this.robotCount);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @param {Number} stepNumber
 | 
						|
     *
 | 
						|
     * @returns {Number}
 | 
						|
     *
 | 
						|
     * @private
 | 
						|
     */
 | 
						|
    private _getAdjustmentWeight(stepNumber) {
 | 
						|
        return Math.pow(1 + this.epsilon, stepNumber);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @param {Number[]} steps
 | 
						|
     *
 | 
						|
     * @returns {Number}
 | 
						|
     *
 | 
						|
     * @private
 | 
						|
     */
 | 
						|
    private _getWeight(steps: number[]): number {
 | 
						|
        const key = create_key(steps);
 | 
						|
        const weight = this.weights[key];
 | 
						|
        return weight as number;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @param {Number[]} steps
 | 
						|
     * @param {Number} value
 | 
						|
     *
 | 
						|
     * @returns {Number}
 | 
						|
     *
 | 
						|
     * @private
 | 
						|
     */
 | 
						|
    private _setWeight(steps, value) {
 | 
						|
        const key = create_key(steps);
 | 
						|
        this.weights[key] = value;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @param {Number[]} steps
 | 
						|
     * @param {Number} weight
 | 
						|
     *
 | 
						|
     * @private
 | 
						|
     */
 | 
						|
    private _adjustWeight(steps, weight) {
 | 
						|
        const currentWeight = this._getWeight(steps);
 | 
						|
        const newWeight = currentWeight + weight;
 | 
						|
        this._setWeight(steps, newWeight);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
export default Daemon;
 |