src_models_parcel.js

import { getPickupScore } from "../utils/misc.js";
import { MapStore } from "./mapStore.js";
import { ServerConfig } from "./serverConfig.js";
import config from "../utils/gameConfig.js"
import { ParcelsStore } from "./parcelsStore.js";


/**
 * Parcel class to represent a parcel in the game
 * @class
 * @description
 * This class is used to represent a parcel in the game.
 * It contains properties such as id, carriedBy, x, y, reward, baseDistance, lastSeen, existingProb, nearestBase,
 * potentialPickUpReward, and potentialPickUpRewardSlave
 * @param {Object} parcel - The parcel object containing id, carriedBy, x, y, reward
 * @param {MapStore} mapStore - The MapStore instance containing the bases
 * @param {number} frame - The current frame number
 * @param {ParcelsStore} parcelStore - The ParcelStore instance managing parcels
 * @property {string} id - The unique identifier of the parcel.
 * @property {string|null} carriedBy - The ID of the agent currently carrying the parcel, or null if not carried.
 * @property {number} x - The x-coordinate of the parcel's position.
 * @property {number} y - The y-coordinate of the parcel's position.
 * @property {number} reward - The reward value of the parcel.
 * @property {number} baseDistance - The distance to the nearest base for this parcel.
 * @property {number} lastSeen - The frame number when the parcel was last seen.
 * @property {number} existingProb - The survival probability of the parcel based on the last seen frame and agent count.
 * @property {{x: number, y: number}|null} nearestBase - The coordinates of the nearest base to the parcel, or null if not applicable.
 * @property {number} potentialPickUpReward - The potential reward for picking up the parcel (for master instance).
 * @property {number} potentialPickUpRewardSlave - The potential reward for picking up the parcel (for slave instance).
 */
export class Parcel {
    constructor(parcel, mapStore, frame, parcelStore) {
        this.id = parcel.id;
        this.carriedBy = parcel.carriedBy;
        this.x = parcel.x;
        this.y = parcel.y;
        this.reward = parcel.reward;

        this.baseDistance = Infinity;

        this.lastSeen = frame;
        this.existingProb = 1;

        
         // @type {{x : number, y : number}}
         
        this.nearestBase = null;

        if (!this.carriedBy) {
            this.calculateNearestBase(mapStore);
        }

        this.potentialPickUpReward = 0; // Reward potenziale per il pickup
        this.potentialPickUpRewardSlave = 0;

    }

   /**
    * calculate the nearest base to this parcel
    * @param {MapStore} mapStore - The MapStore instance containing the bases
    * @description
    * This method calculates the nearest base to the parcel and updates the baseDistance and nearestBase properties.
    * It uses the nearestBase method from the MapStore to find the closest base and its distance.
    * If no base is found, the baseDistance remains Infinity and nearestBase is null.
    * @returns {void}
    */
    calculateNearestBase(mapStore) {
        let [base, minDist] = mapStore.nearestBase(this);

        this.baseDistance = minDist;

        if (base) {
            this.nearestBase = { x: base.x, y: base.y };
        }
    }

    /**
     * Calculate the survival probability of the parcel based on the last seen frame and agent count
     * @param {number} currentFrame - The current frame number
     * @param {number} agentCount - The number of agents in the game
     * @description
     * This method calculates the survival probability of the parcel based on the time since it was last seen and the number of agents.
     * The probability decreases exponentially with time and increases with the number of agents.
     * @example
     * // Example usage:
     * const parcel = new Parcel(parcelData, mapStore, currentFrame, parcelStore);
     * parcel.calculateSurvivalProbability(currentFrame, agentCount);
     */
    calculateSurvivalProbability(currentFrame, agentCount) {
        const seconds = (currentFrame - this.lastSeen) / 20;
        this.existingProb = Math.exp(-config.PARCEL_SURVIVAL_LAMBDA * seconds * agentCount);    // Con 1 agente -> 50% in 10 sec, con 2 50% in 5 sec, ...

    }


    /**
     * Calculate the potential pickup reward for this parcel
     * @param {Object} agentPos - The position of the agent attempting to pick up the parcel
     * @param {boolean} isMaster - Whether the current instance is the master instance
     * @param {number} carriedValue - The total value of parcels currently carried by the agent
     * @param {number} carriedCount - The number of parcels currently carried by the agent
     * @param {MapStore} mapStore - The MapStore instance containing the game map
     * @param {number} clockPenalty - The clock penalty applied to the reward calculation
     * @param {ServerConfig} config - The server configuration settings
     * @description
     * This method calculates the potential pickup reward for a parcel based on its position, carried value, and other parameters.
     * It updates the potentialPickUpReward or potentialPickUpRewardSlave property based on whether it is called from the master or slave instance.
     */
    calculatePotentialPickUpReward(agentPos, isMaster, carriedValue, carriedCount, mapStore, clockPenalty, config) {
        if (this.carriedBy)
            return -Infinity; // Already carried, no reward
        
        const potentialReward = getPickupScore(agentPos, this, carriedValue, carriedCount, this.reward, 1, this.baseDistance, clockPenalty, mapStore, config);

        if (isMaster) {
            this.potentialPickUpReward = potentialReward;
        }
        else {
            this.potentialPickUpRewardSlave = potentialReward;
        }
    }
}