import numpy as np
# 初始化一个空列表,用于存储用户输入的每一行灯状态数据
line = []
# 通过循环让用户逐行输入灯的初始状态数据
for i in range(5):
# 获取用户输入的第i行数据,并去除输入字符串两端可能存在的空白字符(如空格、换行等)
line_input = input("请输入第" + str(i) + "行:").strip()
# 将输入的字符串形式的数据转换为整数列表,例如 "101010" 会转换为 [1, 0, 1, 0, 1, 0],然后添加到line列表中
line.append(list(map(int, line_input)))
# 将存储了用户输入的5行灯状态数据的列表转换为二维的numpy数组,方便后续进行矩阵操作
puzzle = np.array(line)
# 创建一个形状为(1, 6)的全零二维数组,数据类型为整数,用于在行方向上添加到puzzle数组的开头,作为额外的边界行(可能是为了符合特定算法逻辑对边界的处理需求)
zero_row = np.zeros((1, 6), dtype=int)
# 使用np.vstack函数将zero_row数组和puzzle数组按垂直方向(行方向)堆叠在一起,也就是在puzzle数组的开头添加了一行全零数据
puzzle = np.vstack((zero_row, puzzle))
# 创建一个形状为(6, 1)的全零二维数组,数据类型为整数,用于在列方向上添加到puzzle数组的两侧,作为额外的边界列(同样可能是为了满足后续算法对边界情况的处理)
zero_col = np.zeros((6, 1), dtype=int)
# 使用np.hstack函数将两个zero_col数组和中间的puzzle数组按水平方向(列方向)堆叠在一起,即在puzzle数组的最左边和最右边各添加了一列全零数据
puzzle = np.hstack((zero_col, puzzle, zero_col))
# 创建一个形状为(6, 8)的全零二维数组,数据类型为整数,用于记录每个位置的“按下”操作情况,初始时所有位置都为未按下(值为0)
press = np.zeros((6, 8), dtype=int)
def guess():
"""
guess函数用于根据当前的灯状态(puzzle数组)和按下操作情况(press数组),判断当前按下操作是否能使得所有灯熄灭(满足特定条件)。
具体是按照一定的规则更新press数组中对应位置的值,并检查最后一行灯的状态是否符合预期(这里推测是熄灭状态)。
"""
# 遍历除了添加的边界行之外的“有效”行(索引从1到5,实际对应原来输入的5行数据所在的行范围)
for r in range(1, 5):
# 遍历除了添加的边界列之外的“有效”列(索引从1到7,实际对应原来输入的6列数据所在的列范围)
for c in range(1, 7):
# 根据周围灯的状态以及当前位置的按下操作情况,按照特定规则(可能是点灯游戏里的规则,通过异或操作实现状态变化逻辑)计算下一行对应位置的按下操作值,这里取余2实现类似异或的效果,确保结果为0或1
press[r + 1][c] = (puzzle[r][c] + press[r][c] +
press[r - 1][c] + press[r][c - 1] +
press[r][c + 1]) % 2
# 检查最后一行(索引为5,对应添加边界后的实际最后一行)灯的状态是否符合预期(根据某种规则判断是否全部熄灭等情况)
for c in range(1, 7):
if (press[5][c - 1] + press[5][c] + press[5][c + 1] + press[4][c]) % 2!= puzzle[5][c]:
return 0
return 1
def enumeration():
"""
enumeration函数使用穷举法来尝试找到一种按下操作组合(通过修改press数组的值),使得所有灯最终熄灭(满足guess函数里判断的条件)。
它通过不断改变press数组中第一个“有效”位置(press[1][1])的值,并按照一定规则逐步调整其他位置的值,反复调用guess函数进行判断,直到找到满足条件的组合为止。
"""
# 只要guess函数返回0,说明当前按下操作组合不能使得所有灯熄灭,就继续循环尝试不同的按下操作组合
while guess() == 0:
# 先尝试改变press数组中第一个“有效”位置(press[1][1])的值,将其加1(因为初始值为0,这里开始尝试不同的按下情况)
press[1][1] += 1
c = 1
# 当press[1][c]的值大于1时(由于这里只有0和1两种状态表示是否按下,大于1不符合要求),进行如下处理
while press[1][c] > 1:
# 将当前位置的值重置为0,表示不按下
press[1][c] = 0
c += 1
# 只有当列索引小于8(在有效列范围内)时,才对下一个位置的值加1,继续尝试下一种按下情况
if c < 8:
press[1][c] += 1
# 调用enumeration函数开始通过穷举法寻找满足条件的按下操作组合
enumeration()
# 输出灯的初始状态,这里通过切片操作去除了之前添加的边界行和边界列,只显示用户最初输入的5行6列的灯初始状态数据
print("灯的初始状态:\n", puzzle[1:6, 1:7])
# 输出最终找到的满足条件的按下操作组合情况,同样通过切片操作去除边界部分,显示对应“有效”区域内的按下操作情况
print("按下结果为:\n", press[1:6, 1:7])
输出结果: