Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import random
- import math
- class SudokuPlot:
- def __init__(self):
- self.x1 = None
- self.y1 = None
- self.v1 = None
- self.x2 = None
- self.y2 = None
- self.v2 = None
- self.plot = [[-1 for _ in range(9)] for _ in range(9)]
- def read_from_file(self, file_path):
- all_in_sudoku = {1: 9, 2: 9, 3: 9, 4: 9, 5: 9, 6: 9, 7: 9, 8: 9, 9: 9}
- with open(file_path, "r") as fd:
- for i, line in enumerate(fd):
- for j, elem in enumerate(line.replace('\n', '').split(' ')):
- if elem == 'x':
- self.plot[i][j] = {'value': None, 'certain': False}
- else:
- self.plot[i][j] = {'value': int(elem), 'certain': True}
- all_in_sudoku[int(elem)] -= 1
- self.add_left_numbers(all_in_sudoku)
- def add_left_numbers(self, all_in_sudoku):
- index = 0
- left_numbers = []
- for x in all_in_sudoku:
- left_numbers += [x] * all_in_sudoku[x]
- for i in range(9):
- for j in range(9):
- if not self.plot[i][j]['certain']:
- self.plot[i][j]['value'] = left_numbers[index]
- index += 1
- def calculate_energy(self):
- energy_sum = 0
- for x in range(9):
- for y in range(9):
- energy_sum += self.get_row_energy(x, y) + self.get_column_energy(x, y) + self.get_box_energy(x, y)
- return energy_sum
- def get_row_energy(self, a, b):
- row = [x['value'] for x in self.plot[a]]
- return self.count_list_duplicates(row)
- def get_column_energy(self, a, b):
- column = [row[b]['value'] for row in self.plot]
- return self.count_list_duplicates(column)
- def get_box_energy(self, a, b):
- x = int(a / 3)
- y = int(b / 3)
- values = [self.plot[x + i][y + j]['value'] for i in range(3) for j in range(3)]
- return self.count_list_duplicates(values)
- def count_list_duplicates(self, l):
- d = {x: l.count(x) for x in l}
- return sum([x - 1 for x in d.values() if x > 1])
- def exchange(self):
- x1 = random.randint(0, 8)
- y1 = random.randint(0, 8)
- while self.plot[x1][y1]['certain']:
- x1 = random.randint(0, 8)
- y1 = random.randint(0, 8)
- x2 = random.randint(0, 8)
- y2 = random.randint(0, 8)
- while self.plot[x2][y2]['certain']:
- x2 = random.randint(0, 8)
- y2 = random.randint(0, 8)
- self.x1 = x1
- self.y1 = y1
- self.v1 = self.plot[x1][y1]['value']
- self.x2 = x2
- self.y2 = y2
- self.v2 = self.plot[x2][y2]['value']
- self.plot[x1][y1]['value'] = self.v2
- self.plot[x2][y2]['value'] = self.v1
- def revert_last_modification(self):
- self.plot[self.x1][self.y1]['value'] = self.v1
- self.plot[self.x2][self.y2]['value'] = self.v2
- class SudokuSolver:
- def simulate_annealing(self, sudoku_plot, temperature, min_temperature, cooling_function):
- energy = sudoku_plot.calculate_energy()
- best_configuration = {'energy': energy, 'plot': sudoku_plot}
- print('Begin energy {}'.format(energy))
- i = 0
- while min_temperature < temperature and best_configuration['energy'] > 0:
- i += 1
- if i % 1000 == 0:
- print("Iteration {}, temperature {}, energy {}".format(i, temperature, best_configuration['energy']))
- sudoku_plot.exchange()
- new_energy = sudoku_plot.calculate_energy()
- if new_energy < best_configuration['energy']:
- best_configuration = {'energy': new_energy, 'plot': sudoku_plot}
- energy = new_energy
- elif math.exp((energy - new_energy) / temperature) > random.random():
- energy = new_energy
- else:
- sudoku_plot.revert_last_modification()
- temperature = cooling_function(temperature)
- print('End energy {}'.format(best_configuration['energy']))
- return best_configuration
- class CoolingFunctions:
- def fun1(self, rate):
- def f(temperature):
- new_temperature = temperature * rate
- return new_temperature
- return f
- if __name__ == "__main__":
- file = 'data2.txt'
- sp = SudokuPlot()
- sp.read_from_file(file)
- cooling = CoolingFunctions().fun1(0.99999)
- result = SudokuSolver().simulate_annealing(sp, 1, 0.1, cooling)
- print(sp.calculate_energy())
- for line in result['plot'].plot:
- for e in line:
- print('{} '.format(e['value']), end="")
- print()
- # print()
- # sp.get_box_energy(3, 3)
- # print()
- # sp.get_box_energy(8, 3)
- # print()
- # sp.get_box_energy(3, 8)
Advertisement
Add Comment
Please, Sign In to add comment