marklonek

Mownit sudoku

Nov 23rd, 2017
77
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 4.88 KB | None | 0 0
  1. import random
  2.  
  3. import math
  4.  
  5.  
  6. class SudokuPlot:
  7.     def __init__(self):
  8.         self.x1 = None
  9.         self.y1 = None
  10.         self.v1 = None
  11.         self.x2 = None
  12.         self.y2 = None
  13.         self.v2 = None
  14.         self.plot = [[-1 for _ in range(9)] for _ in range(9)]
  15.  
  16.     def read_from_file(self, file_path):
  17.         all_in_sudoku = {1: 9, 2: 9, 3: 9, 4: 9, 5: 9, 6: 9, 7: 9, 8: 9, 9: 9}
  18.         with open(file_path, "r") as fd:
  19.             for i, line in enumerate(fd):
  20.                 for j, elem in enumerate(line.replace('\n', '').split(' ')):
  21.                     if elem == 'x':
  22.                         self.plot[i][j] = {'value': None, 'certain': False}
  23.                     else:
  24.                         self.plot[i][j] = {'value': int(elem), 'certain': True}
  25.                         all_in_sudoku[int(elem)] -= 1
  26.         self.add_left_numbers(all_in_sudoku)
  27.  
  28.     def add_left_numbers(self, all_in_sudoku):
  29.         index = 0
  30.         left_numbers = []
  31.         for x in all_in_sudoku:
  32.             left_numbers += [x] * all_in_sudoku[x]
  33.         for i in range(9):
  34.             for j in range(9):
  35.                 if not self.plot[i][j]['certain']:
  36.                     self.plot[i][j]['value'] = left_numbers[index]
  37.                     index += 1
  38.  
  39.     def calculate_energy(self):
  40.         energy_sum = 0
  41.         for x in range(9):
  42.             for y in range(9):
  43.                 energy_sum += self.get_row_energy(x, y) + self.get_column_energy(x, y) + self.get_box_energy(x, y)
  44.         return energy_sum
  45.  
  46.     def get_row_energy(self, a, b):
  47.         row = [x['value'] for x in self.plot[a]]
  48.         return self.count_list_duplicates(row)
  49.  
  50.     def get_column_energy(self, a, b):
  51.         column = [row[b]['value'] for row in self.plot]
  52.         return self.count_list_duplicates(column)
  53.  
  54.     def get_box_energy(self, a, b):
  55.         x = int(a / 3)
  56.         y = int(b / 3)
  57.         values = [self.plot[x + i][y + j]['value'] for i in range(3) for j in range(3)]
  58.         return self.count_list_duplicates(values)
  59.  
  60.     def count_list_duplicates(self, l):
  61.         d = {x: l.count(x) for x in l}
  62.         return sum([x - 1 for x in d.values() if x > 1])
  63.  
  64.     def exchange(self):
  65.         x1 = random.randint(0, 8)
  66.         y1 = random.randint(0, 8)
  67.         while self.plot[x1][y1]['certain']:
  68.             x1 = random.randint(0, 8)
  69.             y1 = random.randint(0, 8)
  70.  
  71.         x2 = random.randint(0, 8)
  72.         y2 = random.randint(0, 8)
  73.         while self.plot[x2][y2]['certain']:
  74.             x2 = random.randint(0, 8)
  75.             y2 = random.randint(0, 8)
  76.  
  77.         self.x1 = x1
  78.         self.y1 = y1
  79.         self.v1 = self.plot[x1][y1]['value']
  80.  
  81.         self.x2 = x2
  82.         self.y2 = y2
  83.         self.v2 = self.plot[x2][y2]['value']
  84.  
  85.         self.plot[x1][y1]['value'] = self.v2
  86.         self.plot[x2][y2]['value'] = self.v1
  87.  
  88.     def revert_last_modification(self):
  89.         self.plot[self.x1][self.y1]['value'] = self.v1
  90.         self.plot[self.x2][self.y2]['value'] = self.v2
  91.  
  92.  
  93. class SudokuSolver:
  94.     def simulate_annealing(self, sudoku_plot, temperature, min_temperature, cooling_function):
  95.         energy = sudoku_plot.calculate_energy()
  96.         best_configuration = {'energy': energy, 'plot': sudoku_plot}
  97.         print('Begin energy {}'.format(energy))
  98.         i = 0
  99.         while min_temperature < temperature and best_configuration['energy'] > 0:
  100.             i += 1
  101.             if i % 1000 == 0:
  102.                 print("Iteration {}, temperature {}, energy {}".format(i, temperature, best_configuration['energy']))
  103.  
  104.             sudoku_plot.exchange()
  105.             new_energy = sudoku_plot.calculate_energy()
  106.  
  107.             if new_energy < best_configuration['energy']:
  108.                 best_configuration = {'energy': new_energy, 'plot': sudoku_plot}
  109.                 energy = new_energy
  110.             elif math.exp((energy - new_energy) / temperature) > random.random():
  111.                 energy = new_energy
  112.             else:
  113.                 sudoku_plot.revert_last_modification()
  114.  
  115.             temperature = cooling_function(temperature)
  116.         print('End energy {}'.format(best_configuration['energy']))
  117.         return best_configuration
  118.  
  119.  
  120. class CoolingFunctions:
  121.     def fun1(self, rate):
  122.         def f(temperature):
  123.             new_temperature = temperature * rate
  124.             return new_temperature
  125.  
  126.         return f
  127.  
  128.  
  129. if __name__ == "__main__":
  130.     file = 'data2.txt'
  131.     sp = SudokuPlot()
  132.     sp.read_from_file(file)
  133.     cooling = CoolingFunctions().fun1(0.99999)
  134.     result = SudokuSolver().simulate_annealing(sp, 1, 0.1, cooling)
  135.  
  136.     print(sp.calculate_energy())
  137.  
  138.     for line in result['plot'].plot:
  139.         for e in line:
  140.             print('{} '.format(e['value']), end="")
  141.         print()
  142.         # print()
  143.         # sp.get_box_energy(3, 3)
  144.         # print()
  145.         # sp.get_box_energy(8, 3)
  146.         # print()
  147.         # sp.get_box_energy(3, 8)
Advertisement
Add Comment
Please, Sign In to add comment