数独ソルバーを作成してみました
いくつか機能追加したかったり、終了後に再度起動できるようにしたかったりするんですがいったん完成で。
from matplotlib.pyplot import box
import pygame
from pygame.locals import *
import sys
import copy
class Sudoku():
def __init__(self):
# pygame初期化
pygame.init()
# キャンバス作成
self.SURFACE = pygame.display.set_mode((450, 550))
# タイトル作成
pygame.display.set_caption("GAMEをつくろう")
# フォント指定
self.font = pygame.font.Font(None, 40)
self.box = [0]*81
self.buttons = []
self.wait_input = False
self.pos = -1
self.can_input = True
self.button_text = "START"
self.end_flag = False
self.clear_flag = False
for i in range(9):
for j in range(9):
self.buttons.append(pygame.Rect(j*50, i*50, 49, 49))
self.box_checker = [
[0, 1, 2, 9, 10, 11, 18, 19, 20],
[3, 4, 5, 12, 13, 14, 21, 22, 23],
[6, 7, 8, 15, 16, 17, 24, 25, 26],
[27, 28, 29, 36, 37, 38, 45, 46, 47],
[30, 31, 32, 39, 40, 41, 48, 49, 50],
[33, 34, 35, 42, 43, 44, 51, 52, 53],
[54, 55, 56, 63, 64, 65, 72, 73, 74],
[57, 58, 59, 66, 67, 68, 75, 76, 77],
[60, 61, 62, 69, 70, 71, 78, 79, 80],
]
def __draw(self):
"""キャンバス内の描画を行う
"""
for i in range(9):
for j in range(9):
box_color = (128, 128, 128) if self.box[i+j*9] else (255, 255, 255)
pygame.draw.rect(self.SURFACE, box_color, self.buttons[i+j*9])
for i in range(9):
for j in range(9):
if self.box[i+j*9]:
self.SURFACE.blit(self.font.render(str(self.box[i+j*9]), True, (0, 0, 0)), (15+i*50, 15+j*50))
pygame.draw.rect(self.SURFACE, (128, 128, 128), pygame.Rect(0, 450, 450, 100))
self.SURFACE.blit(self.font.render(self.button_text, True, (255, 255, 255)), (180, 500))
pygame.display.update()
def __get_input(self, event):
"""キーボード入力値を取得し、対象座標の値を更新する
0-9 -> 入力値に更新
それ以外 -> 0に更新(0になっている座標がソルバーの対象となる)
"""
if pygame.key.name(event.key).isdigit():
self.box[self.pos] = int(pygame.key.name(event.key))
else:
self.box[self.pos] = 0
def __solver(self):
"""ソルバー本体
"""
while True:
self.__get_event()
# 入力不可なら終了
if self.can_input:
return False
# 終了フラグが立っていたら終了
elif self.end_flag:
if self.clear_flag:
return True
else:
return False
else:
self.tmp_box = []
for i in self.box:
if i:
self.tmp_box.append(i)
else:
self.tmp_box.append(0)
dfs_box = copy.deepcopy(self.tmp_box)
self.__dfs(dfs_box, 0)
def __display(self, box):
for i in range(9):
for j in range(9):
box_color = (128, 128, 128) if self.box[i+j*9] else (255, 255, 255)
pygame.draw.rect(self.SURFACE, box_color, self.buttons[i+j*9])
for i in range(9):
for j in range(9):
if box[i+j*9]:
self.SURFACE.blit(self.font.render(str(box[i+j*9]), True, (0, 0, 0)), (15+i*50, 15+j*50))
pygame.display.update()
def __dfs(self, box, pos):
for i in range(len(self.tmp_box)):
if i > pos:
box[i] = self.tmp_box[i]
if box.count(0) == 0:
self.end_flag = True
self.box = copy.deepcopy(box)
return
if box[pos] != 0:
self.__dfs(box, pos+1)
else:
checker = list(range(1,10))
for i in range(9):
# 縦軸チェック
if box[pos%9 + i*9] in checker:
checker.remove(box[pos%9 + i*9])
# 横軸チェック
if box[pos//9 * 9 + i] in checker:
checker.remove(box[pos//9 * 9 + i])
# 箱の中チェック
for i in self.box_checker:
if pos in i:
for j in i:
if box[j] in checker:
checker.remove(box[j])
if len(checker) != 0:
for i in checker:
box[pos] = i
print(box)
self.__display(box)
self.__dfs(box, pos+1)
if box.count(0) != 0:
box[pos] = 0
else:
return
else:
box[pos] = 0
def __get_event(self):
"""イベント処理
"""
for event in pygame.event.get():
if event.type == QUIT: # 閉じるボタンが押されたら終了
# Pygameの終了(画面を閉じる)
pygame.quit()
# プログラムの終了
sys.exit()
if self.can_input:
# 入力可かつ枠内がクリックされた場合
if event.type == pygame.MOUSEBUTTONDOWN:
# 数字入力領域がクリックされた場合、入力待ちとなる
if event.pos[0] <= 450 and event.pos[1] <= 450:
self.pos = event.pos[0]//50 + event.pos[1]//50 * 9
self.wait_input = True
# スタートボタンがクリックされた
else:
self.can_input = False
self.button_text = "STOP"
self.__draw()
# 入力待ち状態の場合、キーボードからの入力を取得
if event.type == KEYDOWN and self.wait_input:
self.__get_input(event)
self.pos = -1
self.wait_input = False
else:
if event.type == pygame.MOUSEBUTTONDOWN:
if event.pos[1] > 450:
self.can_input = True
self.button_text = "START"
self.__draw()
# メイン関数
def main(self):
self.__draw()
pygame.display.update() # 画面更新
# 表示更新ループ
while True:
self.__get_event()
if not self.can_input:
self.__solver()
self.__draw()
pygame.display.update() # 画面更新
if self.end_flag:
continue
if __name__ == '__main__':
Sudoku().main()