Alejandro Alejandro - 1 month ago 6
Javascript Question

Javascript DRY Pattern - function

New to OO, I am making a game and I have this as my

initialState
:

let initialState = {
grid : null,
player : {
coordinates : null,
health : 100 ,
weapon : "Stick",
expLevel : 1
},
enemies : [],
weapons : [],
items : []
}


when DOM is loaded, I am able to initialize
weapons
and
items
corretly. However, both of these properties share the exact functionality except the object literal that is initialized :

initialState.weapons = placeWeapons(3);
initialState.items = placeItems(2);


where
placeWeapons

function placeWeapons(numberofWeapons){
let weapons = [];
let availableSpots = [];
let placementWeapons = []; //list of coordinates that will place weapons
let grid = initialState.grid;

//collect whats available of coords that are not taken in initialState.occupiedCoordinates
grid.forEach( (row, rowIndex) => (
row.forEach( (cell, colIndex) => {
if (cell === 1){
availableSpots.push([rowIndex,colIndex])
}
})
))

//lets place the weapons. When placed, it will update initialState.occupiedCoordinates
while( placementWeapons.length < numberofWeapons ){
let randCoords = availableSpots[Math.floor(Math.random() * availableSpots.length)];
if (grid[randCoords[0]][randCoords[1]] === 1){
placementWeapons.push(randCoords);
grid[randCoords[0]][randCoords[1]] = 0
}
}
placementWeapons.forEach( coord => {
let weapon = {
name : "Weapon Name",
coords : coord,
damage : 3
}
weapons.push(weapon)
})
return weapons;
}


placeItems

function placeItems(numberofItems){
let items = [];
let availableSpots = [];
let placementItems = []; //list of coordinates that will place items
let grid = initialState.grid;

//collect whats available of coords that are not taken in initialState.occupiedCoordinates
grid.forEach( (row, rowIndex) => (
row.forEach( (cell, colIndex) => {
if (cell === 1){
availableSpots.push([rowIndex,colIndex])
}
})
))

//lets place the items. When placed, it will update initialState.occupiedCoordinates
while( placementItems.length < numberofItems ){
let randCoords = availableSpots[Math.floor(Math.random() * availableSpots.length)];
if (grid[randCoords[0]][randCoords[1]] === 1){
placementItems.push(randCoords);
grid[randCoords[0]][randCoords[1]] = 0
}
}
placementItems.forEach( coord => {
let item = {
name : "Item Name",
coords : coord,
health : 3
}
items.push(item)
})
return items;
}


How can I DRY this pattern?

Answer

The only significant difference I see is the thing being placed. So the logical thing to do is extract that and pass it in as an argument:

// WARNING: Untested code:
function placeThings(thing, numberofThings){
  let things = [];
  let availableSpots = [];
  let placementItems = []; //list of coordinates that will place things
  let grid = initialState.grid;

  //collect whats available of coords that are not taken in initialState.occupiedCoordinates
  grid.forEach( (row, rowIndex) => (
    row.forEach( (cell, colIndex) => {
      if (cell === 1){
        availableSpots.push([rowIndex,colIndex])
      }
    })
  ))

  //lets place the items. When placed, it will update initialState.occupiedCoordinates
  while( placementItems.length < numberofThings ){
    let randCoords = availableSpots[Math.floor(Math.random() * availableSpots.length)];
    if (grid[randCoords[0]][randCoords[1]] === 1){
      placementItems.push(randCoords);
      grid[randCoords[0]][randCoords[1]] = 0
    }
  }
  placementItems.forEach( coord => {
    things.push(Object.create(thing))
  })
  return things;
}

Now you can do:

// Weapons:
placeThings({
  name : "Weapon Name",
  coords : coord,
  damage : 3
},50);

// Items:
placeThings({
  name : "Item Name",
  coords : coord,
  health : 3
},100);

If you want to make the things being placed random you can just pass a function instead of an object:

// WARNING: Untested code:
function placeThings(thingGenerator, numberofThings){
  let things = [];

  /*
   * bla bla..
   */

  placementItems.forEach( coord => {
    things.push(thingGenerator())
  })
  return things;
}

So you'd do something like:

placeThings(makeWeapon, 50);
placeThings(makeItem, 100);
Comments