データ整理
WEB
ゲーム
パズル
|
プログラム例パズルパズルを解くプログラム例を示します. 目次数独数独は暇つぶしに調度良いパズルです.単純なルールなので,結構ハマります.ルールについては,「数独-Wikipedia」を参照下さい. プログラム001 '''数独を計算するモジュール''' 002 import itertools 003 import numpy as np 004 import copy 005 import sys 006 import time 007 008 009 class Solution: 010 '''数独を計算するクラス''' 011 def __init__(self, argv): 012 ''' コンストラクター: 引数のチェックとファイルの読み込み ''' 013 def error_arg(): 014 print('エラー !! 入力の引数の数が違います') 015 print(argv) 016 exit() 017 018 def error_num(): 019 print('入力が 9X9 ではありません') 020 print(self.data_org) 021 exit() 022 023 def error_input_element(): 024 print('入力に 整数: 0 - 9 と異なるものがあります') 025 print(self.data_org) 026 exit() 027 028 allowed = [x for x in range(10)] 029 check = [[False for j in range(9)] for i in range(9)] 030 if len(argv) != 2: error_arg() 031 self.file = argv[1] 032 self.data_org = np.genfromtxt(self.file, delimiter=' ', dtype=int) 033 if(self.data_org.shape[0] != self.data_org.shape[0] != 9):error_num() 034 self.N = self.data_org.shape[0] 035 for i, j in itertools.product(range(9), range(9)): 036 check[i][j] = self.data_org[i][j] in allowed 037 check = np.array(check) 038 if not check.all(): error_input_element() 039 040 041 def print_Question(self): 042 '''読み込んだデータを表示する''' 043 print('問題はつぎのとおり') 044 print(20*'-') 045 for i in range(self.N): 046 for j in range(self.N): 047 if j==self.N-1: 048 if self.data_org[i][j] == 0: 049 print('{0:s}\n'.format('.'), end='') 050 else: 051 print('{0:1d}\n'.format(self.data_org[i][j]), end='') 052 else: 053 if self.data_org[i][j] == 0: 054 print('{0:s} '.format('.'), end='') 055 else: 056 print('{0:1d} '.format(self.data_org[i][j]), end='') 057 print(20*'-') 058 print('\n') 059 060 061 def print_Soluiton(self, sol): 062 '''解を表示する''' 063 print('解はつぎのとおり') 064 print(20*'-') 065 for i in range(self.N): 066 for j in range(self.N): 067 if j==self.N-1: 068 print('{0:1d}\n'.format(sol[i][j][0]), end='') 069 else: 070 print('{0:1d} '.format(sol[i][j][0]), end='') 071 print(20*'-') 072 print('\n') 073 074 075 def Num_det(self, sol): 076 '''確定している要素数を数える''' 077 n = 0 078 for i, j in itertools.product(range(self.N), range(self.N)): 079 if len(sol[i][j]) == 1: n += 1 080 return n 081 082 083 def Num_item(self, sol): 084 '''確定および候補の要素の合計数を数える''' 085 N_arr = [[len(sol[i][j]) for j in range(self.N)] for i in range(self.N)] 086 return int(np.sum(np.array(N_arr))) 087 088 089 def Num_zero(self, sol): 090 '''確定や候補の要素の数がゼロを数える''' 091 N_zero = 0 092 for i, j in itertools.product(range(self.N), range(self.N)): 093 if len(sol[i][j]) == 0: 094 N_zero += 1 095 return N_zero 096 097 098 def is_finished(self, sol): 099 '''解が求められたか否かの判断を行う''' 100 return bool(self.Num_zero(sol)==0 and self.Num_item(sol) == self.N*self.N) 101 102 103 def change_solution(self, is_print=False): 104 '''読み込んだデータを解のデータに変換''' 105 sol = [[0]*self.N for i in range(self.N)] 106 for i, j in itertools.product(range(self.N), range(self.N)): 107 if self.data_org[i][j] == 0: 108 sol[i][j] = [x for x in range(1, self.N+1)] 109 else: 110 sol[i][j] = [self.data_org[i][j]] 111 if is_print: 112 print(sol) 113 return sol 114 115 116 def check_simple(self, sol): 117 '''縦と横,小行列で確定要素を削除''' 118 N_item_old = self.Num_item(sol) 119 while(True): 120 for i, j in itertools.product(range(self.N), range(self.N)): 121 if len(sol[i][j]) == 1: # 確定している値を行の値を削除 122 del_num = sol[i][j][0] 123 for k in range(0, self.N): 124 if k != j and del_num in sol[i][k]: 125 sol[i][k].remove(del_num) 126 if k != i and del_num in sol[k][j]: 127 sol[k][j].remove(del_num) 128 i0, j0 = i//3, j//3 129 for i_sft, j_sft in itertools.product(range(3), range(3)): 130 ki,kj = 3*i0+i_sft, 3*j0+j_sft 131 if ki != i and kj != j and del_num in sol[ki][kj]: 132 sol[ki][kj].remove(del_num) 133 N_item_new = self.Num_item(sol) 134 if N_item_old == N_item_new: 135 break 136 else: 137 N_item_old = N_item_new 138 return sol 139 140 141 def check_same_item(self, sol): 142 '''縦と横,3x3の中の要素に独立した値を確定させる''' 143 N_item_old = self.Num_item(sol) 144 while(True): 145 for i, j in itertools.product(range(self.N), range(self.N)): 146 for test in sol[i][j]: 147 for k in range(self.N): 148 if k!=j and test in sol[i][k]: break 149 else: 150 sol[i][j] = [test] 151 152 for k in range(self.N): 153 if k!=i and test in sol[k][j]: break 154 else: 155 sol[i][j] = [test] 156 157 i0, j0 = i//3, j//3 158 for i_sft, j_sft in itertools.product(range(3), range(3)): 159 ki,kj = 3*i0+i_sft, 3*j0+j_sft 160 if not (ki==i and kj==j) and test in sol[ki][kj]: break 161 else: 162 sol[i][j] = [test] 163 N_item_new = self.Num_item(sol) 164 if N_item_old == N_item_new: 165 break 166 else: 167 N_item_old = N_item_new 168 return sol 169 170 171 172 def candidate(self, sol): 173 '''解の候補を返す''' 174 cnddt = [] 175 for i, j in itertools.product(range(self.N), range(self.N)): 176 nk = len(sol[i][j]) 177 if 1 < nk: 178 for k in range(nk): 179 cnddt.append([i,j, sol[i][j][k]]) 180 return cnddt 181 182 183 '''メイン''' 184 if __name__ == "__main__": 185 start = time.time() 186 sudoku = Solution(argv=sys.argv) 187 sudoku.print_Question() 188 solution = sudoku.change_solution(is_print=False) 189 190 while(True): 191 N_item_old = sudoku.Num_item(solution) 192 solution = sudoku.check_simple(solution) 193 solution = sudoku.check_same_item(solution) 194 N_item_new =sudoku.Num_item(solution) 195 if N_item_old == N_item_new: break 196 197 if not sudoku.is_finished(solution): 198 while(True): 199 solution_org = copy.deepcopy(solution) 200 candidate = sudoku.candidate(solution_org) 201 N_item_org_old = sudoku.Num_item(solution_org) 202 for i in range(len(candidate)): 203 solution = copy.deepcopy(solution_org) 204 solution[candidate[i][0]][candidate[i][1]]=[candidate[i][2]] 205 while(True): 206 N_item_old = sudoku.Num_item(solution) 207 solution = sudoku.check_simple(solution) 208 solution = sudoku.check_same_item(solution) 209 N_item_new =sudoku.Num_item(solution) 210 if sudoku.Num_zero(solution)!=0: 211 d_elem = np.array(solution_org[candidate[i][0]][candidate[i][1]]) 212 d_elem = np.delete(d_elem, np.argwhere(d_elem==candidate[i][2])) 213 solution_org[candidate[i][0]][candidate[i][1]]=list(d_elem) 214 break 215 if N_item_old == N_item_new: break 216 if sudoku.is_finished(solution) == True: break 217 if sudoku.is_finished(solution) == True: break 218 N_item_org_new = sudoku.Num_item(solution_org) 219 print('N: {0:d}\t{1:d}'.format(N_item_org_old, N_item_org_new)) 220 if N_item_org_old == N_item_org_new: break 221 222 if sudoku.is_finished(solution): 223 sudoku.print_Soluiton(solution) 224 else: 225 print('解を求めることができませんでした.') 226 print(solution_org) 227 228 elapsed_time = time.time() - start 229 print("計算時間: {0} [秒]".format(elapsed_time)) インプットと実行方法プログラムのインプットデータの例を以下に示します. #ナンプレ 7 上級編 Question 100
0 0 0 0 0 0 0 0 0
1 6 0 0 0 0 0 5 7
8 0 0 6 0 3 0 0 4
3 0 0 5 0 4 0 0 1
0 2 0 0 9 0 0 6 0
0 0 8 0 0 0 5 0 0
0 0 7 0 0 0 2 0 0
0 0 0 7 0 6 0 0 0
0 0 0 3 4 1 0 0 0
実行コマンドは以下のとおりです. $ python3 Q100.txt 実行結果は,以下のとおりです. 問題はつぎのとおり -------------------- . . . . . . . . . 1 6 . . . . . 5 7 8 . . 6 . 3 . . 4 3 . . 5 . 4 . . 1 . 2 . . 9 . . 6 . . . 8 . . . 5 . . . . 7 . . . 2 . . . . . 7 . 6 . . . . . . 3 4 1 . . . -------------------- 解はつぎのとおり -------------------- 7 9 3 4 1 5 6 8 2 1 6 4 2 8 9 3 5 7 8 5 2 6 7 3 9 1 4 3 7 9 5 6 4 8 2 1 5 2 1 8 9 7 4 6 3 6 4 8 1 3 2 5 7 9 4 1 7 9 5 8 2 3 6 9 3 5 7 2 6 1 4 8 2 8 6 3 4 1 7 9 5 -------------------- 計算時間: 0.13692736625671387 [秒] ページ作成情報参考資料更新履歴
|