Introduction

Hello, and welcome, code explorer! Today's journey takes us through the intricate paths within a 2-dimensional array, often likened to a game board. Our mission is to identify ideal spots for game piece placement. Sounds like an adventure, doesn't it? Let's embark!

Task Statement

Visualize a chessboard in the form of a 2D array, where each cell could be marked 'E' for empty or 'P' for a piece. Our quest involves summoning a Ruby method named find_positions(). Upon examining this 2D array, this method identifies all the spots where a new piece could be placed so that it can move to another empty cell in one move. The catch is that a piece can move only to an immediately neighboring cell directly above, below, to the left, or right, but not diagonally.

Consider this 4x4 board, for instance:

P E E P
E P E P
P E P P
P E P E

The method should render an output as: [[0, 1], [0, 2], [1, 2], [2, 1], [3, 1]]. This output represents the positions (as arrays of row and column indices) where a new piece can fit perfectly and then be able to move in the next turn.

Solution Building: Step 1

Stepping right into action, we start with an empty positions array to help us log the sought positions. Understanding the dimensions of our 'board' paves the way for defining boundaries in our exploration mission. Now, how does one determine the size of a Ruby array? The answer lies in Ruby's length method.

def find_positions(board)
  positions = []
  rows, cols = board.length, board[0].length
Solution Building: Step 2

With our boundary map, we begin our expedition across the board. We use two nested for loops to do this, traversing the entire board one cell at a time.

def find_positions(board)
  positions = []
  rows, cols = board.length, board[0].length

  for i in 0...rows
    for j in 0...cols
      # ensuing exploration
Solution Building: Step 3

What's the plan for each cell, you ask? While exploring each cell, our trusty Ruby code inspects if the cell is empty. If confirmed, it then peeks into the neighbors in the up, down, left, and right directions. If another vacant cell ('E') is spotted, we jot down the main cell's position in our positions array.

def find_positions(board)
  positions = []
  rows, cols = board.length, board[0].length

  for i in 0...rows
    for j in 0...cols
      if board[i][j] == 'E'
        if ((i > 0 && board[i-1][j] == 'E') || 
            (i < rows - 1 && board[i+1][j] == 'E') || 
            (j > 0 && board[i][j-1] == 'E') || 
            (j < cols - 1 && board[i][j+1] == 'E'))
          positions.push([i, j])
        end
      end
    end
  end
  positions
end

board = [
  ['P', 'E', 'E', 'P'],
  ['E', 'P', 'E', 'P'],
  ['P', 'E', 'P', 'P'],
  ['P', 'E', 'P', 'E']
]

puts find_positions(board).inspect

# Prints [[0, 1], [0, 2], [1, 2], [2, 1], [3, 1]]

For each cell marked 'E', the code checks its neighboring cells using conditional statements:

  • Up (i > 0 && board[i-1][j] == 'E'): Ensures that the row index is greater than 0 before accessing the cell above, avoiding out-of-bound errors.
  • Down (i < rows - 1 && board[i+1][j] == 'E'): Ensures that the row index is within the valid range to access the cell below.
  • Left (j > 0 && board[i][j-1] == 'E'): Ensures the column index is greater than 0 before accessing the cell to the left.
  • Right (j < cols - 1 && board[i][j+1] == 'E'): Ensures the column index is within range to access the cell to the right.
Sign up
Join the 1M+ learners on CodeSignal
Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal