鱼C论坛

 找回密码
 立即注册
查看: 3141|回复: 13

[已解决]拼图游戏bug,无法解决,求助~感谢

[复制链接]
发表于 2020-3-1 22:26:52 | 显示全部楼层 |阅读模式
50鱼币
本帖最后由 l0stparadise 于 2020-3-2 00:21 编辑

未解决,手欠手机上点错了,再次求助,如下图,利用数字和一个空格模拟九宫格拼图 2.jpg

但是运行后发现,上图第2次移动可以完成,第3次失败,第4次又成功,自查一直找不到bug,代码如下,请高手解决,多谢~~~
  1. import random


  2. def print_chestable(foo):  #定义打印格式,输出九宫格
  3.     num=0
  4.     for i in foo:
  5.         num+=1
  6.         if num%3==0:
  7.             print(i)
  8.         else:
  9.             print(i, end=" ")


  10. def move():  #定义移动步骤
  11.     global list1  #list1为产生九宫格的1-8,以及一个空格组成,格式如[6, ' ', 7, 8, 4, 3, 1, 5, 2]
  12.     dict1={0:[1,3], 1:[0,2,4],2:[1,5],3:[0,4,6],4:[1,3,5,7],5:[2,4,8],6:[3,7],7:[4,6,8],8:[5,7]}
  13.     #对空格位置周围出现的其他可移动位置的列表索引号进行编号

  14.     chocie = int(input("请输入要移动的数字:"))  #用户输入要移动的数字

  15.     '''
  16.     判断用户输入要移动的数字是不是在空格周围可移动的的数字中,如果在:
  17.         交换空格位置和用户输入位置数字的值
  18.         返回新的列表
  19.     如果用户输入要移动的数字不在空格周围可移动的的数字中:
  20.         重新运行这个移动步骤
  21.     '''
  22.     if list1.index(chocie) in dict1[list1.index(" ")]:
  23.         list1[list1.index(" ")], list1[list1.index(chocie)] = list1[list1.index(chocie)],list1[list1.index(" ")]
  24.         return list1
  25.     else:
  26.         move()

  27. '''
  28. 定义游戏开始
  29.     进入循环
  30.         执行移动步骤并输出九宫格
  31.         如果排序正确
  32.             输出赢了
  33.             结束循环
  34. '''
  35. def game_bengin(bar):
  36.     while True:
  37.         print_chestable(move())
  38.         if bar ==[1,2,3,4,5,6,7,8," "]:
  39.             print("你赢了,牛逼")
  40.             break


  41. list1=[i for i in range(1,9)]  #产生[1,2,3,4,5,6,7,8]的列表
  42. list1.append(" ") #产生[1,2,3,4,5,6,7,8," "]的列表
  43. random.shuffle(list1) #产生[1,2,3,4,5,6,7,8," "]的洗牌后列表
  44. print_chestable(list1) #初始化
  45. game_bengin(list1) #运行游戏
复制代码


最佳答案
2020-3-1 22:26:53
本帖最后由 在东边 于 2020-3-2 13:05 编辑

显然,bug 是由下面这行代码产生的

  1. list1[list1.index(" ")], list1[list1.index(chocie)] = list1[list1.index(chocie)], list1[list1.index(" ")]
复制代码


为了方便讨论,我们简化一下问题,考虑下面这个情况

  1. ls = [1, 2]
  2. ls[ls.index(1)], ls[ls.index(2)] = 2, 1  # 试图交换 1、2,使 ls 变为 [2, 1]
  3. print(ls)
复制代码

上面这段代码的运行结果为
  1. [1, 2]
复制代码


可以看到,ls 并未改变

这个问题与楼主遇到的问题本质上是一样的,即在修改列表过程中,调用列表的 index 方法,列表却并未能如预期那样改变

实际上,这种现象出现的原因主要是因为 index 方法调用与修改列表之间存在先后顺序的问题

  1. ls[ls.index(1)], ls[ls.index(2)] = 2, 1
复制代码


上面这行代码进行了如下几个操作
1. 计算 ls.index(1),结果为 0
2. 将 2 赋值给 ls[0],此时 ls 的值为 [2, 2]
3. 计算 ls.index(2)(注意此时 ls 已经不是原来的 [1, 2],而是 [2, 2]),结果为 0
4. 将 1 赋值给 ls[0],ls 的值为 [1, 2]

也就是说 ls 的值经过了这样一个变化:[1, 2] --> [2, 2] --> [1, 2]



下面通过一些代码验证上述想法

  1. class NList(list):
  2.     def index(self, val):
  3.         print(f"当前列表的值为:{self}")
  4.         res = super().index(val)
  5.         print(f"返回值为:{res}")
  6.         return res

  7. nls = NList([1, 2])
  8. nls[nls.index(1)], nls[nls.index(2)] = 2, 1
  9. print(nls)
复制代码

运行结果如下
  1. 当前列表的值为:[1, 2]
  2. 返回值为:0
  3. 当前列表的值为:[2, 2]
  4. 返回值为:0
  5. [1, 2]
复制代码


代码中,定义了一个继承了 list 的类 NList,并重写了 index 方法,使其在调用 index 方法时,打印一些信息

从运行结果中,我们可以看到

在执行 nls.index(2) 这个操作的时候,列表 nls 的值已经变为 [2, 2]

那么 nls.index(2) 就将返回 0,然后再将 1 赋值给 nls[0],最终 nls 的值就为 [1, 2]

所以,看起来 nls 好像 ”从未改变“,实际上,它是经历了一个变化过程,又变回了原来的样子



最后,回到最初的问题

  1. list1[list1.index(" ")], list1[list1.index(chocie)] = list1[list1.index(chocie)], list1[list1.index(" ")]
  2. list1[list1.index(" ")], list1[list1.index(chocie)] = chocie, " "
复制代码


上面这两行代码是等价的,都是试图交换 chocie 和 " " 在 list1 中的位置

但由于 list1.index(chocie) 这一步是发生在 list1[list1.index(" ")] = chocie 之后,所以就可能会发生问题

为什么说是可能,而不是一定呢

看下面的代码

  1. >>> ls = [1, 2]
  2. >>> # ls[ls.index(1)], ls[ls.index(2)] = 2, 1  # 不能交换 ls 中 1 和 2 的位置,上面已解释
  3. >>> # 交换一下赋值顺序
  4. >>> ls[ls.index(2)], ls[ls.index(1)] = 1, 2
  5. >>> ls
  6. [2, 1]   # 1 和 2 成功交换位置
  7. >>> ls[ls.index(2)], ls[ls.index(1)] = 1, 2
  8. >>> ls
  9. [2, 1]   # 1、2 位置不变
复制代码


可以看到在利用 ls[ls.index(2)], ls[ls.index(1)] = 1, 2 成功交换一次之后

再尝试利用 ls[ls.index(2)], ls[ls.index(1)] = 1, 2 交换的时候,并未成功



第一次交换的过程如下:
1. 计算 ls.index(2),结果为 1
2. 将 1 赋值给 ls[1],此时 ls 的值为 [1, 1]
3. 计算 ls.index(1)(注意此时 ls 已经不是原来的 [1, 2],而是 [1, 1]),结果为 0
4. 将 2 赋值给 ls[0],ls 的值为 [2, 1]

也就是说 ls 的值经过了这样一个变化:[1, 2] --> [1, 1] --> [2, 1]

第二次交换的过程如下:
1. 计算 ls.index(2),结果为 0
2. 将 1 赋值给 ls[0],此时 ls 的值为 [1, 1]
3. 计算 ls.index(1)(注意此时 ls 已经不是原来的 [2, 1],而是 [1, 1]),结果为 0
4. 将 2 赋值给 ls[0],ls 的值为 [2, 1]

也就是说 ls 的值经过了这样一个变化:[2, 1] --> [1, 1] --> [2, 1]


上述过程表明

  1. list1[list1.index(" ")], list1[list1.index(chocie)] = chocie, " "
复制代码


如果你不停地输入同样的数字(即 chocie 每次都一样),那么上面这行代码至多只在第一次产生效果

所以,就出现了楼主的图中,第一次输入 5,正常交换,后面再输入 5 无法交换的问题

最佳答案

查看完整内容

设计有问题吧,移动的时候不还得把方向带着
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2020-3-1 22:26:53 From FishC Mobile | 显示全部楼层
设计有问题吧,移动的时候不还得把方向带着
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2020-3-1 22:26:53 | 显示全部楼层    本楼为最佳答案   
本帖最后由 在东边 于 2020-3-2 13:05 编辑

显然,bug 是由下面这行代码产生的

  1. list1[list1.index(" ")], list1[list1.index(chocie)] = list1[list1.index(chocie)], list1[list1.index(" ")]
复制代码


为了方便讨论,我们简化一下问题,考虑下面这个情况

  1. ls = [1, 2]
  2. ls[ls.index(1)], ls[ls.index(2)] = 2, 1  # 试图交换 1、2,使 ls 变为 [2, 1]
  3. print(ls)
复制代码

上面这段代码的运行结果为
  1. [1, 2]
复制代码


可以看到,ls 并未改变

这个问题与楼主遇到的问题本质上是一样的,即在修改列表过程中,调用列表的 index 方法,列表却并未能如预期那样改变

实际上,这种现象出现的原因主要是因为 index 方法调用与修改列表之间存在先后顺序的问题

  1. ls[ls.index(1)], ls[ls.index(2)] = 2, 1
复制代码


上面这行代码进行了如下几个操作
1. 计算 ls.index(1),结果为 0
2. 将 2 赋值给 ls[0],此时 ls 的值为 [2, 2]
3. 计算 ls.index(2)(注意此时 ls 已经不是原来的 [1, 2],而是 [2, 2]),结果为 0
4. 将 1 赋值给 ls[0],ls 的值为 [1, 2]

也就是说 ls 的值经过了这样一个变化:[1, 2] --> [2, 2] --> [1, 2]



下面通过一些代码验证上述想法

  1. class NList(list):
  2.     def index(self, val):
  3.         print(f"当前列表的值为:{self}")
  4.         res = super().index(val)
  5.         print(f"返回值为:{res}")
  6.         return res

  7. nls = NList([1, 2])
  8. nls[nls.index(1)], nls[nls.index(2)] = 2, 1
  9. print(nls)
复制代码

运行结果如下
  1. 当前列表的值为:[1, 2]
  2. 返回值为:0
  3. 当前列表的值为:[2, 2]
  4. 返回值为:0
  5. [1, 2]
复制代码


代码中,定义了一个继承了 list 的类 NList,并重写了 index 方法,使其在调用 index 方法时,打印一些信息

从运行结果中,我们可以看到

在执行 nls.index(2) 这个操作的时候,列表 nls 的值已经变为 [2, 2]

那么 nls.index(2) 就将返回 0,然后再将 1 赋值给 nls[0],最终 nls 的值就为 [1, 2]

所以,看起来 nls 好像 ”从未改变“,实际上,它是经历了一个变化过程,又变回了原来的样子



最后,回到最初的问题

  1. list1[list1.index(" ")], list1[list1.index(chocie)] = list1[list1.index(chocie)], list1[list1.index(" ")]
  2. list1[list1.index(" ")], list1[list1.index(chocie)] = chocie, " "
复制代码


上面这两行代码是等价的,都是试图交换 chocie 和 " " 在 list1 中的位置

但由于 list1.index(chocie) 这一步是发生在 list1[list1.index(" ")] = chocie 之后,所以就可能会发生问题

为什么说是可能,而不是一定呢

看下面的代码

  1. >>> ls = [1, 2]
  2. >>> # ls[ls.index(1)], ls[ls.index(2)] = 2, 1  # 不能交换 ls 中 1 和 2 的位置,上面已解释
  3. >>> # 交换一下赋值顺序
  4. >>> ls[ls.index(2)], ls[ls.index(1)] = 1, 2
  5. >>> ls
  6. [2, 1]   # 1 和 2 成功交换位置
  7. >>> ls[ls.index(2)], ls[ls.index(1)] = 1, 2
  8. >>> ls
  9. [2, 1]   # 1、2 位置不变
复制代码


可以看到在利用 ls[ls.index(2)], ls[ls.index(1)] = 1, 2 成功交换一次之后

再尝试利用 ls[ls.index(2)], ls[ls.index(1)] = 1, 2 交换的时候,并未成功



第一次交换的过程如下:
1. 计算 ls.index(2),结果为 1
2. 将 1 赋值给 ls[1],此时 ls 的值为 [1, 1]
3. 计算 ls.index(1)(注意此时 ls 已经不是原来的 [1, 2],而是 [1, 1]),结果为 0
4. 将 2 赋值给 ls[0],ls 的值为 [2, 1]

也就是说 ls 的值经过了这样一个变化:[1, 2] --> [1, 1] --> [2, 1]

第二次交换的过程如下:
1. 计算 ls.index(2),结果为 0
2. 将 1 赋值给 ls[0],此时 ls 的值为 [1, 1]
3. 计算 ls.index(1)(注意此时 ls 已经不是原来的 [2, 1],而是 [1, 1]),结果为 0
4. 将 2 赋值给 ls[0],ls 的值为 [2, 1]

也就是说 ls 的值经过了这样一个变化:[2, 1] --> [1, 1] --> [2, 1]


上述过程表明

  1. list1[list1.index(" ")], list1[list1.index(chocie)] = chocie, " "
复制代码


如果你不停地输入同样的数字(即 chocie 每次都一样),那么上面这行代码至多只在第一次产生效果

所以,就出现了楼主的图中,第一次输入 5,正常交换,后面再输入 5 无法交换的问题
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2020-3-1 22:35:57 | 显示全部楼层
wp231957 发表于 2020-3-1 22:32
设计有问题吧,移动的时候不还得把方向带着

要移动的数字只有一个方向可移动,本来就是9宫格,8个数字
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2020-3-1 22:43:38 | 显示全部楼层
wp231957 发表于 2020-3-1 22:26
设计有问题吧,移动的时候不还得把方向带着

手机,点错了,最佳答案。。。。。。。。
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2020-3-1 22:45:21 From FishC Mobile | 显示全部楼层
l0stparadise 发表于 2020-3-1 22:43
手机,点错了,最佳答案。。。。。。。。

呵呵,那就取消吧,我也不知道能不能取消
我也是手机,无法验证代码
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2020-3-1 22:46:20 | 显示全部楼层
wp231957 发表于 2020-3-1 22:45
呵呵,那就取消吧,我也不知道能不能取消
我也是手机,无法验证代码

无所谓,帮看看问题在哪儿,感谢~~
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2020-3-2 07:03:41 | 显示全部楼层
本帖最后由 XiaoPaiShen 于 2020-3-2 07:11 编辑

两处修改:
1. 把获取的index赋給变量,然后再交换 -- 分别取两次 index, 再交换,index值会产生错误, 还没研究怎么错的
2. 不能交换时,不能递归调用 move, 直接返回 list1 就行了
  1. import random

  2. def print_chestable(foo):  #定义打印格式,输出九宫格
  3.     num=0
  4.     for i in foo:
  5.         num+=1
  6.         if num%3==0:
  7.             print(i)
  8.         else:
  9.             print(i, end=" ")


  10. def move():  # 定义移动步骤
  11.     global list1  # list1为产生九宫格的1-8,以及一个空格组成,格式如[6, ' ', 7, 8, 4, 3, 1, 5, 2]
  12.     dict1={0:[1,3], 1:[0,2,4],2:[1,5],3:[0,4,6],4:[1,3,5,7],5:[2,4,8],6:[3,7],7:[4,6,8],8:[5,7]}
  13.     # 对空格位置周围出现的其他可移动位置的列表索引号进行编号

  14.     chocie = int(input("请输入要移动的数字:"))  #用户输入要移动的数字

  15.     '''
  16.     判断用户输入要移动的数字是不是在空格周围可移动的的数字中,如果在:
  17.         交换空格位置和用户输入位置数字的值
  18.         返回新的列表
  19.     如果用户输入要移动的数字不在空格周围可移动的的数字中:
  20.         重新运行这个移动步骤
  21.     '''
  22.     if list1.index(chocie) in dict1[list1.index(" ")]:
  23.         indexEmpty = list1.index(" ")
  24.         indexChoice = list1.index(chocie)
  25.         
  26.         list1[indexEmpty], list1[indexChoice] = list1[indexChoice], list1[indexEmpty]
  27.         return list1
  28.     else:
  29.         print('can not move.')
  30.         # move()
  31.         return list1

  32. '''
  33. 定义游戏开始
  34.     进入循环
  35.         执行移动步骤并输出九宫格
  36.         如果排序正确
  37.             输出赢了
  38.             结束循环
  39. '''
  40. def game_bengin(bar):
  41.     while True:
  42.         print_chestable(move())
  43.         if bar ==[1,2,3,4,5,6,7,8," "]:
  44.             print("你赢了,牛逼")
  45.             break


  46. list1=[i for i in range(1,9)]   # 产生[1,2,3,4,5,6,7,8]的列表
  47. list1.append(" ")               # 产生[1,2,3,4,5,6,7,8," "]的列表
  48. random.shuffle(list1)           # 产生[1,2,3,4,5,6,7,8," "]的洗牌后列表
  49. print_chestable(list1)          # 初始化
  50. game_bengin(list1)              # 运行游戏
复制代码
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2020-3-2 10:07:28 | 显示全部楼层
Mike_python 发表于 2020-3-2 10:01
XiaoPaiShen 那输入为空的时候 也会报错

先不说非法输入的事儿,那个好解决。现在正常输入数字就有bug,是index的问题,但不知道原因
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2020-3-2 13:05:22 From FishC Mobile | 显示全部楼层
l0stparadise 发表于 2020-3-2 10:07
先不说非法输入的事儿,那个好解决。现在正常输入数字就有bug,是index的问题,但不知道原因

你用我改的程序,输入数字是可以正常运行的,你来试试,对不对
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2020-3-2 14:12:38 | 显示全部楼层
在东边 发表于 2020-3-2 13:00
显然,bug 是由下面这行代码产生的


写这么长
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2020-3-2 15:09:55 From FishC Mobile | 显示全部楼层
原因是index,index() 函数用于从列表中找出某个值第一个匹配项的索引位置。
是第一个匹配项的位置

打个比方:
假设:list1 = [7, 8, 3, 6, 1, 4, ' ', 2, 5]
九宫格形状:
7 8 3
6 1 4
    2 5

这时我们选择:2
程序将运行:
list1[list1.index(" ")], list1[list1.index(chocie)] = list1[list1.index(chocie)],list1[list1.index(" ")]
运行上面的代码时,list1是分段变化的
先运行:
list1[list1.index(“ ”)] = list1[list1.index(chocie)]把“  ”替换成 2
list1变为[7, 8, 3, 6, 1, 4, 2, 2, 5]
然后程序才会运行:
list1[list1.index(chocie)] = list1[list1.index(“ ”)]
由于index是找出第一个匹配项的位置,所以最后index会返回第一个2即原本“ ”的索引值
即list1变为[7, 8, 3, 6, 1, 4, ' ', 2, 5]
这个结果和原来的list1是一样的,所以九宫个格也不会有变化

这就导致了九宫格里的数字不能向左或向上
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2020-3-2 15:11:14 From FishC Mobile | 显示全部楼层
我在上面发了我的看法,不知道楼主还需要吗
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2020-3-2 15:14:10 | 显示全部楼层
寻风 发表于 2020-3-2 15:11
我在上面发了我的看法,不知道楼主还需要吗

感谢
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2026-3-1 16:10

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表