2

How can I deep copy a map object to another map ? I'm trying to use ES6 method but this return Map(0){} empty object. My first try was send a map object to function and assign this to a new value in this class. But on next() method I'm removing one property from this map and this change map in unit test file

creatureTurnQueue.js

    export default class CreatureTurnQueue {
    constructor() {
        this.creatureMap = new Map();
        this.creatureArray = [];
        this.observersArray = [];
    }
    initQueue(list = {}) {
        this.creatureMap = Object.assign({}, list)
        this.creatureMap = list //<=old method

        list.forEach(val => this.creatureArray.push(val));
    }
    getActiveCreature() {
        let [first] = this.creatureArray.filter(el => el);
        return first;
    }
    next(list = {}) {
        this.creatureMap.delete(this.creatureMap.keys().next().value);
        if (this.creatureMap.size == 0) {

            this.notifyObserver();
            this.initQueue(list);
            return true;
        }
    }
    addObserver(_observer) {
        this.observersArray.push(_observer)
    }
    removeObserver(_observer) {
        this.observersArray.pull(_observer)
    }
    notifyObserver() {
        this.observersArray.forEach(item => item.resetCounterAttack())
    }
}

creatureTurnQueueTest.js

import Creature from "../creature.js";
import CreatureTurnQueue from "../creatureTurnQueue.js";
import Point from './../point';

export default class CreatureTurnQueueTest {
    queueShoulChangeActiveCreature() {
        let creatureTurnQueue = new CreatureTurnQueue();

        let creture1 = new Creature("aaaa", 1, 1, 1, 1);
        let creture2 = new Creature("bbbb", 1, 1, 1, 1);
        let creture3 = new Creature("cccc", 1, 1, 1, 1);

        let point1 = new Point(1, 0)
        let point2 = new Point(2, 0)
        let point3 = new Point(3, 0)

        let creatureMap = new Map();
        creatureMap.set(point1, creture1);
        creatureMap.set(point2, creture2);
        creatureMap.set(point3, creture3);

        creatureTurnQueue.initQueue(creatureMap);
        console.log("~ creatureMap", creatureMap) <= map have 2 elements
        creatureMap.forEach(item => { <= creatureMap return 2 elements becouse this one value is removed
            if (item !== creatureTurnQueue.getActiveCreature()) {
                console.log("~ item", item)
                console.log("~ creatureTurnQueue.getActiveCreature()", creatureTurnQueue.getActiveCreature())
                throw `Exception: => Kolejka nie dziala poprawnie zwracana aktywna creatura jest inna`;
            }
            if (creatureTurnQueue.next(creatureMap)) {
                throw `Exception: => Kolejka nie dziala poprawnie w momecie wywolania funkcji next()`;
            }
        });
    }
}

The rest of a classes point.js

export default class Point {
    constructor(_x, _y) {
        this.x = _x;
        this.y = _y;
    }
}

creature.js

import CreatureStatistics from "./creatureStatistics.js";

export default class Creature {
    constructor(_name, _attack, _armor, _maxHp, _moveRange) {
        this.stats = this.createCreature(_name, _attack, _armor, _maxHp, _moveRange);
        this.stats.currentHp = this.stats.maxHp;
        this.stats.wasCounterAttack = false;
    }
    createCreature(_name, _attack, _armor, _maxHp, _moveRange) {
        return new CreatureStatistics(
            _name || "Smok",
            _attack || 1,
            _armor || 1,
            _maxHp || 100,
            _moveRange || 10
        );
    }
    setDefaultStats() {
        // this.stats.wasCounterAttack == true ? this.stats.wasCounterAttack = false : this.stats.wasCounterAttack = true
        this.stats.currentHp = this.stats.currentHp != undefined ? this.stats.currentHp : this.stats.maxHp;
    }
    // popraw counter atack
    attack(_defender) {
        _defender.setDefaultStats();
        this.setDefaultStats();

        if (_defender.isAlive()) {
            _defender.stats.currentHp = this.calculateDamage(_defender);
            if (_defender.isAlive() && !_defender.stats.wasCounterAttack) {
                _defender.stats.wasCounterAttack = true;
                this.stats.currentHp = _defender.calculateDamage(this);
            }
        }
    }
    calculateDamage(attackedCreature) {
        return attackedCreature.stats.currentHp - this.stats.getAttack() + attackedCreature.stats.getArmor() > attackedCreature.stats.getMaxHp()
            ? attackedCreature.stats.currentHp
            : attackedCreature.stats.currentHp - this.stats.getAttack() + attackedCreature.stats.getArmor();
    }
    isAlive() {
        if (this.stats.currentHp > 0) {
            return true;
        }
    }
    getCurrentHp() {
        return this.stats.currentHp;
    }
    resetCounterAttack() {
        this.stats.wasCounterAttack = false;
    }
    canCounterAttack() {
        return !this.stats.wasCounterAttack
    }

}

creatureStatistics.js

export default class CreatureStatistics {
    constructor(_name, _attack, _armor, _maxHp, _moveRange) {
        this.name = _name;
        this.attack = _attack;
        this.armor = _armor;
        this.maxHp = _maxHp;
        this.moveRange = _moveRange;
    }
    getName() {
        return this.name;
    }
    getAttack() {
        return this.attack;
    }
    getArmor() {
        return this.armor;
    }
    getMaxHp() {
        return this.maxHp;
    }
    getMoveRange() {
        return this.moveRange;
    }
}
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
pawel szewczyk
  • 261
  • 2
  • 11

1 Answers1

2

The map was in fact a reference of the creatureMap from unit test script. Modifying the map inside your class will modify the creatureMap in unit test. You can try to create a new Map and copy over all values:

// Start class CreateTurnQueue
initQueue(list = {}) {
   
   const newMap = new Map();
   
   // Both Object and Map has entries method although the order is different
   const iterator = list.entries();
   
   for(const item of iterator) {
      const [point, creature] = item;
      newMap.set(point, creature);
      this.creatureArray.push(creature);
   }
   this.creatureMap = newMap;
   
}
// End class CreateTurnQueue

Now you don't have a reference to the creatureMap from the unit test script and modify this.creatureMap will not affect the one you passed to the initQueue method as argument.

Abrar Hossain
  • 2,594
  • 8
  • 29
  • 54
  • 2
    No need to make it so complicated, though: `this.creatureMap = new Map(list); this.creatureArray = Array.from(list.values());` – Bergi Dec 01 '20 at 11:20