在扫雷游戏中,将雷均匀地分布在局面中依靠一种布雷算法。

将布雷的位置视为一维数组,其长度为高×宽。
数字 -1 表示 有雷;数字 0 表示非雷。

算法一:朴素的想法

  1. 随机寻找一个位置;
  2. 如果该位置是空的,则布雷;
  3. 如果该位置是雷,那么返回 步骤1;
  4. 直到布雷数到达总雷数。
    1. y = [0] * Row * Column
    2. num_i = 0
    3. while num_i < num:
    4. while True:
    5. idd = random.randint(0, Row * Column - 1) # 产生a, b的一个整数型随机数
    6. if y[idd] != -1:
    7. y[idd] = -1
    8. num_i += 1
    9. break
    经测试,当雷数为99时,算法的运行时间为1.2754秒。但是这种算法在雷数较大时性能急剧下降,因为随机选择的位置大概率是雷。当雷数为479时,算法的运行时间长达33.0841秒。

算法二:算法一改进

算法一的问题在于如果布雷数量很大,可能多次随机出的布雷位置相同,布满特定数量的雷需要的时间增加。

那么只要在每次选择出 布雷 的位置后,将这个位置从下次挑选范围内除去即可。

维护两个列表,no_bomb,is_bomb。前者是没有雷的方格索引,后者是有雷的方格索引。

  1. y = [0]*(Row*Column)
  2. no_bomb = list(range(0,Row*Column))
  3. is_bomb = []
  4. count_bomb = 0
  5. while count_bomb < Num:
  6. Id = random.randint(0,Row*Column - count_bomb - 1)
  7. is_bomb.append(no_bomb[Id])
  8. no_bomb.pop(Id)
  9. count_bomb += 1
  10. for i in is_bomb:
  11. y[i]=-1

算法三:洗牌算法

洗牌算法的步骤为:
Step1:初始化一维局面数组,使得前RowColumn-Num个位置均为0,后Num个位置均为-1
Step2:遍历数组从id= Row
Column-Num到id=RowColumn-1的位置
_*Step3
_:交换当前访问位置与在当前访问位置之前随机选取的位置的值

  1. y = [0]*(Row*Column-Num)
  2. y = y+[-1]*Num
  3. for i in range(Row*Column-Num,Row*Column):
  4. idd = random.randint(0,i-1)
  5. y[idd],y[i] = y[i],y[idd]

算法四:洗牌算法改进

当雷数少于一半时,算法不变;但当雷数多于一半时,我们把非雷看作雷,而把雷看作非雷。这样仅仅添加一个选择语句后,就兼顾了算法在雷数较多与较少时的性能。

  1. if Num<Row*Column/2:
  2. y=[0]*(Row*Column-Num)
  3. y=y+[-1]*Num
  4. for i in range(Row*Column-Num,Row*Column):
  5. idd=random.randint(0,i-1)
  6. y[idd],y[i]=y[i],y[idd]
  7. else:
  8. y=[-1]*Num
  9. y=y+[0]*(Row*Column-Num)
  10. for i in range(Num,Row*Column):
  11. idd=random.randint(0,i-1)
  12. y[idd],y[i]=y[i],y[idd]