数独小游戏

无聊之余,写了一些小游戏(当然,也有参考别人的代码),当作练手打发时间

(本数独可能并不平衡,可能存在多解,提示功能只提供最基本的提示,避免依赖提示)

import random
import math

sudoku = []


# 生成一个随机的数组
def random_list():
    num_list = [1, 2, 3, 4, 5, 6, 7, 8, 9]
    random.shuffle(num_list)
    return num_list


def print_grid(arr):
    print('------------------------------')
    for i in range(9):
        for j in range(9):
            if arr[i][j] == 0:
                print('.', end='')
            else:
                print(arr[i][j], end='')
            if j % 3 == 2:
                print(end='   ')
            else:
                print(end=' ')
        print()
        if i % 3 == 2 and i != 8:
            print()
    print('------------------------------')


#生成数独,返回需要填格数
def shudu(arr):
    xx = random.randint(50, 51)
    x = xx
    while x > 0:
        x -= 1
        y = 0
        while arr[y // 9][y % 9] == 0:
            y = random.randint(0, 80)
            # print(y)
            # print(f'x={y // 9},y={y // 9}')
        arr[y // 9][y % 9] = 0

    print_grid(arr)
    return xx

#单元格判断
def bo(x, y, value, a):
    if a[x][y] != 0:
        print('已有数字')
        return False
    else:
        #判断行列不冲突
        for i in range(0, 9):
            if a[x][i] == value or a[i][y] == value:
                return False
        #判断所在格子属于的3*3方块不冲突
        xx = x // 3 *3
        yy = y // 3 *3
        for i in range(0, 3):
            if bo and xx + i < 8:
                for j in range(0, 3):
                    if yy + j < 8:
                        if a[xx + i][yy + j] == value:
                            return False
    return True
    
#数独操作
def caozuo(x, y, value, a):
        if bo(x, y, value, a):
            a[x][y] = value
            return True
        else:
            print('填入失败')
            return False

#最终判断结果是否合法
def check(a):
    for i in range(0, 9):
        l1 = []
        l2 = []
        l3 = []
        for j in range(0, 9):
            if a[i][j] in l1 or a[j][i] in l2 or a[i//3*3+j//3][i%3*3+j%3] in l3:
                print(f'出现重复:x={i},y={j}')
                return False
            l1.append(a[i][j])
            l2.append(a[j][i])
            l3.append(a[i // 3 * 3 + j // 3][i % 3 * 3 + j % 3])
    return True

def get_row(row):
    row_arr = []
    for v in sudoku[row]:
        if v == 0:
            continue
        row_arr.append(v)
    return row_arr


def get_col(col):
    col_arr = []
    for i in range(9):
        val = sudoku[i][col]
        if val == 0:
            continue
        col_arr.append(sudoku[i][col])
    return col_arr


def get_block(num):
    col_arr = []
    seq = num % 3
    col_end = 9 if seq == 0 else seq * 3
    row_end = int(math.ceil(num / 3) * 3)
    for i in range(row_end - 3, row_end):
        for j in range(col_end - 3, col_end):
            val = sudoku[i][j]
            if val != 0:
                col_arr.append(sudoku[i][j])
    return col_arr


def get_block_seq(row, col):
    col_seq = int(math.ceil((col + 0.1) / 3))
    row_seq = int(math.ceil((row + 0.1) / 3))
    return 3 * (row_seq - 1) + col_seq


def get_enable_arr(row, col):
    avail_arr = random_list()
    seq = get_block_seq(row, col)
    block = get_block(seq)
    row = get_row(row)
    col = get_col(col)
    unable_arr = list(set(block + row + col))
    for v in unable_arr:
        if v in avail_arr:
            avail_arr.remove(v)
    return avail_arr


#开始
def begin(result):   
    num = shudu(result)
    b=[]
    while num > 0:
        print_grid(result)
        print(f'剩余{num}格')
        try:
            s = input('请输入:').split(' ')

            #撤退
            if 'b' in s:
                break_one(b, result)
                num += 1
                continue

            #提示
            if 't' in s:
                tishi(result)
                continue

            x = int(s[0]) - 1
            y = int(s[1]) - 1
            v = int(s[2])
            if caozuo(x, y, v, result):
                b.append({'x': x, 'y': y})
                num -= 1
        except Exception:
            continue
        
    print_grid(result)
    if check(result):
        print('完成')
    else:
        print('失败')

#后退操作
def break_one(b, a):
    if b:
        one = b.pop()
        a[one['x']][one['y']] = 0
    else:
        print('不可后退')
    return

#提示
def tishi(a):
    for i in range(9):
        for j in range(9):
            if a[i][j] != 0:
                continue
            b = 1
            value = 0
            for k in range(1, 10):
                if bo(i, j, k, a):
                    if not value:
                        value = k
                    else:
                        b = 0
                        break
            if b:
                print(f'提示:x={i+1}, y={j+1}, v={value}')
                return
    print('无提示!')
    return

#输入方块编号,填充数独
def square(i):
    i -= 1
    num_list = random_list()
    for row in range((i // 3)*3, (i // 3)*3+ 3):
        for col in range((i % 3) * 3, (i % 3) * 3):
            sudoku[row][col] = num_list.pop()
    
                        
if __name__ == "__main__":
    # 初始化一个9行9列的数组
    sudoku = [[0 for i in range(9)] for j in range(9)]

    #填充1,5,9号方块
    square(1)
    square(5)
    square(9)
    
    box_list = []
    for row in range(9):
        for col in range(9):
            if sudoku[row][col] == 0:
                box_list.append({'row': row, 'col': col})
    
    i = 0
    can_num = {}
    count = 0
    while i < len(box_list):
        count += 1
        position = box_list[i]
        row = position['row']
        col = position['col']
        key = '%dx%d' % (row, col)
        # print(key)
        if key in can_num:
            enable_arr = can_num[key]
        else:   
            enable_arr = get_enable_arr(row, col)
            can_num[key] = enable_arr
        # print(can_num)
        # x=input('回车')

        if len(enable_arr) <= 0:
            i -= 1
            if key in can_num:
                del (can_num[key])
            sudoku[row][col] = 0
            continue
        else:
            sudoku[row][col] = enable_arr.pop()
            i += 1

    result = []
    for i in range(0,9):
        result.append(sudoku[i].copy())
    
    print_grid(sudoku)
    #开始
    begin(result)
    

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值