1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
| import re import copy
sudoku_template1 = [[1,0,0,0,0,0,0,0,0], [0,2,0,0,0,0,0,0,0], [0,0,3,0,0,0,0,0,0], [0,0,0,4,0,0,0,0,0], [0,0,0,0,5,0,0,0,0], [0,0,0,0,0,6,0,0,0], [0,0,0,0,0,0,7,0,0], [0,0,0,0,0,0,0,8,0], [0,0,0,0,0,0,0,0,9]]
sudoku_template2 = [[8,0,0,0,0,0,0,0,0], [0,0,3,6,0,0,0,0,0], [0,7,0,0,9,0,2,0,0], [0,5,0,0,0,7,0,0,0], [0,0,0,0,4,5,7,0,0], [0,0,0,1,0,0,0,3,0], [0,0,1,0,0,0,0,6,8], [0,0,8,5,0,0,0,1,0], [0,9,0,0,0,0,4,0,0]]
def crack_it(sudoku=sudoku_template1): '''主函数,输入数独进行运算,如未输入则调用默认数独,格式为9x9的二维列表''' init_sudoku = str_to_num(copy.deepcopy(sudoku)) if is_valid_sudoku(sudoku): candidate_list = filter_candidate_list(init_sudoku, init_candidate_list(init_sudoku), start=0) cracked_sudoku = fill_blank(init_sudoku, candidate_list, start=0) print(cracked_sudoku) print_sudoku(cracked_sudoku) return cracked_sudoku else: return '请检查一下输入是否有误- -0'
def str_to_num(data): '''初步校验+统一格式,空字符转0,无效字符转0''' for i in range(9): for j in range(9): if re.match('[1-9]', str(data[i][j])): data[i][j] = int(data[i][j]) elif re.match('', str(data[i][j])): data[i][j] = 0 else: data[i][j] = 0 return data
def is_valid_sudoku(data): '''判断整个数独是否有效''' for y in range(9): for x in range(9): if data[y][x] > 9: return False
if data[y][x] != 0 and data[y].count(data[y][x]) > 1: return False
for col in range(9): if data[y][x] != 0 and col != y: if data[col][x] == data[y][x]: return False
for i in range(3): for j in range(3): if data[y][x] != 0 and (i+3*(y//3), j+3*(x//3)) != (y, x): if data[i+3*(y//3)][j+3*(x//3)] == data[y][x]: return False return True
def init_candidate_list(data): '''初始化建立一个数独的备选数列表,一个空格就对应其坐标以及填上1~9的备选数字,格式为81x9的二维列表''' data_list = [] for y in range(9): for x in range(9): if data[y][x] == 0: data_list.append([(x, y), [1, 2, 3, 4, 5, 6, 7, 8, 9]]) return data_list
def filter_candidate_list(data, data_list, start): '''对数独的备选数表进行过滤,删除无效的备选数''' for blank_index in range(start, len(data_list)): data_list[blank_index][1] = [] for num in range(1,10): if is_valid_num(data, data_list[blank_index][0][0], data_list[blank_index][0][1], num): data_list[blank_index][1].append(num) return data_list
def is_valid_num(data, x, y, num): '''输入数独、坐标、数字,判断该位置填入该数字是否合理''' if data[y].count(num) > 0: return False
for col in range(9): if data[col][x] == num: return False
for a in range(3): for b in range(3): if data[a+3*(y//3)][b+3*(x//3)] == num: return False return True
def fill_blank(data, data_list, start): ''' 核心函数,递归尝试代入备选数,类似深度优先遍历算法。 一旦某位置填入为True(由is_valid_num函数判断),则开始下一位置的填入;若某位置填入为False,则return回上一级。 参数解释: data: 数独矩阵,二维列表 data_list: 备选数表,二维列表 start: 递归进行的位置,对应data_list的下标 ''' all_data = [] if start < len(data_list): one = data_list[start] for num in one[1]: if is_valid_num(data, one[0][0], one[0][1], num): data[one[0][1]][one[0][0]] = num tem_data = fill_blank(data, data_list, start+1) if tem_data: return tem_data data[one[0][1]][one[0][0]] = 0 else: return data
def print_sudoku(data): '''打印数独到控制台''' print('>>> 破解结果:') for i in range(9): for j in range(9): print('{:^3}'.format(data[i][j]), end='') print('') print('')
if __name__ == '__main__': l = [ [0,0,5,3,0,0,0,0,0], [8,0,0,0,0,0,0,2,0], [0,7,0,0,1,0,5,0,0], [4,0,0,0,0,5,3,0,0], [0,1,0,0,7,0,0,0,6], [0,0,3,2,0,0,0,8,0], [0,6,0,5,0,0,0,0,9], [0,0,4,0,0,0,0,3,0], [0,0,0,0,0,9,7,0,0], ] crack_it(l)
result = [[1, 4, 5, 3, 2, 7, 6, 9, 8], [8, 3, 9, 6, 5, 4, 1, 2, 7], [6, 7, 2, 9, 1, 8, 5, 4, 3], [4, 9, 6, 1, 8, 5, 3, 7, 2], [2, 1, 8, 4, 7, 3, 9, 5, 6], [7, 5, 3, 2, 9, 6, 4, 8, 1], [3, 6, 7, 5, 4, 2, 8, 1, 9], [9, 8, 4, 7, 6, 1, 2, 3, 5], [5, 2, 1, 8, 3, 9, 7, 6, 4]] print('flag{',end='') for i in result: for j in i: print(j,end='') print('}')
|