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)
ifdr²+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