用python完成一个数独小游戏

用python完成一个数独小游戏

时隔一年我回来完善我的数独程序了,在原来使用matlab产生数独的基础上,改为python语法,并对其进行扩展功能,改为一个小游戏。
matlab产生数独的原理在我第一篇博客里有比较详细的介绍,matlab产生数独原理,这里不多说
改为python以后代码如下

def daan():                                          #用于产生数独答案
    shudu = np.zeros((9,9),dtype=int)                 #产生全0数组备用
    while (sum(sum(shudu[:,:]))!=405):                #判断数独答案是否正确,简单了点,但很实用
        n = 1
        A = np.zeros((9,9), dtype=int)
        a = [x for x in range(1, 10)]                 #产生1-9数组备用
        b = [x for x in range(1, 10)]
        random.shuffle(b)                              #产生随机1-9数组,作为数独第一行
        A[0,:] = b                                     #赋值
        for i in range(1,9):                            #开始填数
            for j in range(0,9):
                x = A[i,:]                              #取出所在行
                y = A[:,j]                               #取出所在列
                if 0<=j and j<3:
                    z = A[:,0:3]
                elif 3<=j and j<6:
                    z = A[:,3:6]
                else :
                    z = A[:,6:9]
                if 0 <= i and i < 3:
                    z = z[0:3,:]
                elif 3 <= i and i < 6:
                    z = z[3:6,:]
                else:
                    z = z[6:9,:]                         #取出所在宫

                x_pos = np.nonzero(x)[0]                   #取出行,列,宫的所有非零值
                X = np.zeros((len(x_pos)), dtype=int)
                for p in range(0, len(x_pos)):
                    X[p] = x[x_pos[p]]

                y_pos = np.nonzero(y)[0]
                Y = np.zeros((len(y_pos)), dtype=int)
                for p in range(0, len(y_pos)):
                    Y[p] = y[y_pos[p]]

                z_pos = np.transpose(np.nonzero(z))
                Z = np.zeros((len(z_pos)), dtype=int)
                for p in range(0,len(z_pos)):
                    m = z_pos[p,0]
                    n = z_pos[p,1]
                    Z[p] = z[m,n]


                t = list(set(X).union(set(Y)))
                t = list(set(t).union(set(Z)))                 #所有非零值取并集,

                n = list(set(a).difference(set(t)))            # 并集和a取差集,判断哪些数还可以填

                try:
                    L = len(n)                                #判断是否还有备选数
                except BaseException as e:
                    L = 0

                r = random.random()

                h = math.ceil(r*L)                            #备选数中随机选择一个
                try:
                    A[i,j] = n[h-1]                            #进行赋值
                except BaseException as e:
                    n = 2                                      #报错则说明之前的填数有误
                    break
            if n == 2:
                break
        if n == 2:
            continue                                          #重新开始循环
        shudu = A                                              #81个数全部正确,则赋值
    return shudu                                               #返回

这样可以产生一个标准数独作为答案
下面可以随机挖空产生一个数独作为题面

def chansheng(shudu,grade):                                  #随机挖空,产生数独题面
    for i in range(0,9):
        b = [x for x in range(0, 9)]
        random.shuffle(b)
        for j in range(0,grade):
            shudu[i,b[j]] = 0
    return shudu

grade作为输入控制数独难度,每一行挖掉几个数字

然后是修改数独函数,用来让用户填数

def xiugai(shudu,pos,pos_nonling):                          #输入参数,对数独进行修改
    x = int(pos/100)                                        #得到行值
    y = int((pos%100)/10)                                  #得到列值
    for i in range(0,len(pos_nonling)):                     #pos_nonling代表题面非零值的位置
        a = int(pos_nonling[i,0])
        b = int(pos_nonling[i,1])
        if x-1 == a and y-1 == b:
            print('此数不可修改,请重新输入')                    #这些位置的数字不可修改
            n = 2
            return shudu,n
    num = int((pos%100)%10)                                   #若不是这些位置,则可进行修改
    shudu[x-1,y-1] = num
    n = 1                  #是否正确修改的标志位
    return shudu,n           #返回修改后的结果和标志位

检查填入的数字是否正确

def jiancha(shudu,pos,shibai):                     #检查填入数字是否正确
    a = int(pos/100)                                        #得到行值
    b = int((pos%100)/10)                                  #得到列值
    c = int((pos%100)%10)                                   #得到所填数字
    shudu[a-1,b-1] = 0

    x = shudu[a-1, :]
    y = shudu[:, b-1]
    if 0 <= b-1 and b-1 < 3:
        z = shudu[:, 0:3]
    elif 3 <= b-1 and b-1 < 6:
        z = shudu[:, 3:6]
    else:
        z = shudu[:, 6:9]


    if 0 <= a-1 and a-1 < 3:
        z = z[0:3, :]
    elif 3 <= a-1 and a-1 < 6:
        z = z[3:6, :]
    else:
        z = z[6:9, :]

    x_pos = np.nonzero(x)[0]
    X = np.zeros((len(x_pos)), dtype=int)
    for p in range(0, len(x_pos)):
        X[p] = x[x_pos[p]]

    y_pos = np.nonzero(y)[0]
    Y = np.zeros((len(y_pos)), dtype=int)
    for p in range(0, len(y_pos)):
        Y[p] = y[y_pos[p]]

    z_pos = np.transpose(np.nonzero(z))
    Z = np.zeros((len(z_pos)), dtype=int)
    for p in range(0, len(z_pos)):
        m = z_pos[p, 0]
        n = z_pos[p, 1]
        Z[p] = z[m, n]

    t = list(set(X).union(set(Y)))
    t = list(set(t).union(set(Z)))                          #以上和产生答案逻辑相同,获取所有不可填数字

    if c in t:                                                #与不可填数字相同
        shibai = shibai+1
        print('此处已经不能填', c)
        print("您已失败%d次" % (shibai))
        print("剩余失败次数:", shibaicishu - shibai)
        shudu[a-1, b-1] = 0                                   #抹除这次填数
        return  shibai
    else:
        shudu[a-1, b-1] = c                                  #不同则进行赋值
        return  shibai

判断游戏是否结束,是否全部填完

def jieshu(shudu):                                      #检查游戏是否结束
    if sum(sum(shudu[:, :])) == 405:
        return 1
    else:
        return 2

对每一次的数独进行展示

def show(shudu,pos_nonling):                          #对每一步的数独结果进行展示
    for i in range(0,10):
        for j in range(0,10):
            if i == 0 and j == 0:                         #(1,1)位置空白,为了好看
                print('\t',end='')
            if i == 0 and j != 0:
                print('\033[34m',j,'\t',end='')#紫色         #第一行打入用紫色写入横坐标
                if j == 9:
                    print('\n')                               #结束后换行
            if i != 0 and j == 0:
                print('\033[34m',i,'\t',end='')              #第一列用紫色打入列坐标
            if i != 0 and j != 0:
                if shudu[i-1,j-1] == 0:
                    print('\033[0m',' ', '\t', end='')          #被挖掉得空不进行显示
                else:
                    for m in range(0, len(pos_nonling)):         #判断是否为题面固定数字
                        a = int(pos_nonling[m, 0])
                        b = int(pos_nonling[m, 1])
                        if i - 1 == a and j - 1 == b:
                            key = 1
                            break
                        else:
                            key = 2
                    if key == 1:
                        print('\033[0m', shudu[i-1,j-1], '\t', end='')               #题面固定数字用白色显示
                    else:
                        print('\033[31m', shudu[i - 1, j - 1], '\t', end='')         #可填数字用红色显示
                if j == 9:
                    print('\n')                                                        #每行结尾换行

最后,主函数

if __name__ == '__main__':


    print('游戏开始')
    global shibai
    shibai = 0    #用来统计失败次数


    try:
        grand = int(input('请选择难度(1——6):'))                                          #每行挖掉几个空
        while (grand < 1 or grand > 6):                                           #最少挖一个,最多6个
            try:
                grand = int(input('您的输入有误,请输入1——6之间的任意一个整数:'))
            except BaseException as e:
                continue
    except BaseException as e:
        grand = 0
        while(grand<1 or grand>6):
            try:
                grand = int(input('您的输入有误,请输入1——6之间的任意一个整数:'))
            except BaseException as e:
                continue

    try:
        shibaicishu = int(input('请选择可失败次数:'))                           #允许输入错误的次数
        while (shibaicishu < 1):
            try:
                shibaicishu = int(input('您的输入有误,请输入一个正整数:'))
            except BaseException as e:
                continue
    except BaseException as e:
        shibaicishu = 0
        while(shibaicishu<1):
            try:
                shibaicishu = int(input('您的输入有误,请输入一个正整数:'))
            except BaseException as e:
                continue

    shudu_answer= daan()                                           #产生数独


    shudu_question = chansheng(shudu_answer,grand)               #挖空
    pos_nonling = np.transpose(np.nonzero(shudu_question))         #获取非零元素位置
    show(shudu_question,pos_nonling)                             #展示

    while(1):
        n = 2                                               #标志位,输入是否正确
        while(n == 2):
            try:
                pos = int(input('请输入要输入的数字:'))          #输入一个三位数,百位代表行值,十位代表列值,个位代表要填的数,所以最大999,最小111
                while (pos < 111 or pos > 999):
                    try:
                        pos = int(input('您的输入有误,请输入一个三位数,百位代表行值,十位代表列值,个位代表要填的数:'))
                    except BaseException as e:
                        continue
            except BaseException as e:
                pos = 0
                while (pos < 111 or pos > 999):
                    try:
                        pos = int(input('您的输入有误,请输入一个三位数,百位代表行值,十位代表列值,个位代表要填的数:'))
                    except BaseException as e:
                        continue
            [shudu_change,n] = xiugai(shudu_question,pos,pos_nonling)                                        #修改数独

        shibai = jiancha(shudu_change,pos,shibai)                                                            #判断是否错误
        if shibai == shibaicishu:                                                                            #失败次数和预先设定一样,则输
            key_finish = 1
            break
        show(shudu_change,pos_nonling)
        stop = jieshu(shudu_change)                   #判断是否全部填完
        if stop == 1:
            key_finish = 2
            break
    if key_finish == 1:                                #标志位
        print('游戏结束,挑战失败')
    else:
        print('恭喜,挑战成功')

实测了一下,在pycharm里跑没有问题,运行如下,蓝色代表行列坐标值,白色为固定数字,红色为用户填入但是在cmd里运行出示问题,没有颜色显示,在这里插入图片描述
但是换成Windows terminal以后就可以了,运行结果很漂亮在这里插入图片描述而且我没有办法打包生成exe文件,让我非常苦恼
如果有人可以成功生成exe的话十分希望可以和我联系一下,并且发我一份,十分感谢。
可以发我邮箱:tai_ge@163.com

  • 7
    点赞
  • 59
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值