/**
* Board module
* @module Board
* @property {Map} occupiedSlots List of occupied slots on the board
* @property {Map} components List of components on the board
* @property {boolean} closed Indicates whether the circuit on the board is closed or not
* @property {Circuit[]} circuits Each item in this array stores a Circuit object
*/
'use strict';
/*
pin index 0 - positive
pin index 1 - negative
*/
/**
* Board
*
* @instance
* @param {number} [width=10] Width of the board - 0 indexed
* @param {number} [height=10] Height of the board - 0 indexed
* @returns {Board}
*
* @example
* let board = Board(100, 100);
*/
let Board = function Board(width = 10, height = 10) {
// Initialise empty board
let board = Array.apply(null, { length: width });
board = board.map(() => {
return Array.apply(null, { length: height });
});
let occupiedSlots = new Map(),
components = new Map();
let closed = false;
let circuits = [];
/**
* Initialise a Slot if it hasn't already been done.
*
* @private
* @method initSlot
* @param {Position} pos e.g. [1,1]
*/
function initSlot(pos){
let [x,y] = pos;
if(!board[x][y]){
board[x][y] = new Slot(pos);
}
}
/**
* Return the slot specified by the position given
*
* @private
* @method getSlot
* @param {Position} pos
* @returns {Slot}
*/
function getSlot(pos){
return board[pos[0]][pos[1]];
}
/**
* Place Component pins into respective Slots <br>
* Uses [Slot#add]{@link module:Slot#add}
*
* @protected
* @instance
* @method place
* @param {Component} component
* @param {Positions[]} positions
* @see Use [Component#place]{@link module:Component#place} method instead
*/
function place(component, positions) {
positions.forEach((position, index) => {
// Initialise to be a Slot if it is not one yet
initSlot(position);
// Add the component to this Slot
getSlot(position).add(component, index);
// Add to occupiedSlots
addOccupiedSlot(position);
});
addComponent(component);
}
/**
* Remove Component from its Slots <br>
* Uses [Slot#remove]{@link module:Slot#remove}
*
* @protected
* @instance
* @method remove
* @param {Component} component
* @see Use [Component#remove]{@link module:Component#remove} method
*/
function remove(component){
component.pins.forEach((position) => {
let slot = getSlot(position);
slot.remove(component);
if(slot.count === 0){
removeOccupiedSlot(position);
}
});
removeComponent(component);
}
/**
* Adds a position to a list of occupied Slots
*
* @private
* @method addOccupiedSlot
* @param {Position} pos
*/
function addOccupiedSlot(pos){
if(!occupiedSlots.has(pos.toString())){
occupiedSlots.set(pos.toString(), board[pos[0]][pos[1]]);
}
}
/**
* Remove position from the list of occupied Slots
*
* @private
* @method removeOccupiedSlot
* @param {Position} pos
*/
function removeOccupiedSlot(pos){
if(occupiedSlots.has(pos.toString())){
occupiedSlots.delete(pos.toString());
}
}
/**
* Add Component to list of components on the Board
*
* @private
* @method addComponent
* @param {Component} component
*/
function addComponent(component){
if(!components.has(component.id)){
components.set(component.id, component);
}
}
/**
* Remove Component from list of components on the Board
*
* @private
* @method removeComponent
* @param {Component} component
*/
function removeComponent(component){
if(components.has(component.id)){
components.delete(component.id, component);
}
}
/**
* Get array of active source Components
*
* @public
* @instance
* @method getActiveSources
* @returns {Components[]}
*/
function getActiveSources(){
let actSources = [];
for(let component of components.values()){
if(component.type === ComponentType.Source && component.active){
actSources.push(component);
}
}
return actSources;
}
/**
* Returns true if any true node has any untraveled components
*
* @public
* @instance
* @method hasUnfinishedNode
* @returns {Boolean}
*/
function hasUnfinishedNode(){
let hasUnfinished = false;
for(let slot of occupiedSlots.values()){
if(slot.isTrueNode && !slot.hasAllTraveled){
hasUnfinished = true;
break;
}
}
return hasUnfinished;
}
/**
* Returns true if Component Type is found on the Board
*
* @public
* @instance
* @method hasType
* @param {ComponentType} type
* @returns {Boolean}
*/
function hasType(type){
let found = false;
for(let component of components.values()){
if(component.type === type){
found = true;
break;
}
}
return found;
}
/**
* Adds given circuit to the array of circuits
*
* @protected
* @instance
* @method addCircuit
* @param {Circuit} circuit
* @see [Circuit]{@link module:Circuit} module
*/
function addCircuit(circuit){
circuits.push(circuit);
}
return {
board: board,
occupiedSlots: occupiedSlots,
components: components,
closed: closed,
get circuits () { return circuits; },
addCircuit: addCircuit,
getSlot: getSlot,
place: place,
remove: remove,
get activeSources() { return getActiveSources(); },
get hasUnfinishedNode() { return hasUnfinishedNode(); },
hasType: hasType
};
};
module.exports = Board;