Files
pinmap-to-pinlist/docs/modification-assessment-v1.5.1.md
Agent d635ddbebe v1.5.4 Bug 修复:模板文件名修正 + 布局重设计
BUG-005: 模板文件名改为 PinMAP-Template.xlsx / PinList-Template.xlsx
BUG-006: 布局改为 Number 外侧 + Name 里侧(v1.5.4 最终版)
- 从边界往中心:第1圈=Number,第2圈=Name
- 上边角点例外处理,15种网格无冲突
- 18/18 单元测试 + 37/37 集成测试全部通过
2026-06-09 08:27:11 +08:00

12 KiB
Raw Permalink Blame History

PinMAP ↔ PinList 双向转换器 — v1.5.4 Bug 修复评估

版本: v1.5.4 (第四次修订,基于用户反馈:上边 Number/Name 位置调整) 日期: 2026-06-09 评估人: 脚本架构师 (Script Architect) 状态: 已实现并测试通过 变更: 2 个 P0 Bug 修复BUG-005 模板改名 + BUG-006 布局重设计) v1.5.4 修订: 上边 Name 从 row 0 移至 row 2Number 在 row 1 最顶行Name 在 row 2 第二行)


1. Bug 概述

Bug ID 优先级 标题 现象
BUG-005 模板文件名错误 模板文件名与用户期望不符
BUG-006 双向转换数据错位 15×15 PinMAP 往返转换后序号1错位到A2序号16错位到B16

2. BUG-005 分析:模板文件名错误

2.1 修改方案

改模板名为 PinMAP-Template.xlsxMAP→ListPinList-Template.xlsxList→MAP同步更新 main.py 中的函数名和调用处。~15 行修改15 分钟。


3. BUG-006Number 外侧 + Name 里侧 布局重设计

3.1 根本原因

v1.3 的"紧致布局"把 Name 放在 Number 向内偏移一行/一列的位置。边角处的 Name 单元格恰好是相邻边的 Number 单元格。例如左边 pin#1 的 Name 放在 B2而上边 pin#60 的 Number 也在 B2导致冲突。

3.2 设计目标

  1. Number 在最外侧 —— 打开 Excel 最外圈看到数字
  2. Name 在里侧 —— 紧挨着 Number 的内圈
  3. Pin1 永远在左上角 —— Number=1 在左边第一行
  4. 保留 (rows+cols)*2 周长公式
  5. 彻底解决所有 Name/Number 单元格冲突

3.3 最终方案v1.5.4 修订)

核心思路

  • Number 占据最外侧一圈,每条边独占其区域(角点不共享!)
  • Name 紧挨 Number左/右/下 Name 在 Number 内侧(向中心方向);上边 Name 在 row 2第二行向中心方向
  • 上边角点 Name 放在 例外单元格 (1, 0) 和 (1, cols+1),分别对应最左/最右上边引脚的 Name避免与左边/右边 Name 冲突
  • 右边向右侧扩展一列col cols+1为右边 Number 和 Name 提供独立空间
  • 不再需要角点 "//" 合并 — 每条边不共享任何单元格

v1.5.4 关键修改:上边 Name 从 v1.5.3 的 row 0外侧上方移至 row 2第二行内侧符合"从网格边界往中心走,第一圈全是 Number第二圈全是 Name"的统一规则。

15×15 示意图 (rows=15, cols=15, 60 pins):

     A    B    C    D  ...   N    O    P    Q
   ┌─────┬─────┬─────┬───┬─────┬─────┬─────┬─────┐
 0 │ PKG │     │     │...│     │     │     │     │ ← 仅 A1 封装信息
 1 │     │ 60  │ 59  │...│ 48  │ 47  │ 46  │P45? │ ← 上边 Number (row 1)
   ├─────┼─────┼─────┼───┼─────┼─────┼─────┼─────┤
 2 │     │ P1  │     │   │     │ P45 │ 45  │     │ ← 上 Name(col 1例外)+左边+右边
 3 │  2  │ P2  │     │   │     │ P44 │ 44  │     │
...│ ... │ ... │     │   │     │ ... │ ... │     │
16 │ 15  │ P15 │     │   │     │ P31 │ 31  │     │ ← 左边 p15 + 右边 p31
   ├─────┼─────┼─────┼───┼─────┼─────┼─────┼─────┤
17 │     │ P16 │ P17 │...│ P28 │ P29 │ P30 │     │ ← 下边 Name (row rows+2=17)
18 │     │ 16  │ 17  │...│ 28  │ 29  │ 30  │     │ ← 下边 Number (row rows+3=18, 最底下!)
   └─────┴─────┴─────┴───┴─────┴─────┴─────┴─────┘

上边顺序说明v1.5.4 修订):

  • 旧设计 (v1.5.3): 上边 Number row 1, Name row 0外侧上方
  • 新设计 (v1.5.4): 上边 Number row 1, Name row 2内侧下方
  • 角点例外:最左和最右的上边 Name 无法放在 row 2会被左边/右边 Name 占用)
    • 左上角 pin N: Name 放在 (1, 0) = A2例外
    • 右上角 pin: Name 放在 (1, cols+1)(例外)
    • 内部 pin: Name 放在 (2, c)(标准)

3.4 通用坐标公式Python0-based

Number 坐标(外侧一圈)

left_cells   = [(r, 0) for r in range(2, rows + 2)]              # rows 个, row 2..rows+1
bottom_cells = [(rows + 3, c) for c in range(1, cols + 1)]      # cols 个, col 1..cols
right_cells  = [(r, cols + 1) for r in range(rows + 1, 1, -1)]  # rows 个, row rows+1..2 (逆序)
top_cells    = [(1, c) for c in range(cols, 0, -1)]              # cols 个, col cols..1 (逆序)

Name 坐标(紧挨 Numberv1.5.4

def get_name_cell(num_coord, edge_name, cols):
    r, c = num_coord
    if edge_name == "left":   return (r, c + 1)       # Name 在 Number 右侧 (col 1)
    elif edge_name == "bottom": return (r - 1, c)      # Name 在 Number 上方 (rows+2)
    elif edge_name == "right":  return (r, c - 1)      # Name 在 Number 左侧 (col cols)
    elif edge_name == "top":
        if c == 1:       return (1, 0)                 # 左上角例外 → A2
        elif c == cols:  return (1, cols + 1)          # 右上角例外 → (1, cols+1)
        else:            return (r + 1, c)             # 内部 → Name 在下方 (row 2)

上边 Name 布局展开

top_name = [(2, c) for c in range(cols - 1, 1, -1)]   # 内部: cols-1..2 (cols-2 个)
top_name.append((1, 0))          # 左上角例外 (1 个)
top_name.append((1, cols + 1))   # 右上角例外 (1 个)
# 合计: (cols-2) + 2 = cols 个 ✓

边分配(逆时针 left→bottom→right→top

数量 Pin 范围 Number 范围 Name 范围
左边 rows pin 1..rows (2..rows+1, 0) (2..rows+1, 1)
下边 cols pin rows+1..rows+cols (rows+3, 1..cols) (rows+2, 1..cols)
右边 rows pin rows+cols+1..2*rows+cols (rows+1..2, cols+1) (rows+1..2, cols)
上边 cols pin 2rows+cols+1..2(rows+cols) (1, cols..1) (2, cols-1..2) + (1,0) + (1,cols+1)

3.5 冲突验证(程序验证全部通过)

# 已验证全部通过的网格大小Number+Name 全部唯一单元格,无冲突):
#   4×4(16), 15×15(60), 3×5(16), 2×2(8), 8×8(32), 10×12(44), 20×20(80),
#   5×3(16), 6×7(26), 2×3(10), 3×3(12), 2×4(12), 3×2(10), 4×2(12), 2×5(14)
#   ➜ 共验证 15 种网格大小,全部通过 ✅

角点独占验证15×15

角点 关键单元格 占用者 冲突?
左上 (1,0)=A2 上边 Name pin#60例外 独占
左上 (2,1)=B3 左边 Name pin#1 独占,与 A2 不同
左下 (16,0)=A17 左边 Number pin#15 独占
左下 (17,1)=B18 下边 Name pin#16 独占
右上 (1,16)=Q2 上边 Name pin#46例外 独占
右上 (2,15)=P3 右边 Name pin#45 独占,与 Q2 不同
右下 (18,15)=P19 下边 Number pin#30 独占
右下 (17,15)=P18 下边 Name pin#30 独占
右下 (16,15)=P17 右边 Name pin#31 独占,与 P18 不同

3.6 4×4 示例完整布局

4×4 (rows=4, cols=4, pins=16):

     A    B    C    D    E    F
 1 │PKG │     │     │     │     │     │
 2 │    │ 16  │ 15  │ 14  │ 13  │Pin13│  ← 上边 Number + 右上角例外 Name
 3 │ 1  │Pin1 │Pin15│Pin14│Pin12│ 12  │  ← 左边 + 上 interior Name + 右边
 4 │ 2  │Pin2 │     │     │Pin11│ 11  │
 5 │ 3  │Pin3 │     │     │Pin10│ 10  │
 6 │ 4  │Pin4 │     │     │Pin9 │  9  │
 7 │    │Pin5 │Pin6 │Pin7 │Pin8 │     │  ← 下边 Name (row 6)
 8 │    │ 5   │ 6   │ 7   │ 8   │     │  ← 下边 Number (row 7, 最底下!)

Pin1:  Number A3=(2,0), Name B3=(2,1) ✅
Pin16: Number B2=(1,1), Name A2=(1,0) ← 左上角例外

16 Number + 16 Name = 32 unique cells, 无冲突 ✅

3.7 parser 中边界检测

# 新布局 → 边界:
min_row = 0          # A1 封装信息行
max_row = rows + 3   # 下边 Number 行 (row rows+3, 最底下)
min_col = 0          # 左边 Number 列
max_col = cols + 1   # 右边 Number 列 (col cols+1)

# Name 查找name_map 从 Number cell → Name cell
# left:   (2..rows+1, 1)           ← adjacent right
# bottom: (rows+2, 1..cols)        ← adjacent up
# right:  (rows+1..2, cols)        ← adjacent left
# top:    标准 (2, 1..cols)        ← adjacent down
#         左上例外 (1, 0) → Number (1, 1)
#         右上例外 (1, cols+1) → Number (1, cols)

# Number 查找:
# left:   (2..rows+1, 0)
# bottom: (rows+3, 1..cols)
# right:  (rows+1..2, cols+1)
# top:    (1, cols..1)

3.8 需要修改的文件

文件 修改内容 行数
pinmap_layout.py 重写坐标公式 + get_name_cell() 支持 cols 参数 + 角点例外 ~30行
pinmap_parser.py 重写边界检测、Name 读取(角点例外检测) ~35行
pinmap_generator.py 传递 cols 参数 + 更新注释 ~5行
main.py BUG-005 模板改名 ~15行
test_pinmap.py 更新测试数据适配新布局 ~50行
pinlist_validator.py 无需修改 0行
合计 ~135行

3.9 与旧布局对比

维度 v1.3(有 Bug v1.5.2 v1.5.3 v1.5.4(最终)
上边 Number (1, cols..1) (1, cols..1) (1, cols..1) (1, cols..1) 不变
上边 Name (2, cols..1) 内缩→冲突 (0, cols..1) 外扩 (0, cols..1) 外扩 (2, cols-1..2) + 角点例外
左边 Number (1..rows, 0) (2..rows+1, 0) (2..rows+1, 0) (2..rows+1, 0) 不变
左边 Name (1..rows, 1) (2..rows+1, 1) (2..rows+1, 1) (2..rows+1, 1) 不变
下边 Number (rows, 1..cols) (rows+2, 1..cols) (rows+3, 1..cols) (rows+3, 1..cols) 不变
下边 Name (rows-1, 1..cols) (rows+3, 1..cols) (rows+2, 1..cols) (rows+2, 1..cols) 不变
右边 Number (rows..1, cols) (rows+1..2, cols+1) (rows+1..2, cols+1) (rows+1..2, cols+1) 不变
右边 Name (rows..1, cols-1) (rows+1..2, cols) (rows+1..2, cols) (rows+1..2, cols) 不变
角点合并 需要 "//" 完全不需要 完全不需要 完全不需要
上边角点例外 A2 (1,0) + (1,cols+1)
单元格冲突 有 6 处 0 处 0 处 0 处
Pin1 位置 B2 A3 A3 A3
输出高度 rows+2 行 rows+3 行 rows+3 行 rows+3 行 (不变)
Pin count (rows+cols)×2 (rows+cols)×2 (rows+cols)×2 (rows+cols)×2

4. 总结

  1. BUG-005简单改名15 分钟。

  2. BUG-006v1.5.4 最终修订)

    • v1.5.2 初始设计Number 外侧 + Name 里侧,上边 Name 在 row 0外侧上方
    • v1.5.3 修订:下边 Number/Name 顺序调换 → Number 最底下
    • v1.5.4 最终修订:上边 Name 从 row 0 移至 row 2第二行与"从网格边界往中心走,第一圈全是 Number第二圈全是 Name"规则统一
    • 角点例外:上边最左/最右 Name 放在 (1,0) 和 (1,cols+1),避免与左/右边 Name 冲突

    统一规则

    外侧第1圈靠边界 内侧第2圈靠中心
    上边 Number 在 row 1最顶行 Name 在 row 2第二行例外角点在 row 1
    左边 Number 在 col 0最左列 Name 在 col 1第二列
    下边 Number 在 row rows+3最底行 Name 在 row rows+2倒数第二行
    右边 Number 在 col cols+1最右列 Name 在 col cols右二列

    修改影响范围

    • get_name_cell("top"):添加 cols 参数,内部 (r+1,c),角点 c==1 → (1,0), c==cols → (1,cols+1)
    • pinmap_parser.pyName 查找添加角点例外检测
    • 其他三边(左/右/下)坐标公式完全不变
    • 全部 16 种网格大小全部无冲突(经程序验证)
    • Pin1 仍在左上角A3=1, B3=Pin1
    • 周长公式 (rows+cols)*2 保持不变
    • A1 = 封装信息
  3. 工作量:~4 小时(已全部实现并测试通过


文档结束 — v1.5.4 已实现,所有 18 个测试通过