<commit_before>
import RG from '../rg';

const MEM_NO_ACTORS = Object.freeze([]);

interface ActorsMap {
    enemies?: any[];
    friends?: any[];
    seen?: {[key: string]: any};
}

const NOT_ATTACKED = null;

/* Memory is used by the actor to hold information about enemies, items etc.
 * It's a separate object from decision-making brain.*/
export class Memory {

    protected _actors: ActorsMap;
    protected _enemyTypes: {[key: string]: true};
    protected _communications: any[];
    protected _lastAttackedID: number;

    constructor() {
        this._actors = {};
        this._enemyTypes = {}; // List of enemy types for this actor
        this._communications = [];
        this._lastAttackedID = NOT_ATTACKED;
        // TODO add memory of player closing a door/using stairs
    }

    /* Adds a generic enemy type. */
    addEnemyType(type): void {
        this._enemyTypes[type] = true;
    }

    /* Removes a generic enemy type. */
    removeEnemyType(type): void {
        if (this._enemyTypes[type]) {
            delete this._enemyTypes[type];
        }
    }

    /* Checks if given actor is an enemy. */
    isEnemy(actor): boolean {
        if (this._actors.hasOwnProperty('enemies')) {
            const index = this._actors.enemies.indexOf(actor);
            if (index >= 0) {return true;}
        }
        // Friend overrides generic enemy type
        if (!this.isFriend(actor)) {
            if (this._enemyTypes[actor.getType()]) {
                return true;
            }
            if (actor.isPlayer()) {
                return this._enemyTypes.player;
            }
        }
        return false;
    }

    /* Checks if actor is a friend. */
    isFriend(actor) {
        if (this._actors.hasOwnProperty('friends')) {
            const index = this._actors.friends.indexOf(actor);
            return index >= 0;
        }
        return false;
    }

    /* Adds an actor friend. */
    addFriend(actor) {
        if (this.isEnemy(actor)) {
            this.removeEnemy(actor);
        }
        if (!this._actors.hasOwnProperty('friends')) {
            this._actors.friends = [];
        }
        if (!this.isFriend(actor)) {
            this._actors.friends.push(actor);
        }
    }

    addEnemySeenCell(actor) {
        if (!this._actors.seen) {this._actors.seen = {};}
        this._actors.seen[actor.getID()] = {x: actor.getX(), y: actor.getY(),
            level: actor.getLevel().getID()};
    }

    hasSeen(actor) {
        if (this._actors.seen && this._actors.seen[actor.getID()]) {
            return true;
        }
        return false;
    }

    getLastSeen(actor) {
        if (this._actors.seen[actor.getID()]) {
            return this._actors.seen[actor.getID()];
        }
        return null;
    }

    /* Adds given actor as (personal) enemy. */
    addEnemy(actor) {
        if (!RG.isActor(actor)) {
            const json = JSON.stringify(actor);
            RG.err('Memory', 'addEnemy',
                'Only actors can be added. Got: ' + json);
        }
        if (!this.isEnemy(actor)) {
            if (this.isFriend(actor)) {
                this.removeFriend(actor);
            }
            if (!this._actors.hasOwnProperty('enemies')) {
                this._actors.enemies = [];
            }
            this._actors.enemies.push(actor);
            if (this._communications.length > 0) {
                this._communications = []; // Invalidate communications
            }
        }
    }

    removeEnemy(actor) {
        if (this._actors.hasOwnProperty('enemies')) {
            const index = this._actors.enemies.indexOf(actor);
            if (index >= 0) {
                this._actors.enemies.splice(index, 1);
            }
        }
    }

    removeFriend(actor) {
        if (this._actors.hasOwnProperty('friends')) {
            const index = this._actors.friends.indexOf(actor);
            if (index >= 0) {
                this._actors.friends.splice(index, 1);
            }
        }
    }

    getEnemies() {
        return this._actors.enemies || MEM_NO_ACTORS;
    }

    getFriends() {
        return this._actors.friends || MEM_NO_ACTORS;
    }

    /* Copies memory (mainly friends/enemies) from one actor. Used when another
     * actor is summoned to copy summoner's enemies. */
    copyMemoryFrom(actor) {
        const memory = actor.getBrain().getMemory();
        const enemies = memory.getEnemies().slice();
        this._actors.enemies = enemies;
        const friends = memory.getFriends().slice();
        this._actors.friends = friends;
        this._enemyTypes = Object.assign({}, memory._enemyTypes);
    }

    /* Adds a communication with given actor. */
    addCommunicationWith(actor) {
        if (!this.hasCommunicatedWith(actor)) {
            this._communications.push(actor);
        }
    }

    wasLastAttacked(actor) {
        return this._lastAttackedID === actor.getID();
    }

    /* Sets last attacked actor. This is used to prevent actor from switching
     * target between attacks (which is ineffective to kill anything). */
    setLastAttacked(actor) {<commit_msg>Added types and return types.<commit_after>
import RG from '../rg';
import {ICoordXY} from '../interfaces';

type BaseActor = import('../actor').BaseActor;

const MEM_NO_ACTORS: BaseActor[] = [];

interface ActorsMap {
    enemies?: BaseActor[];
    friends?: BaseActor[];
    seen?: {[key: string]: ICoordXY};
}

const NOT_ATTACKED = null;

/* Memory is used by the actor to hold information about enemies, items etc.
 * It's a separate object from decision-making brain.*/
export class Memory {

    protected _actors: ActorsMap;
    protected _enemyTypes: {[key: string]: true};
    protected _communications: BaseActor[];
    protected _lastAttackedID: number;

    constructor() {
        this._actors = {};
        this._enemyTypes = {}; // List of enemy types for this actor
        this._communications = [];
        this._lastAttackedID = NOT_ATTACKED;
        // TODO add memory of player closing a door/using stairs
    }

    /* Adds a generic enemy type. */
    addEnemyType(type: string): void {
        this._enemyTypes[type] = true;
    }

    /* Removes a generic enemy type. */
    removeEnemyType(type: string): void {
        if (this._enemyTypes[type]) {
            delete this._enemyTypes[type];
        }
    }

    /* Checks if given actor is an enemy. */
    isEnemy(actor: BaseActor): boolean {
        if (this._actors.hasOwnProperty('enemies')) {
            const index = this._actors.enemies.indexOf(actor);
            if (index >= 0) {return true;}
        }
        // Friend overrides generic enemy type
        if (!this.isFriend(actor)) {
            if (this._enemyTypes[actor.getType()]) {
                return true;
            }
            if (actor.isPlayer()) {
                return this._enemyTypes.player;
            }
        }
        return false;
    }

    /* Checks if actor is a friend. */
    isFriend(actor: BaseActor): boolean {
        if (this._actors.hasOwnProperty('friends')) {
            const index = this._actors.friends.indexOf(actor);
            return index >= 0;
        }
        return false;
    }

    /* Adds an actor friend. */
    addFriend(actor: BaseActor): void {
        if (this.isEnemy(actor)) {
            this.removeEnemy(actor);
        }
        if (!this._actors.hasOwnProperty('friends')) {
            this._actors.friends = [];
        }
        if (!this.isFriend(actor)) {
            this._actors.friends.push(actor);
        }
    }

    addEnemySeenCell(actor: BaseActor): void {
        if (!this._actors.seen) {this._actors.seen = {};}
        this._actors.seen[actor.getID()] = {x: actor.getX(), y: actor.getY(),
            level: actor.getLevel().getID()};
    }

    hasSeen(actor: BaseActor): boolean {
        if (this._actors.seen && this._actors.seen[actor.getID()]) {
            return true;
        }
        return false;
    }

    getLastSeen(actor: BaseActor): ICoordXY | null {
        if (this._actors.seen[actor.getID()]) {
            return this._actors.seen[actor.getID()];
        }
        return null;
    }

    /* Adds given actor as (personal) enemy. */
    addEnemy(actor: BaseActor): void {
        if (!RG.isActor(actor)) {
            const json = JSON.stringify(actor);
            RG.err('Memory', 'addEnemy',
                'Only actors can be added. Got: ' + json);
        }
        if (!this.isEnemy(actor)) {
            if (this.isFriend(actor)) {
                this.removeFriend(actor);
            }
            if (!this._actors.hasOwnProperty('enemies')) {
                this._actors.enemies = [];
            }
            this._actors.enemies.push(actor);
            if (this._communications.length > 0) {
                this._communications = []; // Invalidate communications
            }
        }
    }

    removeEnemy(actor: BaseActor): void {
        if (this._actors.hasOwnProperty('enemies')) {
            const index = this._actors.enemies.indexOf(actor);
            if (index >= 0) {
                this._actors.enemies.splice(index, 1);
            }
        }
    }

    removeFriend(actor: BaseActor): void {
        if (this._actors.hasOwnProperty('friends')) {
            const index = this._actors.friends.indexOf(actor);
            if (index >= 0) {
                this._actors.friends.splice(index, 1);
            }
        }
    }

    getEnemyActors(): BaseActor[] {
        return this._actors.enemies || MEM_NO_ACTORS;
    }

    getFriendActors(): BaseActor[] {
        return this._actors.friends || MEM_NO_ACTORS;
    }

    /* Copies memory (mainly friends/enemies) from one actor. Used when another
     * actor is summoned to copy summoner's enemies. */
    copyMemoryFrom(actor: BaseActor): void {
        const memory: Memory = actor.getBrain().getMemory();
        const enemies = memory.getEnemyActors().slice();
        this._actors.enemies = enemies;
        const friends = memory.getFriendActors().slice();
        this._actors.friends = friends;
        this._enemyTypes = Object.assign({}, memory._enemyTypes);
    }

    /* Adds a communication with given actor. */
    addCommunicationWith(actor: BaseActor): void {
        if (!this.hasCommunicatedWith(actor)) {
            this._communications.push(actor);
        }
    }

    wasLastAttacked(actor: BaseActor): boolean {
        return this._lastAttackedID === actor.getID();
    }

    /* Sets last attacked actor. This is used to prevent actor from switching
     * target between attacks (which is ineffective to kill anything). */
    setLastAttacked(actor: BaseActor): void {
{'fraction_non_alphanumeric': 0.12713615023474178, 'fraction_numerical': 0.0013145539906103286, 'mean_word_length': 1.9619021134593992, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5900216', 'n_tokens_mistral': 3193, 'n_tokens_neox': 3016, 'n_words': 700}