
本文详解如何将一维索引(如 1~16)映射到二维网格坐标,并基于随机选中的索引批量设置对应单元格为 1,同时提供健壮、可扩展的打印格式支持不同尺寸网格。
在处理网格类问题时,一个常见需求是:给定一个 size × size 的方阵,用从 1 开始的线性编号(按行优先顺序)标识每个格子——即 (0,0)→1, (0,1)→2, …, (0,size−1)→size, (1,0)→size+1,依此类推。用户希望从该编号空间中随机选取一半位置(如 size=4 时选 8 个数),并将对应网格单元设为 1,其余保持 0。
关键难点在于索引转换:需将输入的整数 i(如 12)准确还原为二维坐标 (row, col)。Python 提供了简洁解法:
- 行号 = (i - 1) // size
- 列号 = (i - 1) % size
更优雅地,可直接使用 divmod(i - 1, size) 同时获取二者。
以下为完整实现,严格遵循 关注点分离(Separation of Concerns)与 PEP 8 命名规范:
import random
def make_grid(size, chosen_indices):
"""创建 size×size 网格,将 chosen_indices 中的线性索引对应位置设为 1"""
grid = [[0] * size for _ in range(size)]
for i in chosen_indices:
row, col = divmod(i - 1, size)
grid[row][col] = 1
return grid
def print_grid(grid):
"""格式化打印网格,自动适配大尺寸索引对齐"""
if not grid:
return
size = len(grid)
max_idx_width = len(str(size - 1))
fmt = f"{{:>{max_idx_width}d}}"
# 打印每行:索引 + [元素]
for i, row in enumerate(grid):
print(fmt.format(i), end="[")
print(" ".join(fmt.format(x) for x in row), end="]\n")
# 打印列索引标头(缩进与行索引对齐)
print(" " * max_idx_width, end=" ")
print(" ".join(fmt.format(j) for j in range(size)))
# 主流程
size = int(input("Size? (even) "))
area = size * size
half = area // 2
the_chosen_half = random.sample(range(1, area + 1), half)
grid = make_grid(size, the_chosen_half)
print_grid(grid)✅ 示例输出(size=4, chosen=[1,2,3,4,5,6,7,8]):
0[1 1 1 1] 1[1 1 1 1] 2[0 0 0 0] 3[0 0 0 0] 0 1 2 3
✅ 示例输出(size=4, chosen=[12,5,16,2,8,9,15,3]):
0[0 1 1 0] 1[1 0 0 1] 2[1 0 0 1] 3[0 0 1 1] 0 1 2 3
⚠️ 重要注意事项:
- 原始代码中 vertical.append(horizontal); horizontal=[] 导致所有行引用同一列表对象,修改任一行会影响全部——这是典型浅拷贝陷阱。本方案使用 [[0]*size for _ in range(size)] 确保每行独立。
- print_grid 中动态计算索引宽度(max_idx_width)可避免大网格(如 size=15)出现列错位,提升可读性。
- 避免全局变量:所有数据通过参数传递,函数职责单一,便于测试与复用。
此设计不仅解决了当前问题,更为后续扩展(如支持矩形网格、自定义填充值、导出 CSV 等)奠定了清晰、可维护的基础。










