You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python中FEN字符串坐标索引问题:移动棋子时添加逻辑出错

问题描述

国际象棋中FEN字符串用于描述棋盘配置。我编写了ChangeFEN函数,尝试根据棋子的棋盘坐标从字符串中移除棋子,再将其添加到新坐标位置。移除棋子的索引查找循环运行正常,但添加棋子的循环无法正常工作,每次移动棋子时代码都会计算错误的索引。

当前FEN字符串:

curFEN = "r5k1/5ppp/1p6/p1p5/7b/1PPrqPP1/1PQ4P/R4R1K"

函数代码:

def ChangeFEN(Orig, New):

    global curFEN
    PrevX, PrevY = Orig
    NewX, NewY = New

    rows = curFEN.split("/")

    # delete piece from FEN string

    index = 0
    for i in range(PrevY-1):
        index += len(rows[i]) + 1

    space = 0
    index2 = 0
    #print(rows[PrevY-1])
    for index2, i in enumerate(rows[PrevY-1]):
        if i.isdigit() == True:
            space += int(i)
        else:
            if space == PrevX-1:
                break
            else:
                space += 1

    index3 = index + index2

    piece = curFEN[index3]

    if index3 == 0:
        a = "/"
    else:
        a = curFEN[index3 - 1]

    try:
        b = curFEN[index3 + 1]
    except IndexError:
        b = "/"

    if a == "/":
        if curFEN[index3 + 1].isdigit() == True:
            #print("letter, number")
            curFEN = curFEN[0 : index3] + str(1 + int(curFEN[index3 + 1])) + curFEN[index3 + 2 :]
        else:
            #print("letter, letter")
            curFEN = curFEN[0 : index3] + "1" + curFEN[index3 + 1 :]
    elif b == "/":
        if curFEN[index3 - 1].isdigit() == True:
            #print("number, letter")
            curFEN = curFEN[0 : index3 - 1] + str(int(curFEN[index3 - 1]) + 1) + curFEN[index3 + 1 :]
        else:
            #print("letter, letter")
            curFEN = curFEN[0 : index3] + "1" + curFEN[index3 + 1 :]
    else:
        if curFEN[index3 - 1].isdigit() == True:
            if curFEN[index3 + 1].isdigit() == True:
                #print("number, letter, number")
                curFEN = curFEN[0 : index3 - 1] + str(int(curFEN[index3 - 1]) + 1 + int(curFEN[index3 + 1])) + curFEN[index3 + 2 : ]
            else:
                #print("number, letter, letter")
                curFEN = curFEN[0 : index3 - 1] + str(int(curFEN[index3 - 1]) + 1) + curFEN[index3 + 1 :]
        else:
            if curFEN[index3 + 1].isdigit() == True:
                #print("letter, letter, number")
                curFEN = curFEN[0 : index3] + str(1 + int(curFEN[index3 + 1])) + curFEN[index3 + 2 :]
            else:
                #print("letter, letter, letter")
                curFEN = curFEN[0 : index3] + "1" + curFEN[index3 + 1 :]
    
    # add piece to FEN string

    index = 0
    for i in range(NewY-1):
        index += len(rows[i]) + 1
    #index = index - 1
    
    space = 0
    index2 = 0
    #print(rows[NewY-1])

    for index2, i in enumerate(rows[NewY-1]):
        if i.isdigit() == True:
            for j in range(int(i)):
                space += 1
                if space == NewX:
                    break
        else:
            if space == NewX:
                break
            else:
                space += 1

    #print(index)
    #print(index2)
    index3 = index + index2 #- NewY

    #print(curFEN[index3])
问题原因

添加棋子部分存在三个核心错误:

  1. 移除棋子后curFEN已被修改,但仍使用原始的rows变量计算新坐标索引,导致基于旧棋盘数据的位置计算完全错误。
  2. 新坐标的space计数逻辑混乱:遇到数字时逐个计数,但未处理“计数到目标位置后,确定在数字中的偏移”,循环结束后无法正确定位插入点。
  3. 缺失插入棋子后的数字拆分/合并逻辑,比如插入位置是数字时,未将数字拆分为对应空格数的前后部分,直接插入会破坏FEN格式。
修复方案

重新设计添加棋子的逻辑,基于修改后的curFEN重新计算位置,并处理数字的拆分与合并:

def ChangeFEN(Orig, New):
    global curFEN
    PrevX, PrevY = Orig
    NewX, NewY = New

    # --- 保留原移除棋子逻辑(确认正常工作)---
    rows = curFEN.split("/")

    index = 0
    for i in range(PrevY-1):
        index += len(rows[i]) + 1

    space = 0
    index2 = 0
    for index2, i in enumerate(rows[PrevY-1]):
        if i.isdigit():
            space += int(i)
        else:
            if space == PrevX-1:
                break
            else:
                space += 1

    index3 = index + index2
    piece = curFEN[index3]

    left_char = curFEN[index3-1] if index3 > 0 else "/"
    right_char = curFEN[index3+1] if index3+1 < len(curFEN) else "/"

    if left_char == "/":
        if right_char.isdigit():
            curFEN = curFEN[:index3] + str(1 + int(right_char)) + curFEN[index3+2:]
        else:
            curFEN = curFEN[:index3] + "1" + curFEN[index3+1:]
    elif right_char == "/":
        if left_char.isdigit():
            curFEN = curFEN[:index3-1] + str(int(left_char) + 1) + curFEN[index3+1:]
        else:
            curFEN = curFEN[:index3] + "1" + curFEN[index3+1:]
    else:
        if left_char.isdigit() and right_char.isdigit():
            curFEN = curFEN[:index3-1] + str(int(left_char) + 1 + int(right_char)) + curFEN[index3+2:]
        elif left_char.isdigit():
            curFEN = curFEN[:index3-1] + str(int(left_char) + 1) + curFEN[index3+1:]
        elif right_char.isdigit():
            curFEN = curFEN[:index3] + str(1 + int(right_char)) + curFEN[index3+2:]
        else:
            curFEN = curFEN[:index3] + "1" + curFEN[index3+1:]

    # --- 修复后的添加棋子逻辑 ---
    # 基于修改后的FEN重新拆分行
    new_rows = curFEN.split("/")
    target_row = new_rows[NewY-1]
    row_start_index = 0
    # 计算目标行在FEN字符串中的起始位置
    for i in range(NewY-1):
        row_start_index += len(new_rows[i]) + 1

    space_count = 0
    insert_pos_in_row = 0
    digit_offset = 0  # 记录插入点在数字字符内的偏移

    for idx, c in enumerate(target_row):
        if c.isdigit():
            digit_val = int(c)
            if space_count + digit_val >= NewX:
                # 插入点在当前数字内部
                insert_pos_in_row = idx
                digit_offset = NewX - space_count
                break
            space_count += digit_val
        else:
            space_count += 1
        
        if space_count == NewX:
            insert_pos_in_row = idx + 1
            digit_offset = 0
            break

    # 修改目标行
    modified_row = ""
    if digit_offset > 0:
        # 拆分数字,插入棋子
        digit = int(target_row[insert_pos_in_row])
        left_digit = digit - digit_offset
        right_digit = digit_offset - 1  # 插入棋子后空格数减1
        modified_row = (
            target_row[:insert_pos_in_row]
            + (str(left_digit) if left_digit > 0 else "")
            + piece
            + (str(right_digit) if right_digit > 0 else "")
            + target_row[insert_pos_in_row+1:]
        )
    else:
        if insert_pos_in_row < len(target_row) and target_row[insert_pos_in_row].isdigit():
            # 插入点在数字前,将数字减1
            digit = int(target_row[insert_pos_in_row])
            new_digit = digit - 1
            modified_row = (
                target_row[:insert_pos_in_row]
                + piece
                + (str(new_digit) if new_digit > 0 else "")
                + target_row[insert_pos_in_row+1:]
            )
        else:
            # 直接插入棋子
            modified_row = target_row[:insert_pos_in_row] + piece + target_row[insert_pos_in_row:]

    # 拼接新的FEN字符串
    new_rows[NewY-1] = modified_row
    curFEN = "/".join(new_rows)
关键修复点
  • 移除棋子后立即基于更新后的curFEN重新拆分行,避免使用旧棋盘数据。
  • 重构插入位置的计数逻辑,精准判断插入点是在数字内部还是字符间隙。
  • 处理数字拆分/合并:插入点在数字内时拆分数字并插入棋子;插入点在数字前时将数字减1后拼接棋子,保证FEN格式合法。

内容的提问来源于stack exchange,提问作者Coder

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 21:17:22