diff --git a/.gitignore b/.gitignore index 054022e..1f95eb2 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,7 @@ #################### Python.gitignore #################### # App Specific -sudoku* +sudoku*.png data.json # Byte-compiled / optimized / DLL files diff --git a/application/sudoku_generator.py b/application/sudoku_generator.py new file mode 100644 index 0000000..b455f98 --- /dev/null +++ b/application/sudoku_generator.py @@ -0,0 +1,216 @@ +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 +