鱼C论坛

 找回密码
 立即注册
查看: 1168|回复: 0

[技术交流] 袋马计划-生成完整数独

[复制链接]
发表于 2018-4-14 00:13:49 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
使用随机数生成完整的数独,不使用已有的答案交换行列及数字
当前代码有一定几率使spyder内核崩溃,原因不详

  1. # -*- coding: utf-8 -*-
  2. """
  3. Created on Fri Apr 13 20:49:47 2018

  4. @author: Administrator
  5. """

  6. import numpy as np
  7. from random import sample as sm
  8. from itertools import permutations as pe

  9. cho=np.random.choice
  10. ar=np.arange
  11. meveryPos=list(pe(range(3),3))
  12. def mgenerate():
  13.     mwhole=ar(81).reshape((9,9))#整个数独棋盘
  14.     #下面这个循环怎么精简一下?
  15.     for i in range(0,9,3):
  16.         for j in range(0,9,3):
  17.             mwhole[i:i+3,j:j+3]=cho(ar(9),(3,3),0)#给9个九宫格随机赋值0-8
  18.     #对每三九宫格构成的行、列调整
  19.     def madjust(mparts):
  20.         #记录数字的列位置,9个子列表分别记录9个数字的列数字
  21.         mdigitColumn=[[] for i in range(9)]
  22.         for i in range(9):
  23.             for j in range(3):
  24.                 mdigitColumn[mparts[j,i]].append(i)#记录数字的列位置
  25.         #记录数字在每一行的可能性,初始为6种随机位置(3*2*1)
  26.         mdigitPos=[sm(meveryPos,6) for _ in range(9)]
  27.         #当确定一个数字的位置后,去掉其他数字在这个位置的可能性
  28.         def deleteUnpossible(mnowDigit,mdigitPos):
  29.             #记录起始状态,当以下循环确定下一个数字导致其他数字可能性为0时,恢复状态
  30.             temp=mnowDigit,mdigitPos[:]
  31.             #循环遍历当前数字的每一种可能,因为初始化可能值时已使用随机数,此处选择不必随机
  32.             for meachpos in mdigitPos[mnowDigit][:]:
  33.                 #每次循环开始说明没有找到解,需要重新赋值,应该再写一个过程?
  34.                 #应该引用副本,害我找了一个晚的bug
  35.                 mdigitPos=temp[1][:]
  36.                 mnowDigit=temp[0]+0
  37.                 #修改当前数字的可能性为当前遍历的可能性
  38.                 mdigitPos[mnowDigit]=[meachpos]
  39.                 #记录当前数字选择后,被占用的位置,用于后面的比较
  40.                 mtakenPossition=list(zip(mdigitColumn[mnowDigit],mdigitPos[mnowDigit][0]))
  41.                 #删除当前数字以外的其他数字的不可能性
  42.                 for eachdigit in set(range(9))-set([mnowDigit]):
  43.                     #矛盾检查,查找每一种可能是否和已被占用的位置一致,任意位置存在说明不可能
  44.                     mdigitPos[eachdigit]=[eachpos for eachpos in mdigitPos[eachdigit] if sum(map(lambda x:list(zip(mdigitColumn[eachdigit],eachpos))[x]==mtakenPossition[x],range(3)))==0]
  45.                     #任意数字的可能性为空,都不再继续判断,退出循环继续下一个可能性
  46.                     if mdigitPos[eachdigit]==[]:break
  47.                 #循环没有退出,表明当前数字的可能性不影响其他数字,继续
  48.                 else:
  49.                     #下一个判断的数字,优先选择可能性最少的且不唯一的,这样写会导致虽然某个数字只有一种可能性,
  50.                     #但是没有对这种可能性进行矛盾检查,会出现位置重复,#这个bug又耗了我2个晚上
  51.                     mnowDigit=mdigitPos.index(min(mdigitPos,key=lambda x:len(x) if len(x)!=1 else 99))
  52.                     #因为上面图方便,下面这里不得不检查合法性
  53.                     #当mnowDigit==0,说明每个数字可能性唯一,同时要求所有数字的行位置和为9
  54.                     #即9个数字的行位置有三个为0,三个为1,三个为2,3个每个九宫格每个都要如此
  55.                     if mnowDigit==0 and sum(i==9 for i in np.sum(np.array(list(map(lambda x:x[0],mdigitPos))),axis=0))==3:
  56.                         #当满足各个数字可能性唯一性条件,退出递归,返回行位置
  57.                         return mdigitPos
  58.                     #进入递归
  59.                     mdigitPos=deleteUnpossible(mnowDigit,mdigitPos)
  60.                     #退出递归时,如果为0,说明没有找到解,继续循环,否则继续退出递归
  61.                     if mdigitPos:return mdigitPos
  62.             #循环结束没有找到解,返回0
  63.             return 0
  64.         #从数字0开始,没必要再随机
  65.         #因为推论:任意随机九宫格必有解,所以不必对结果判断
  66.         mdigitPos=deleteUnpossible(0,mdigitPos)
  67.         #给区域赋值,向量和列表一样,传的是对象的引用,结果修改以后不必返回???
  68.         for i in range(9):
  69.             for j in zip(mdigitPos[i][0],mdigitColumn[i]):
  70.                 mparts[j]=i
  71.     #整个数独分9个九宫格,每次判断一行三个,一列三个
  72.     for i in range(0,9,3):
  73.         madjust(mwhole[i:i+3])
  74.         madjust(mwhole[:,i:i+3].T)
  75.     #打印,并对行列、九宫格验证
  76.     print(mwhole+1)
  77.     print('行唯一性',[len(set(mwhole[i])) for i in range(9)])
  78.     print('列唯一性',[len(set(mwhole[:,i])) for i in range(9)])
  79.     print('九宫格唯一性',[len(set(list(mwhole[i:i+3,j:j+3].reshape(1,9)[0]))) for i in range(0,9,3) for j in range(0,9,3)])
  80.    
  81. mgenerate()
复制代码
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-4-19 03:09

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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