【五子棋迷】Python 实现-附ChatGPT解析

1.题目

张兵和王武是五子棋只迷,工作之余经常切磋棋艺。这不,这会儿又下起来了。走了一会儿,轮张兵了,对着一条线思考起来了这条线上的棋子分布如下
用数组表示:-1 0 1 1 1 0 1 -1 1

棋子分布说明:

  1. -1代表白子,0代表空位,1 代表黑子
  2. 数组长度L,满足 1 L< 40,L为奇数

你得帮他写一个程序,算出最有利的出子位置。
最有利的定义

  1. 找到一个空位(0),用棋子(1/-1)填充该位置,可以使得当前子的最大连续长度变大
  2. 如果存在多个位置,返回最靠近中间的较小的那个坐标
  3. 如果不存在可行位置,直接返回-1:
  4. 连续长度不能超过5个(五字棋约束)

输入描述:
第一行: 当前出子颜色
第二行: 当前的棋局状态
输出描述
1个整数,表示出子位置的数组下标

示例1
输入:

1
-1 0 1 1 1 0 1 0 1 -1 1
输出: 5
说明: 当前为黑子(1),放置在下标为5的位置,黑子的最大连续长度,可以由3到5

示例2
输入:

-1
-1 0 1 1 1 0 1 0 1 -1 1
输出: 1
说明: 当前为白子(-1),唯一可以放置的位置下标为1,白子的最大长度,由1变为2

示例3
输入:

1
0 0 0 0 1 0 0 0 0 1 0
输出: 5
说明: 可行的位置很多,5最接近中间的位置坐标

2.解析

这份代码的主要思路是找到最有利的出子位置,以满足以下条件:

  1. 在空位上放置当前颜色的棋子(1表示黑子,-1表示白子)。
  2. 能够使得当前位置的最大连续长度变大,但不能超过5个。
  3. 如果存在多个可行位置,返回最靠近棋盘中间的那个位置。


下面是代码的详细解释:

  1. 首先,定义了一个函数 find_best_move,它接受两个参数:current_color 表示当前出子的颜色,board_state 表示当前的棋局状态,以一个列表的形式表示。
  2. 在函数内部,初始化了两个变量:max_continuous_length 用于记录最大连续长度,best_move 用于记录最有利的出子位置下标,初始值都设为-1。
  3. 然后,使用一个 for 循环遍历棋盘中的每个位置,即 i 表示当前位置的下标。
  4. 在 for 循环中,首先检查当前位置是否是空位,即 board_state[i] == 0。如果是空位,就进入下面的操作,否则跳过。
  5. 在当前位置放置当前颜色的棋子 board_state[i] = current_color,模拟了将棋子放在这里的情况。
  6. 接下来,计算当前位置的连续长度 continuous_length。这里使用了一个内嵌的 for 循环来分别计算当前位置的左侧和右侧的连续长度。这个 for 循环使用变量 delta 来控制方向,分别检查左侧和右侧的棋子,如果与当前颜色相同,就增加连续长度 continuous_length。
  7. 在计算连续长度后,通过条件判断来更新 best_move
    如果当前位置的连续长度大于 max_continuous_length,
    或者等于 max_continuous_length 但更靠近棋盘中间(通过计算绝对差值来比较),
    就更新 max_continuous_length 和 best_move。
  8. 最后,为了继续探索其他位置,将当前位置的棋子恢复为0,即 board_state[i] = 0。
  9. for 循环结束后,函数返回 best_move,即最有利的出子位置的下标。

整个代码的核心思想遍历空位,模拟将棋子放在每个空位后计算连续长度,并根据条件选择最有利的出子位置。简化的部分在于省略了单独的 calculate_continuous_length 函数,直接在遍历中计算连续长度,并使用一个 for 循环来处理左侧和右侧的搜索。

3.代码

Q:‘for delta in [-1, 1]:’ 这段for循环及其下的while再展开解释

for delta in [-1, 1]:
   # 这个循环会执行两次,分别对应着检查左侧和右侧的方向
   
    j = i + delta  # j 表示当前位置的相邻位置,delta 控制方向,-1 表示左侧,1 表示右侧
   while 0 <= j < len(board_state) and board_state[j] == current_color:
       # 这是一个 while 循环,它会一直执行直到不满足下列条件之一:
       # 1. j 超出了棋盘边界,即 j 小于 0 或大于等于棋盘大小
       # 2. j 处的棋子颜色与当前颜色不相同
       # 如果当前位置 j 处的棋子颜色与当前颜色相同,就增加连续长度
       continuous_length += 1

       # 然后继续检查下一个相邻位置,即向左或向右移动一格
       j += delta

当进入 for delta in [-1, 1]: 循环时,这段代码会分别考虑两个方向:左侧和右侧。下面是对这段代码的正确解释和运行思路:

  1. for delta in [-1, 1]: 循环会执行两次,第一次 delta 取值为 -1,第二次 delta 取值为 1。这两次循环分别对应检查左侧和右侧的方向。
  2. 对于每个方向,循环首先计算当前位置的连续长度。开始时, continuous_length 初始化为1,因为当前位置自身也算作一个棋子。
  3. 循环进入内部的 while 循环,该循环用于在当前方向上继续探索,直到不满足下列条件之一:
  • j 超出了棋盘边界(小于0或大于等于棋盘大小)。
  • j 处的棋子颜色与当前颜色不相同。
  1. 在 while 循环内部,如果当前位置 j 处的棋子颜色与当前颜色相同,就增加 continuous_length,表示当前位置的连续长度。然后,将 j 移动到下一个相邻位置,即向左或向右移动一格,以继续检查下一个位置。
  2. 两个方向上的循环分别计算了左侧和右侧的连续长度,并将结果存储在 continuous_length 中。
  3. 在两个方向上的循环结束后,continuous_length 的值就是左侧和右侧连续长度的总和。
  4. 最后,根据这个连续长度的总和以及其他条件,比较当前位置和其他位置,决定是否更新 best_move,即最佳出子位置的下标。

总的运行思路是,该代码通过分别检查左侧和右侧的方向,在每个方向上计算当前位置的连续长度,然后根据这些连续长度的总和来确定最佳出子位置。这样,代码考虑了横向连续性,确保了最有利的出子位置。

def find_best_move(current_color, board_state):
    max_continuous_length = 0  # 记录最大连续长度
    best_move = -1  # 记录最有利的出子位置下标

    for i in range(len(board_state)):
        if board_state[i] == 0:  # 只考虑空位
            # 在当前位置放置棋子
            board_state[i] = current_color

            # 计算当前位置的连续长度(只需考虑当前位置的左侧和右侧)
            continuous_length = 1  # 初始长度为1
            for delta in [-1, 1]:
                j = i + delta
                while 0 <= j < len(board_state) and board_state[j] == current_color:
                    continuous_length += 1
                    j += delta

            # 更新最佳位置
            if continuous_length > max_continuous_length or (continuous_length == max_continuous_length and abs(i - len(board_state) // 2) < abs(best_move - len(board_state) // 2)):
                max_continuous_length = continuous_length
                best_move = i

            # 恢复原始棋盘状态
            board_state[i] = 0

    return best_move

# 读取输入
current_color = int(input())
board_state = list(map(int, input().split()))

# 调用函数找到最有利的出子位置
best_move = find_best_move(current_color, board_state)

# 输出结果
print(best_move)

'''
1
-1 0 1 1 1 0 1 0 1 -1 1
输出: 5
'''

示例1的调试信息

当前位置:1, 当前颜色:1, 棋盘状态:[-1, 1, 1, 1, 1, 0, 1, 0, 1, -1, 1]
  当前位置:0, 连续长度:1
  当前位置:2, 连续长度:2
  当前位置:3, 连续长度:3
  当前位置:4, 连续长度:4
  当前位置:5, 连续长度:5
  当前位置:6, 连续长度:6
  当前位置:7, 连续长度:7
  当前位置:8, 连续长度:8
  当前位置:9, 连续长度:9
  当前位置:10, 连续长度:10
当前位置:5, 当前颜色:1, 棋盘状态:[-1, 1, 1, 1, 1, 1, 1, 0, 1, -1, 1]
  当前位置:4, 连续长度:1
  当前位置:6, 连续长度:2
  当前位置:7, 连续长度:3
  当前位置:8, 连续长度:4
  当前位置:9, 连续长度:5
  当前位置:10, 连续长度:6
当前位置:10, 当前颜色:1, 棋盘状态:[-1, 1, 1, 1, 1, 0, 1, 0, 1, -1, 1]
  当前位置:9, 连续长度:1
  当前位置:8, 连续长度:2
  当前位置:7, 连续长度:3
  当前位置:6, 连续长度:4
  当前位置:5, 连续长度:5
  当前位置:4, 连续长度:6
  当前位置:3, 连续长度:7
  当前位置:2, 连续长度:8
  当前位置:1, 连续长度:9
  当前位置:0, 连续长度:10
最佳出子位置:5

调试代码如下

def find_best_move(current_color, board_state):
    max_continuous_length = 0
    best_move = -1

    for i in range(len(board_state)):
        if board_state[i] == 0:
            board_state[i] = current_color
            continuous_length = 1

            # 打印当前位置的信息
            print(f"当前位置:{i}, 当前颜色:{current_color}, 棋盘状态:{board_state}")

            for delta in [-1, 1]:
                j = i + delta
                while 0 <= j < len(board_state) and board_state[j] == current_color:
                    continuous_length += 1
                    j += delta

                    # 打印连续长度的计算过程
                    print(f"  当前位置:{j}, 连续长度:{continuous_length}")

            if (
                continuous_length > max_continuous_length
                or (continuous_length == max_continuous_length and abs(i - len(board_state) // 2) < abs(best_move - len(board_state) // 2))
            ):
                max_continuous_length = continuous_length
                best_move = i

            board_state[i] = 0

    return best_move

# 模拟示例1的输入
current_color = 1
board_state = [-1, 0, 1, 1, 1, 0, 1, 0, 1, -1, 1]

best_move = find_best_move(current_color, board_state)
print("最佳出子位置:", best_move)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值