1958. Check if Move Is Legal - Explanation
Prerequisites
Before attempting this problem, you should be comfortable with:
- 2D Arrays/Matrices - Understanding how to navigate and manipulate grid-based data structures
- Direction Vectors - Using coordinate offsets to traverse in 8 directions (horizontal, vertical, diagonal)
- Boundary Checking - Validating array indices to avoid out-of-bounds errors
1. Iteration - I
Intuition
This problem simulates an Othello/Reversi move validation. A move is legal if placing a piece creates a "good line" in any of the 8 directions (horizontal, vertical, or diagonal). A good line starts with the placed piece, has one or more opponent pieces in between, and ends with another piece of the same color. The total length must be at least 3.
Algorithm
- Place the piece of the given color at the specified position on the board.
- Define all 8 possible directions: up, down, left, right, and the 4 diagonals.
- For each direction, check if a valid line can be formed:
- Start from the placed position and move one step in the chosen direction.
- Track the length of the line.
- Continue moving while within bounds and encountering non-empty cells.
- If we hit an empty cell, this direction is invalid.
- If we reach a cell with our color and the total length is at least
3, the line is valid.
- If any direction produces a valid line, return
true. - If no valid line exists in any direction, return
false.
class Solution:
def checkMove(self, board: List[List[str]], rMove: int, cMove: int, color: str) -> bool:
ROWS, COLS = len(board), len(board[0])
direction = [[1, 0], [-1, 0], [0, 1], [0, -1],
[1, 1], [-1, -1], [1, -1], [-1, 1]]
board[rMove][cMove] = color
def legal(row, col, color, direc):
dr, dc = direc
row, col = row + dr, col + dc
length = 1
while 0 <= row < ROWS and 0 <= col < COLS:
length += 1
if board[row][col] == ".":
return False
if board[row][col] == color:
return length >= 3
row, col = row + dr, col + dc
return False
for d in direction:
if legal(rMove, cMove, color, d):
return True
return FalseTime & Space Complexity
- Time complexity:
- Space complexity:
2. Iteration - II
Intuition
This is a more compact implementation of the same logic. Instead of storing directions as pairs, we use a single array where consecutive elements form direction pairs. This reduces memory usage slightly and makes the iteration more streamlined.
Algorithm
- Place the piece of the given color at the specified position.
- Use a compact direction array where
direction[d]anddirection[d+1]represent the row and column deltas for each direction. - Loop through indices
0to8, treating each as a different direction. - For each direction:
- Start from the placed position.
- Move in the direction while tracking the line length.
- Stop if we go out of bounds or hit an empty cell.
- If we reach our own color and have traversed more than one cell (length > 1), return
true.
- If no valid line is found in any direction, return
false.
class Solution:
def checkMove(self, board: List[List[str]], rMove: int, cMove: int, color: str) -> bool:
ROWS, COLS = len(board), len(board[0])
direction = [0, 1, 0, -1, 0, 1, 1, -1, -1, 1]
board[rMove][cMove] = color
for d in range(9):
length = 1
row, col = rMove, cMove
while True:
row += direction[d]
col += direction[d + 1]
if row < 0 or col < 0 or row >= ROWS or col >= COLS or board[row][col] == ".":
break
if board[row][col] == color:
if length > 1:
return True
break
length += 1
return FalseTime & Space Complexity
- Time complexity:
- Space complexity:
Common Pitfalls
Forgetting to Place the Piece Before Checking
The move validation must include the piece being placed at (rMove, cMove). If you forget to set board[rMove][cMove] = color before checking directions, you may incorrectly validate lines that don't actually start with your piece.
# Must place the piece first:
board[rMove][cMove] = colorNot Requiring At Least One Opponent Piece Between
A valid line must have at least one opponent piece between your placed piece and another piece of your color. Checking only that the endpoint matches your color without verifying length >= 3 allows invalid moves where two of your pieces are adjacent.
# Wrong: just checking board[row][col] == color
# Correct:
if board[row][col] == color:
return length >= 3 # Ensures at least one opponent piece in betweenMissing a Direction or Checking Only 4 Directions
There are 8 possible directions (horizontal, vertical, and 4 diagonals). A common mistake is checking only 4 directions (e.g., only cardinal or only diagonal), which misses valid lines in the unchecked directions.