def correct_solution(self): """Corrects solution.""" for i in range(0, self.size[0]): for j in range(0, self.size[1]): if self.puzzle[i, j] > 0: queue = define_block(i, j) visited = [] while queue: q = queue.pop() visited.append(q) for p in adjacent_squares(*q): p_sym = symmetric_point(i, j, *p) q_sym = symmetric_point(i, j, *q) pos_wall = wall_between(p[0], p[1], q[0], q[1]) sym_wall = wall_between(p_sym[0], p_sym[1], q_sym[0], q_sym[1]) if not self.is_wall( *pos_wall) and not self.is_wall( *sym_wall) and p not in visited: queue.append(p) elif self.is_wall( *pos_wall) and not self.is_wall(*sym_wall): self.solution[sym_wall[0], sym_wall[1]] = 1 elif not self.is_wall(*pos_wall) and self.is_wall( *sym_wall): self.solution[pos_wall[0], pos_wall[1]] = 1 block = get_unique(visited) for b in block: self.solution[b[0], b[1]] = self.puzzle[i, j]
def check_closed(self): """Checks if there are new closed blocks.""" for i, row in enumerate(self.solution): for j, el in enumerate(row): if self.puzzle[i, j] > 0 and not closest_closed( i, j, self.solution): queue = define_block(i, j) visited = [] while queue: p = queue.pop() visited.append(p) next_ones = adjacent_squares(p[0], p[1]) for n in next_ones: if self.is_inside(*n) and not self.puzzle[n[0], n[1]] < 0 \ and not self.is_wall(*wall_between(p[0], p[1], n[0], n[1])) \ and n not in visited: n_sym = symmetric_point(i, j, n[0], n[1]) p_sym = symmetric_point(i, j, p[0], p[1]) if (self.is_inside(*n_sym) and self.is_inside(*p_sym)) and \ not self.puzzle[n_sym[0], n_sym[1]] < 0 or \ not self.is_wall(*wall_between(p_sym[0], p_sym[1], n_sym[0], n_sym[1])): queue.append(n) if self.puzzle[i, j] > 0: block = get_unique(np.array(visited)) if self.block_is_closed(block, self.solution): for b in block: self.solution[b[0], b[1]] = self.puzzle[i, j]
def fill_from_dot(self, i, j, k=0, block=None): """ Fills block from given dot. :param k: describes how far from dot algorithm will attempt to fill puzzle :param i: position :param j: position :param block: if not empty, function can use only points in block :return: how many walls were put in """ filled_count = 0 queue = define_block(i, j) visited = [] no_queue = False while queue: p = queue.pop() visited.append(p) next_ones = [] for n in adjacent_squares(p[0], p[1]): if 0 < k < point_dist(n[0], n[1], i, j): no_queue = True wall = wall_between(n[0], n[1], p[0], p[1]) if n not in visited: if block is not None: if n in block: if not (self.is_inside(*wall) and self.puzzle[wall[0], wall[1]] > 0) \ and not (self.is_inside(*n) and self.solution[n[0], n[1]] < 0): next_ones.append(n) else: if not (self.is_inside(*wall) and self.puzzle[wall[0], wall[1]] > 0) \ and not (self.is_inside(*n) and self.puzzle[n[0], n[1]] > 0): next_ones.append(n) for n in next_ones: n_sym = symmetric_point(i, j, n[0], n[1]) p_sym = symmetric_point(i, j, p[0], p[1]) new_wall = wall_between(p_sym[0], p_sym[1], n_sym[0], n_sym[1]) curr_wall = wall_between(p[0], p[1], n[0], n[1]) if self.is_wall(*curr_wall) and \ self.is_inside(*new_wall) and not (self.is_wall(*new_wall) or self.puzzle[new_wall[0], new_wall[1]] > 0): self.solution[new_wall[0], new_wall[1]] = 1 filled_count += 1 if self.is_wall(*new_wall) and \ self.is_inside(*curr_wall) and not (self.is_wall(*curr_wall) or self.puzzle[curr_wall[0], curr_wall[1]] > 0): self.solution[curr_wall[0], curr_wall[1]] = 1 filled_count += 1 if not no_queue: for n in next_ones: curr_wall = wall_between(p[0], p[1], n[0], n[1]) if not self.is_wall(*curr_wall) and \ self.is_inside(*n) and self.solution[n[0], n[1]] < 1: queue.append(n) if self.puzzle[i, j] > 0: block = get_unique(np.array(visited)) if self.block_is_closed(block, self.solution): for b in block: self.solution[b[0], b[1]] = self.puzzle[i, j] return filled_count
def fill_block(self, x, y, c): """ Fills unfilled blocks in puzzle with dots. :param x: position :param y: position :param c: color to fill :return: """ queue = misc.define_block(x, y) visited = [] while queue: q = queue.pop() visited.append(q) queue2 = misc.adjacent_squares(*q) for q2 in queue2: if q2 not in visited and \ not self.solver.is_wall(*misc.wall_between(q[0], q[1], q2[0], q2[1])) and \ self.solver.is_inside(*q2): queue.append(q2) block = misc.get_unique(np.array(visited)) if len(block) == 1: b = block[0] self.solver.puzzle[b[0], b[1]] = c self.solver.solution[b[0], b[1]] = c elif len(block) == 2: new_dot = misc.wall_between(block[0][0], block[0][1], block[1][0], block[1][1]) self.solver.puzzle[new_dot[0], new_dot[1]] = c self.solver.solution[block[0][0], block[0][1]] = c self.solver.solution[block[1][0], block[1][1]] = c else: # check if symmetric xs = [a[0] for a in block] ys = [a[1] for a in block] dot = [int((min(xs) + max(xs))/2), int((min(ys) + max(ys))/2)] symmetric = True for b in block: sym_b = misc.symmetric_point(dot[0], dot[1], b[0], b[1]) if [sym_b[0], sym_b[1]] not in block.tolist(): symmetric = False if symmetric: self.solver.puzzle[dot[0], dot[1]] = c for b in block: self.solver.solution[b[0], b[1]] = c else: new_dot = block[np.random.randint(len(block))] self.solver.puzzle[new_dot[0], new_dot[1]] = c return True return False
def remove_redundant_walls(self): """Removes any redundant walls inside blocks.""" for i in range(0, self.size[0]): for j in range(0, self.size[1]): if self.solver.puzzle[i, j] > 0: queue = misc.define_block(i, j) visited = [] while queue: q = queue.pop() visited.append(q) queue2 = misc.adjacent_squares(*q) for q2 in queue2: if q2 not in visited and \ not self.solver.is_wall(*misc.wall_between(q[0], q[1], q2[0], q2[1])) and \ self.solver.is_inside(*q2): queue.append(q2) block = misc.get_unique(np.array(visited)) all_walls = [] for b in block: all_walls.append(misc.define_frame(b[0], b[1])) all_walls = np.array(all_walls).reshape(-1, 2) red_walls = np.array([x for x in all_walls if misc.count(all_walls, x) > 1]) for w in red_walls: self.solver.solution[w[0], w[1]] = 0
def init_fill(self): """Fills obvious lines between two dots: if two squares contain dot or part of dot there is line.""" for x in range(0, self.size[0], 2): for y in range(0, self.size[1], 2): if self.contains_dot(x, y): adjacent = adjacent_squares(x, y) for pair in adjacent: if self.is_inside(*pair): i, j = pair if self.contains_dot( i, j) and not self.is_same_dot(x, y, i, j): a, b = wall_between(x, y, i, j) self.solution[a, b] = 1
def update_user_filling(self): """Updates blocked regions and fills them.""" for i in range(self.size[0]): for j in range(self.size[1]): if self.puzzle[i, j] > 0: block = [] if self.block_is_closed(define_block(i, j), self.user_solution): block = define_block(i, j) else: queue = define_block(i, j) visited = [] search = True while queue and search: p = queue.pop() visited.append(p) next_ones = adjacent_squares(p[0], p[1]) for n in next_ones: if self.is_inside(*n) and n not in visited: if not self.is_wall(*wall_between( p[0], p[1], n[0], n[1]), user=True): queue.append(n) if self.puzzle[n[0], n[1]] > 0 and \ not self.is_wall(*wall_between(p[0], p[1], n[0], n[1])): search = False break if search: block = get_unique(np.array(visited)) if len(block) > 0: if self.block_is_closed(block, self.user_solution): for b in block: self.user_solution[b[0], b[1]] = self.puzzle[i, j] for i, row in enumerate(self.user_solution): for j, el in enumerate(row): self.fill_color[ i, j] = el if i % 2 == 0 and j % 2 == 0 and el > 0 else 0
def find_blocked_regions(self): """Finds parts of blocks with all walls checked and one dot. Then fills symmetric part of that block.""" filled_count = 0 for i, row in enumerate(self.solution): for j, el in enumerate(row): if i % 2 == 0 and j % 2 == 0 and el == 0: queue = [] dots = [] visited = [[i, j]] for p in adjacent_squares(i, j): pos_wall = wall_between(i, j, p[0], p[1]) cor_dot = self.dot_in_corner(i, j, p[0], p[1]) if self.is_inside( *pos_wall) and self.puzzle[pos_wall[0], pos_wall[1]] > 0: dots.append(pos_wall) elif not self.is_wall(*pos_wall) and self.is_inside( *p) and self.puzzle[p[0], p[1]] > 0: dots.append(p) elif not self.is_wall(*pos_wall): queue.append(p) if not cor_dot == [-1, -1]: dots.append(cor_dot) while queue: p = queue.pop() sym_part = False if len(dots) == 1: for d in dots: s = symmetric_point(d[0], d[1], p[0], p[1]) if [s[0], s[1]] in visited: sym_part = True if not sym_part: visited.append(p) next_ones = adjacent_squares(p[0], p[1]) for n in next_ones: pos_wall = wall_between(p[0], p[1], n[0], n[1]) if n not in visited and not self.is_wall( *pos_wall): corner_dot = self.dot_in_corner( n[0], n[1], p[0], p[1]) if self.is_inside(*pos_wall) and self.puzzle[pos_wall[0], pos_wall[1]] > 0 \ and pos_wall not in dots: dots.append(pos_wall) elif self.is_inside(*n) and self.puzzle[ n[0], n[1]] > 0 and n not in dots: dots.append(n) elif self.is_inside( *n ) and n not in visited and n not in dots: queue.append(n) if not corner_dot == [ -1, -1 ] and corner_dot not in dots: dots.append(corner_dot) block = get_unique(np.array(visited)) if len(dots) == 1 and len(block) > 0: dot = dots[0] filled_count += self.fill_from_dot(dot[0], dot[1], k=0, block=block) elif len(dots) > 1 and len(block) > 0: self.test_dots(i, j, dots) return filled_count