from PIL import Image from PIL import ImageDraw from PIL import ImageFont import copy def generate_sudoku(): base = 3 side = base*base # pattern for a baseline valid solution def pattern(r,c): return (base*(r%base)+r//base+c)%side # randomize rows, columns and numbers (of valid base pattern) from random import sample def shuffle(s): return sample(s,len(s)) rBase = range(base) rows = [ g*base + r for g in shuffle(rBase) for r in shuffle(rBase) ] cols = [ g*base + c for g in shuffle(rBase) for c in shuffle(rBase) ] nums = shuffle(range(1,base*base+1)) # produce board using randomized baseline pattern board = [ [nums[pattern(r,c)] for c in cols] for r in rows ] # for line in board: print(line) # solution = board[:] solution = copy.deepcopy(board) # print(solution) squares = side*side # empties = squares * 3//5 # empties = squares * 2//10 empties = squares * 11//20 # empties = squares * diff # print(squares) # print(empties) # print(squares * 13//20) for p in sample(range(squares),empties): board[p//side][p%side] = 0 # numSize = len(str(side)) # for line in board: # print(*(f"{n or '.':{numSize}} " for n in line)) def expandLine(line): return line[0]+line[5:9].join([line[1:5]*(base-1)]*base)+line[9:13] # return line[0]+line[3:7].join([line[1:3]*(base-1)]*base)+line[3:5] # return line[0]+line[3:5].join([line[1:3]*(base-1)]*base)+line[5:7] # return line[0]+line[4:7].join([line[1:4]*(base-1)]*base)+line[7:10] line0 = expandLine("╔═══╤═══╦═══╗") line1 = expandLine("║ . │ . ║ . ║") line2 = expandLine("╟───┼───╫───╢") line3 = expandLine("╠═══╪═══╬═══╣") line4 = expandLine("╚═══╧═══╩═══╝") # line0 = expandLine("╔═╤═╦═╗") # line1 = expandLine("║.│.║.║") # line2 = expandLine("╟─┼─╫─╢") # line3 = expandLine("╠═╪═╬═╣") # line4 = expandLine("╚═╧═╩═╝") # line0 = expandLine("╔═╤═╦═╗") # line1 = expandLine("║.│.║.║") # line2 = expandLine("╟─┼─╫─╢") # line3 = expandLine("╠═╪═╬═╣") # line4 = expandLine("╚═╧═╩═╝") # line0 = expandLine("╔══╤══╦══╗") # line1 = expandLine("║. │. ║. ║") # line2 = expandLine("╟──┼──╫──╢") # line3 = expandLine("╠══╪══╬══╣") # line4 = expandLine("╚══╧══╩══╝") symbol = " 1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ" nums = [ [""]+[symbol[n] for n in row] for row in board ] nums_sol = [ [""]+[symbol[n] for n in row] for row in solution ] output = [] output_sol = [] # print(line0) output.append(line0) output_sol.append(line0) for r in range(1,side+1): output.append("".join(n+s for n,s in zip(nums[r-1],line1.split(".")))) output.append([line2,line3,line4][(r%side==0)+(r%base==0)]) # print( "".join(n+s for n,s in zip(nums[r-1],line1.split("."))) ) # print([line2,line3,line4][(r%side==0)+(r%base==0)]) for r in range(1,side+1): output_sol.append("".join(n+s for n,s in zip(nums_sol[r-1],line1.split(".")))) output_sol.append([line2,line3,line4][(r%side==0)+(r%base==0)]) # print('=') # print(output) # for x in output: # print(x) # print('-') return [output, output_sol] def convert_to_image(sudoku, size=16, flipped=False): # sample text and font # unicode_text = u"Unicode Characters: \u00C6 \u00E6 \u00B2 \u00C4 \u00D1 \u220F" unicode_text = sudoku[0] # print(sudoku) # print(len(sudoku)) verdana_font = ImageFont.truetype("application/IBMPlexMono-Medium.ttf", size, encoding="unic") # get the line size bx, by, text_width, text_height = verdana_font.getbbox(unicode_text) # print(verdana_font.getsize(unicode_text)) # print(verdana_font.getbbox(unicode_text)) # print(verdana_font.getlength(unicode_text)) # print(text_height) # create a blank canvas with extra space between lines canvas = Image.new('RGB', (text_width + 10, ((text_height-2)*(len(sudoku)))), (255, 255, 255)) # canvas.convert('L') # draw the text onto the text canvas, and use black as the text color draw = ImageDraw.Draw(canvas) # for x in sudoku: pos = 0 for x in sudoku: unicode_text = x draw.text((5,pos), unicode_text, font = verdana_font, fill = "#000000") pos += (text_height-2) # save the blank canvas to a file # fn = lambda x : 255 if x > 200 else 0 # canvas.convert('L').point(fn, mode='1') if flipped: canvas = canvas.transpose(Image.ROTATE_180) canvas.save("sudoku_" + str(size) +".png", "PNG") # img = Image.new('RGB', (200, 100)) # d = ImageDraw.Draw(img) # d.text((30, 20), sudoku[0], fill=(255, 0, 0)) # text_width, text_height = d.textsize(sudoku[0]) # print(text_width, text_height) if __name__ == '__main__': out = generate_sudoku() su = out[0] su_sol = out[1] # print(out) for x in su: print(x) for y in su_sol: print(y) convert_to_image(su) convert_to_image(su_sol, size=8, flipped=True) # print(su) # for x in generate_sudoku(): # print(x) # print(board) # import random # from itertools import islice # print([*islice(shortSudokuSolve(board),2)][0]) # print([*islice(shortSudokuSolve(board),2)][1]) # if [*islice(shortSudokuSolve(board),2)][0] == [*islice(shortSudokuSolve(board),2)][1]: # print('ay') # else: # print('er') # while True: # solved = [*islice(shortSudokuSolve(board),2)] # # print(len(solved)) # # print(solved) # if len(solved)==1: # # print('yay!') # break # diffPos = [(r,c) for r in range(9) for c in range(9) # if solved[0][r][c] != solved[1][r][c] ] # r,c = random.choice(diffPos) # board[r][c] = solution[r][c] # # print(board) # print(r,c) # # print(board) # print(board) # print(solution) # print('ysy') # def expandLine(line): # return line[0]+line[5:9].join([line[1:5]*(base-1)]*base)+line[9:13] # line0 = expandLine("╔═══╤═══╦═══╗") # line1 = expandLine("║ . │ . ║ . ║") # line2 = expandLine("╟───┼───╫───╢") # line3 = expandLine("╠═══╪═══╬═══╣") # line4 = expandLine("╚═══╧═══╩═══╝") # symbol = " 1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ" # nums = [ [""]+[symbol[n] for n in row] for row in board ] # output = [] # print(line0) # output.append(line0) # for r in range(1,side+1): # output.append("".join(n+s for n,s in zip(nums[r-1],line1.split(".")))) # output.append([line2,line3,line4][(r%side==0)+(r%base==0)]) # print( "".join(n+s for n,s in zip(nums[r-1],line1.split("."))) ) # print([line2,line3,line4][(r%side==0)+(r%base==0)]) # print('==') # print(output) # for x in output: # print(x) # print('--') # return output