Skip to main content

Matrix Toolbox

🧰 Matrix Toolbox

1. Generate empty grid (N × M)

# N rows, M cols, all None
grid = [[None] * M for _ in range(N)]

If you want zeros instead:

grid = [[0] * M for _ in range(N)]
Python Fundamentals Note

But why isnt this [[[None], [None], [None]],[[None], ...] ]

Python’s * operator on a list doesn’t say “repeat the whole list structure this many times” — it says “repeat the element(s) inside this list”. Think about what would happen if our object was something that could actually be multiplied using *, but we don't want to multiply, rather we want multiple instances of that object.

[4] * 3
# → [4, 4, 4] (we want three 4’s, not [12])

If you just did 4 * 3, Python treats that as integer multiplication → 12. You need the list brackets [] to tell Python “make a list with 4, then repeat that list’s contents 3 times.”


2. Bounds check helper

def in_bounds(r, c, N, M):
return 0 <= r < N and 0 <= c < M

Usage:

if in_bounds(r+dr, c+dc, N, M):
...

3. Neighbor offsets

  • 4-way (up, down, left, right):
DIRS_4 = [(-1,+0), (+1,+0), (+0,-1), (+0,+1)]
  • 8-way (including diagonals): (k-distance 1)
DIRS_8 = [(-1,-1), (-1,+0), (-1,+1),    # row above
( +0,-1), ( +0,+1), # row with item (exclude self)
( +1,-1), ( 1,+0), ( +1,-1)] # row below

obviously remove the + symbols, i just added to this further the point that these are offsets for the item we are checking, not the actual indices

Loop:

for dr, dc in DIRS_8:
nr, nc = r+dr, c+dc
if in_bounds(nr, nc, N, M):
...

  • of k-distance:

📏 Defining k-distance neighbors

  • Distance 1 (standard) → the 8 adjacent cells: one step away in row/col/diag.

  • Distance 2 → all cells whose row/col offset ≤ 2.

    • That gives you a 5×5 box centered at (r,c).
    • So 25 − 1 = 24 neighbors.
  • Distance k → a (2k+1)×(2k+1) box → total neighbors = (2k+1)² − 1.

Remember to add a condition to skip checking self/target (offset (0,0))

def in_bounds(row, col, n_rows, n_cols):
return 0 <= row < n_rows and 0 <= col < n_cols


def neighbors(row, col, n_rows, n_cols, distance=1, diagonals=True):
"""
Return all neighbor coordinates around (row, col) within a given distance.

Args:
row, col: Current cell position
n_rows, n_cols: Grid dimensions
distance: How far out to look (1 = immediate neighbors, 2 = distance-2, etc.)
diagonals: If False, only include Manhattan (N,S,E,W) neighbors

Returns:
List of (row, col) tuples
"""
results = []
for d_row in range(-distance, distance + 1):
for d_col in range(-distance, distance + 1):
if d_row == 0 and d_col == 0:
continue # skip the center cell itself

if not diagonals and abs(d_row) + abs(d_col) > distance:
continue # drop diagonal-like moves if diagonals=False

chk_row, chk_col = row + d_row, col + d_col
if in_bounds(chk_row, chk_col, n_rows, n_cols):
results.append((chk_row, chk_col))

return results

🔀 Variants (Not implemented here - to explore later)

  • Chebyshev distance (the default above) → “all cells within k steps in any direction” (square neighborhood).
  • Manhattan distance (like in BFS shortest paths) → only cells where |dr|+|dc| ≤ k.
  • Euclidean distance cutoff → include (dr,dc) if dr²+dc² ≤ k² (circle neighborhood).

4. Common patterns

  • Initialize with unique values (for testing/debugging):
grid = [[r*M + c for c in range(M)] for r in range(N)]

→ Gives each cell a unique ID.

  • Copying a grid safely:
from copy import deepcopy
grid_copy = deepcopy(grid)
  • Flatten index (for random sampling):
pos = r * M + c
r, c = divmod(pos, M)

🔑 Mental Model

  • Row-first indexing: grid[r][c]
  • Check bounds before use
  • Use comprehension for fresh rows


🧰 Implementation Pattern (Python)

def neighbors(r, c, N, M, k=1, diagonals=True):
out = []
for dr in range(-k, k+1):
for dc in range(-k, k+1):
if dr == 0 and dc == 0:
continue # skip self
if not diagonals and abs(dr) + abs(dc) > k:
continue # Manhattan distance if needed
nr, nc = r+dr, c+dc
if 0 <= nr < N and 0 <= nc < M:
out.append((nr, nc))
return out

Examples

neighbors(2, 2, 5, 5, k=1)
# 8 cells around (2,2)

neighbors(2, 2, 5, 5, k=2)
# 24 cells in a 5x5 square, minus center

🧮 Neighbor Counts

  • k = 1 → 8 neighbors
  • k = 2 → 24 neighbors
  • k = 3 → 48 neighbors
  • General: (2k+1)² − 1