def save_nonogram_from_url(url): try: nono_id, nono_name, d = parse_nonogram(url) except Exception as e: # print('Ссылка не туда') print(e) else: columns_number = d[1][0] % d[1][3] + d[1][1] % d[1][3] - d[1][2] % d[ 1][3] # ширина rows_number = d[2][0] % d[2][3] + d[2][1] % d[2][3] - d[2][2] % d[2][ 3] # высота colors_number = d[3][0] % d[3][3] + d[3][1] % d[3][3] - d[3][2] % d[3][ 3] nono_answer = np.full((rows_number, columns_number), 0) # print('Columns number =', columns_number) # print('Rows number', rows_number) v = colors_number + 5 black_rows_number = d[v][0] % d[v][3] * ( d[v][0] % d[v][3]) + d[v][1] % d[v][3] * 2 + d[v][2] % d[v][3] decoder = d[v + 1] for x in range(v + 2, v + 1 + black_rows_number + 1): for v in range(d[x][0] - decoder[0] - 1, d[x][0] - decoder[0] + d[x][1] - decoder[1] - 1): nono_answer[d[x][3] - decoder[3] - 1][v] = d[x][2] - decoder[2] header_rows = get_header_from_array(nono_answer) header_columns = get_header_from_array(nono_answer.T) header = Header(header_rows, header_columns) nonogram = Nonogram(nono_id, nono_name, header, nono_answer) nono_db.write_nonogram_to_db(nonogram)
def __init__(self): self.nonogram = Nonogram() self.rows = self.nonogram.get_row_constraints() self.col = self.nonogram.get_column_constraints() self.row_length = len(self.rows) self.col_length = len(self.col) # define a state self.state = State(self.rows, self.col) # get permutations from nonogram.py (attempt 1) self.col_permutations = self.hash_col_permutations() self.row_permutations = self.hash_row_permutations() self.traversed = 0 self.all_created_nodes = 0
def test_init_overlap(): rows = [[1, 1], [5], [5], [3], [1]] cols = [[2], [4], [4], [4], [2]] nono = Nonogram(rows, cols) e = nono.EMPTY u = nono.UNKNOWN f = nono.FILLED answer = [[u, u, u, u, u], [f, f, f, f, f], [f, f, f, f, f], [u, f, f, f, u], [u, u, u, u, u]] s = Solver(nono) s.initial_overlaps() assert nono.board == answer
def init_games(self): try: loaded_data = ast.literal_eval(self.window['-LOADED_DATA-'].get()) if not isinstance(loaded_data, list): raise ValueError() self.games = [] for id in loaded_data: if not isinstance(id, int): raise ValueError() nonogram = Nonogram(self.games_queue) nonogram.load_from_db(id) self.games.append(nonogram) except (ValueError, SyntaxError): sg.popup_error('Entered data incorrect') self.window['-NO_OF_GAMES-'].update(str(len(self.games)))
def initialize_cells(my_image): width = my_image.shape[1] * cell_width height = my_image.shape[0] * cell_width nonogram = Nonogram(width, height, cell_width) for i in range(cell_width, height + cell_width, cell_width): for j in range(cell_width, width + cell_width, cell_width): if my_image[(i - cell_width) // cell_width, (j - cell_width) // cell_width] == 0: color = BLACK else: color = WHITE cell = Cell(((j - cell_width) // cell_width, (i - cell_width) // cell_width), j, i, color, cell_width) nonogram.add_cell(cell) return nonogram, width, height
def random_nonogram(row_count, col_count): cell_count = row_count * col_count # nonograms with half of the cells colored are the hardest colored_cell_count = np.random.binomial(cell_count, 0.5) fields = list(itertools.product(range(row_count), range(col_count))) colored_fields = random.sample(fields, k=colored_cell_count) nonogram = Nonogram(row_count, col_count, colored_cells=colored_fields) nonogram.calculate_descriptors() nonogram.reset_cells() if nonogram.solve(): return nonogram else: return random_nonogram(row_count, col_count)
def __init__(self, gui_queue, filename=None, db_id=None): self.main_gui_queue = gui_queue if filename is not None or db_id is not None: self.game = Nonogram() if filename is not None: self.game.load_from_file(filename) else: self.game.load_from_db(db_id) else: raise ValueError("GUIGame object wasn't initialized!") self.game_width, self.game_height = 0, 0 self.BOX_WIDTH, self.BOX_HEIGHT = 0, 0 # window sizes related variables self.WINDOW_SIZE_X = 500 # initial width of the window self.WINDOW_SIZE_Y = 500 # initial height of the window self.stored_size = (0, 0) # width and height of the last drawn window self.reload_size = True # boolean for checking if the window needs to be redrawn due to window resizing self.TIP_SIZE = 150 # widht (for rows) or height (for columns) of box containing hints # variables storing object ids of hints/board self.row_hint_ids = [ ] # array storing IDs of drawn objects of hints for rows self.col_hint_ids = [ ] # array storing IDs of drawn objects of hints for columns # init display variables self.layout = None # layout of current window self.window = None # pointer to window object self.puzzle = None # pointer to window fragment containing puzzle tiles self.row_hints = None # pointer to window fragment containing hints for rows self.col_hints = None # pointer to window fragment containing hints for columns self.queue = queue.Queue() self.threads_id = []
from nonogram import Nonogram from solver import Solver rows = [[1, 1], [5], [5], [3], [1]] cols = [[2], [4], [4], [4], [2]] nono = Nonogram(rows, cols) s = Solver(nono, False) s.solve() print(nono.verify()) print(nono) rows = [[1, 2, 3], [3, 1], [4, 2], [1, 3], [1, 2, 3]] cols = [[1, 3], [2], [3], [3, 1], [1], [1], [1, 2], [2, 2], [1, 2], [1]] nono = Nonogram(rows, cols) s = Solver(nono, False) s.solve() print(nono.verify()) print(nono) rows = [[2, 4, 1, 1], [1, 2, 1], [2, 1, 1, 2, 1], [3, 5, 1], [1, 1, 2, 1, 1], [1, 2, 1, 1, 3], [1, 1, 1, 2, 3], [1, 1, 1, 1, 1, 1, 1], [2, 3, 2, 1, 1], [1, 2, 6], [2, 1, 1, 1, 2, 2], [2, 1, 1, 1, 1, 1], [1, 1, 3, 1, 1, 1], [1, 1, 1, 1, 2, 1], [1, 1, 7, 1]] cols = [[1, 3, 7], [1, 2, 3, 2], [4, 1, 1, 1], [1, 1, 3, 1], [4, 1, 1, 1, 1], [1, 1, 2, 1, 3], [1, 3, 1, 2, 1], [1, 3, 2, 1, 1], [1, 4], [5, 1], [3, 2, 3, 2], [4, 1, 2], [5, 1], [2, 2, 2], [1, 11]]
from nonogram import Square, Nonogram col_num = [[2], [1, 1], [1, 2], [1, 1], [2]] row_num = [[1], [1, 1], [1, 1], [1, 1, 1], [1]] n = Nonogram(row_num, col_num) n.print_nonogram()
class GeneticAlgorithm(object): global file file = open('output.txt', 'w') # instance of nonogram board global nonogram, population, fitness, ROWS, COLUMNS, ROW_COUNT, COLUMN_COUNT, POPSIZE, MUTATIONPROB, CROSSOVERPROB nonogram = Nonogram() population = [] fitness = [] ROWS = nonogram.get_row_constraints() COLUMNS = nonogram.get_column_constraints() ROW_COUNT = len(ROWS) COLUMN_COUNT = len(COLUMNS) POPSIZE = 300 MUTATIONPROB = None CROSSOVERPROB = 75 # generate random population of suitable solutions for nonogram def generate_population(self): pop = [] for i in range(0, POPSIZE): state = nonogram.get_random_state(ROWS, COLUMNS) # get solution generated based on row constraints pop.append(state[0]) return pop # evaluate the fintness of each solution in the population def evaluate_fitness(self, pop): fit = [] # print pop for sol in pop: fit.append(nonogram.check_all_col(sol)) return fit '''1ST APPROACH''' # create a new population by repeating # selection, crossover, mutation, accepting def create_new_population_1(self, pairs): pop = [] # create a new population by repeating # selection, crossover, mutation, accepting (placing new offspring in new pop) parents = self.selection(pairs) while len(pop) <= POPSIZE: cross = self.crossover(parents) offspring = self.mutation(cross) # place new offspring in a new population pop.append(offspring) print("PARENTS ARE\n") print nonogram.print_state(parents[0]) print("\n\n") print nonogram.print_state(parents[1]) print("\n\n") # return new generated population return pop '''2ND APPROACH''' # create a new population by repeating # selection, crossover, mutation, accepting def create_new_population_2(self, pairs): pre_pop = [] # create a new population by repeating # selection, crossover, mutation, accepting (placing new offspring in new pop) # select best individuals based on their fitness chosen = self.selection_2(pairs) chosen = sorted(chosen, key=operator.attrgetter('fitness')) pre_pop.append(chosen[0].get_state()) pre_pop.append(chosen[1].get_state()) # the rest crossover cross = self.crossover_2(chosen[2:]) pre_pop.extend(cross) # print pre_pop # mutate the whole pre_pop post_pop = [] for i in range(0, len(pre_pop)): offspring = self.mutation(pre_pop[i]) # place new offspring in a new population post_pop.append(offspring) # '''WRITING TO FILE''' # file.write("BEST 2 ARE\n") # file.write(nonogram.print_state(chosen[0].get_state())) # file.write(str(chosen[0].get_fit())) # file.write("\n\n") # file.write(nonogram.print_state(chosen[1].get_state())) # file.write(str(chosen[1].get_fit())) # file.write("\n\n") print("BEST 2 ARE\n") print nonogram.print_state(chosen[0].get_state()) print str(chosen[0].get_fit()) print("\n\n") print nonogram.print_state(chosen[1].get_state()) print(str(chosen[1].get_fit())) print("\n\n") # return new generated population return post_pop # use roulette wheel to select best solutions from a population according to their fitness # the better fitness, the bigger chance to be selected def selection_2(self, pairs): sum_fit = 0 # store fitness in an array fit_array = [] for i in pairs: sum_fit += i.get_fit() fit_array.append(i.get_fit()) # print "sum fit is", sum_fit fit_array.reverse() chosen = [] fitness_function = [] index = 0 for j in fit_array: fit_val = j # print "fit val is", fit_val fitness_function.append(range(index, index + fit_val)) index += fit_val # print fitness_function for k in range(0, POPSIZE): probability = random.randint(0, sum_fit) for a in range(0, len(fitness_function)): if probability in fitness_function[a]: chosen.append(pairs[a]) # print len(chosen) # print chosen return chosen # with a crossover probability cross over the parents to form 2 new offsprings # return a list of new offsprings def crossover_2(self, parents): index_i = 0 index_j = 1 # list of offsprings to return list = [] while index_i < len(parents) and index_j < len(parents): # generate a random probability probability = random.randint(0, 100) if probability < CROSSOVERPROB: # generate a random crossover point crossover_point = random.randint(0, ROW_COUNT) # copy everything before this point from parent 1 and after this point from parent 2 offspring1 = [] offspring2 = [] # get states of parents state1 = parents[index_i].get_state() state2 = parents[index_j].get_state() for i in range(0, crossover_point): offspring1.append(state1[i]) offspring2.append(state2[i]) for j in range(crossover_point, ROW_COUNT): offspring1.append(state2[j]) offspring2.append(state1[j]) list.append(offspring1) list.append(offspring2) else: list.append(parents[index_i].get_state()) list.append(parents[index_j].get_state()) index_i += 2 index_j += 2 return list '''1ST APPROACH''' # select 2 solutions from a population according to their fitness # the better fitness, the bigger chance to be selected def selection(self, pairs): sorted_pairs = sorted(pairs, key=operator.attrgetter('fitness')) sol1 = sorted_pairs[0] sol2 = sorted_pairs[1] # '''WRITING TO FILE''' # file.write("PARENTS ARE\n") # file.write(nonogram.print_state(sol1.get_state())) # file.write(str(sol1.get_fit())) # file.write("\n") # file.write(nonogram.print_state(sol2.get_state())) # file.write(str(sol2.get_fit())) # file.write("\n") # list of 2 chosen solutions chosen = [sol1.get_state(), sol2.get_state()] return chosen # with a crossover probability cross over the parents to form a new offspring def crossover(self, parents): # generate a random probability probability = random.randint(0, 100) if probability < CROSSOVERPROB: # generate a random crossover point crossover_point = random.randint(0, ROW_COUNT) # copy everything before this point from parent 1 and after this point from parent 2 offspring = [] for i in range(0, crossover_point): offspring.append(parents[0][i]) for j in range(crossover_point, ROW_COUNT): offspring.append(parents[1][j]) else: offspring = parents[0] return offspring # with a mutation probability mutate new offspring at each locus (position in chromosome) def mutation(self, offspring): # new mutated offspring new = [] for i in range(0, ROW_COUNT): # 20% chance a row get mutated probability = random.randint(0, 100) if probability <= MUTATIONPROB: # print "row" + str(i) + " get mutated" # print offspring[i] rand = nonogram.get_random_row(i) # print "became" # print rand new.append(rand) else: new.append(offspring[i]) return new # return solution if all constraints are met def check_goal(self, pop): for sol in pop: if nonogram.check_all_col(sol) is 0: return sol return None # method to pair each solution with its fitness def pair_up(self, pop, fitness): pairs = [] for i in range(0, len(pop)): solution = Solution(pop[i], fitness[i]) pairs.append(solution) return pairs # main method def __init__(self): if len(sys.argv) == 1: print "Choose an approach: greedy or proper" print "'python genetic.py greedy' or 'python genetic.py proper'" return if str(sys.argv[1]) == "greedy": global MUTATIONPROB MUTATIONPROB = 30 elif str(sys.argv[1]) == "proper": global MUTATIONPROB MUTATIONPROB = 5 start = time.time() global population, fitness # STEP 1: generate random population population = self.generate_population() # loop to return the best solution in current population flag = None counter = 0 while flag is None: counter += 1 string = "Generation " + str(counter) + "\n" # file.write(string) # STEP 2: evaluate fitness of each sol in population fitness = self.evaluate_fitness(population) # pair each solution with its fitness pairs = self.pair_up(population, fitness) # STEP 3: create a new population if str(sys.argv[1]) == "greedy": population = self.create_new_population_1(pairs) elif str(sys.argv[1]) == "proper": population = self.create_new_population_2(pairs) # STEP 4: check if the end condition is satisfied flag = self.check_goal(population) end = time.time() runtime = end - start '''WRITING TO FILE''' # file.write("SOLUTION IS \n") # file.write(nonogram.print_state(flag)) # file.write("\n") # file.write("\nRUNTIME IS") # file.write(str(runtime)) print "RUNTIME IS %s" % runtime print "Number of generations: %s" % counter print(nonogram.print_state(flag))
if __name__ == '__main__': #file_name = "lost.txt" file_name = "beach.txt" #file_name = "artist.txt" # faster with match_forwards than match backwards. NFA is of course the fastest #file_name = "balance.txt" #file_name = "warship.txt" #file_name = "bear.txt" # the webpbn puzzles are super hard #file_name = "webpbn-01611-For merilinnuke" +'.txt' file_name = 'puzzles/' + file_name runs_row, runs_col, solution = decode(file_name) puzzle = Nonogram(runs_row, runs_col) find_solution = True make_guess = True # set solution if solution and not find_solution: # the webpbn files have solutions print("setting solution ...") grid_sol = decode_solution(solution, len(runs_row), len(runs_col)) puzzle.set_grid(grid_sol) ##solve game if find_solution: start_time = time.time() grid = solve_fast(puzzle, make_guess=make_guess) #grid = solve(puzzle) end_time = time.time()
five_strip1 = [( 1, 2, ) + 6 * (1, ), (2, ) + 6 * (1, ) + (2, ), (1, ), (2, 1, 1, 2, 1, 2, 1), (1, 1, 1, 2, 1, 1, 1)] three_strip = [(1, ), (18, ), (1, 1)] five_strip2 = [(1, 2, 1, 2, 1, 1, 2), (1, 1, 1, 2, 1, 1, 1), (1, ), (2, 1, 1, 2, 1, 2, 1), (1, 1, 1, 2, 1, 1, 1)] two_strip = [(1, 2, 1, 2, 1, 1, 2), (1, 1, 1, 2, 1, 1, 1)] #r_row = five_strip1 + three_strip + five_strip2 + three_strip + two_strip #r_col = [(3,2,3,2,1),(1,1,2,1,1,2,1)] + [(1,)*7 for _ in range(15)] + [(2,1,3,1,3)] ## small but constraint propagation alone won't solve #r_row = [(4,),(4,),(1,),(1,1),(1,)] # not possible to solve with this solver #r_col = [(1,),(2,1),(2,1),(2,1),(1,1)] # not possible to solve with this solver puzzle = Nonogram(r_row, r_col) ## set solution #puzzle.set_grid(solution) ## solve game start_time = time.time() grid = solve(puzzle) puzzle.set_grid(grid) end_time = time.time() puzzle.show_grid(show_instructions=True, to_file=False, symbols="x#.?") print(puzzle.is_complete(), "{:.2f}%%".format(puzzle.progress * 100)) print("time taken: {:.5f}s".format(end_time - start_time)) print("solved with {} guesses".format(puzzle.guesses))
from config import NUM_COLS, NUM_ROWS, pickle_unsolved_file_path from nonogram import Nonogram import pickle csv_path = '../data/hanjie.csv' save = True # True -> save to file, False -> load file # saves the Nonograms in csv_path to a pickled list of unsolved Nonograms with open(csv_path) as csvfile: readCSV = csv.reader(csvfile, delimiter=',') filtered = [ { 'title': row[2], 'number': int(row[3]), 'solution': row[4], 'rows': row[6], 'cols': row[7] } for i, row in enumerate(readCSV) if i > 0 and int(row[0]) == NUM_COLS and int(row[1]) == NUM_ROWS ] nonograms = [ Nonogram(d['rows'], d['cols'], d['title'], d['number'], d['solution']) for d in filtered ] for nono in nonograms: print(nono) with open('../' + pickle_unsolved_file_path, 'wb') as f: pickle.dump(nonograms, f)
import tkinter as tk from tkinter import messagebox, Button from nonogram import Nonogram from image import Img import numpy as np # ##### DEFINE GRID HERE ###### # ROWS = 10 COLS = 10 # Visual size of grid box GRID_SIZE = 40 # Initialize nonogram = Nonogram() img = Img() tiles = [[0 for _ in range(COLS)] for _ in range(ROWS)] def create_grid(event=None): w = grid.winfo_width() # Get current width of canvas h = grid.winfo_height() # Get current height of canvas grid.delete('grid_line') # Will only remove the grid_line # Creates all vertical lines at intevals of 100 for i in range(0, w, GRID_SIZE): grid.create_line([(i, 0), (i, h)], tag='grid_line') # Creates all horizontal lines at intevals of 100 for i in range(0, h, GRID_SIZE): grid.create_line([(0, i), (w, i)], tag='grid_line')
def event_handler(self): event, values = self.window.read(timeout=100) # handle queue from other GUI windows while len(self.queue) > 0: self.read_queue(self.queue[-1]) self.queue.pop(-1) if event in (None, ): return False if event in '-INIT_GAMES-': try: loaded_data = ast.literal_eval( self.window['-LOADED_DATA-'].get()) if not isinstance(loaded_data, list): raise ValueError() self.games = [] for id in loaded_data: if not isinstance(id, int): raise ValueError() nonogram = Nonogram() nonogram.load_from_db(id) self.games.append(nonogram) except (ValueError, SyntaxError): sg.popup_error('Entered data incorrect') if not self.game_gui_opened and event in ('...file', '-FILE_LOAD-'): self.game_gui = GUIGame(self.queue, 'test.txt') self.game_gui.set_layout() self.game_gui_opened = True if not self.game_gui_opened and event in ('...database', '-DB_LOAD-'): popup_text = sg.popup_get_text('Choose puzzle ID (1-9800)', 'Load puzzle from database') if popup_text: puzzle_id = int(popup_text) if 0 < puzzle_id < 9801: self.game_gui = GUIGame(self.queue, db_id=puzzle_id) self.game_gui.set_layout() self.game_gui_opened = True self.game_gui.reload() self.game_gui.redraw_hints(self.game_gui.game.rows, self.game_gui.game.cols) self.game_gui.redraw() if not self.database_gui_opened and event == 'Browse database': self.database_gui = GUIDatabase(self.queue) self.database_gui.set_layout() self.database_gui_opened = True if self.game_gui_opened and not self.game_gui.event_handler(): self.game_gui = None self.game_gui_opened = False if self.database_gui_opened and not self.database_gui.event_handler(): self.database_gui = None self.database_gui_opened = False return True