0

For context, this is for the classic battleships game.

I have a gameboard grid array like so:

[[null, null, null, null, null],
[null, null, null, null, null],
[null, null, null, null, null],
[null, null, null, null, null],
[null, null, null, null, null]],

I'm attempting to place a ship object in the array. The object consists of some properties, such as the ship's name, it's length and it's index (so that the position the ship is hit can be marked on the ship object). For example, a ship placed on the first row might look like this:

[null, {name: 'boat' , index: 0 }, {name: 'boat' , index: 1 }, null, null]

I want to achieve this using functional programming principles and avoid mutating the array, which is what I'm currently doing (i.e. using for loops and setting array[x][y] = {ship}).

I understand that the best way of achieving this is by using map().

Since the array is 2 dimensional I am nesting two maps together. My function so far looks like this:

const placeShip = (ship, x, y) => {
    if (grid[x][y] !== null) return;
    const newGrid = grid.map((row, indexX) => row.map((element, indexY) => {
      if (indexX === x && indexY === y) {
        {
          name: ship.name,
          index: XXX
        } // how to insert the index position?
      }
    }
    return newGrid
  }

The trouble I am experiencing is twofold. Firstly, I can't figure out how I can correctly insert the ship's index position in the object using the nested map. This was easy enough using for loops as they begin at 0 and end at ship.length.

Secondly, I'm going wrong somewhere and my function is not returning a 2d array with any objects in it, I am just receiving undefined.

Where am I going wrong?

Thanks

12
  • return. That's all. Commented Aug 26, 2021 at 19:46
  • Could you please elaborate? I think I've been staring at this for too long Commented Aug 26, 2021 at 19:47
  • When you say how to insert the index position? it's not clear what index you are referring to. What should that value be? A single number? a array with x, y coords? Commented Aug 26, 2021 at 19:50
  • @LearningPython you aren't returning anything from your inner row .map, so you are going to wind up with a grid of undefineds. Which is also going to cause your conditional check at the beginning to have false positives on subsequent calls. Commented Aug 26, 2021 at 19:51
  • @Mark I am trying to include the index position of the ship's length. Maybe it wasn't clear in the example I give towards the start of my question. Basically, when a hit is placed on the grid and it hits a ship, I need to record on the ship object which position of the ship was hit. E.g. if it was 4 cells long, whether it was hit in the 1st, 2nd, 3rd or 4th part of its length. Does that make sense? Commented Aug 26, 2021 at 19:54

1 Answer 1

1

If you only consider horizontally placed ships, you can check whether a ship appears on a tile like so:

ri === r &&    // The ship sails on the current row
ci >= c &&     // The start of the ship lies left of this column
ci < c + size  // The end of the ship lies right of this column

Then, the index between 0 and shipSize can be calculated using: ci - c

Here's a simplified example:

const grid = Array.from(Array(4), () => Array(4).fill("~~"));

const placeShipH = (r, c, size, name, grid) => grid.map(
  (row, ri) => row.map(
    (col, ci) => ri === r && ci >= c && ci < c + size
      ? `${name}${ci - c + 1}`
      : col
  )
);

const placeShipV = (r, c, size, name, grid) => grid.map(
  (row, ri) => row.map(
    (col, ci) => ci === c && ri >= r && ri < r + size
      ? `${name}${ri - r + 1}`
      : col
  )
);

const gridToString = grid => grid.map(row => row.join(" ")).join("\n");

const afterShipA = placeShipH(1, 1, 2, "A", grid);
const afterShipB = placeShipH(3, 0, 3, "B", afterShipA);
const afterShipC = placeShipV(0, 3, 3, "C", afterShipB)

console.log(gridToString(afterShipC));

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks, this is exactly what I was looking for. I'm going to adapt it for vertical layouts too, which I imagine shouldn't be too hard.
I spoke too soon I think. Are there any considerable changes to the above in order to implement for vertical placement? I'm using (columnIndex === column && rowIndex >= row && rowIndex < row + ship.length) however I seem to be getting infinitely long column ships.
The code you've shown looks good to me... I added the vertical example in the example above and it seems to work. Maybe the .length property is undefined?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.