def do_triple_swap(self): before = self.board.evaluate() swaps = list(self.enumerate_all_swaps()) try: for idx1, (swap1id1, swap1id2) in enumerate(swaps): self.swap(swap1id1, swap1id2) for idx2, swap2id1, swap2id2 in enumerate(swaps): self.swap(swap2id1, swap2id2) for idx3, swap3id1, swap3id2 in enumerate(swaps): self.swap(swap3id1, swap3id2) self.board.fix_orientation() self.board.heuristic_orientation() after = board.evaluate() if after > before: #print(f"triple swap success {swap1id1}{swap1id2}{swap2id1}{swap2id2}{swap3id1}{swap3id2} score {before} -> {after}") raise Exception() # third swap back self.swap(swap3id1, swap3id2) # second swap back self.swap(swap2id1, swap2id2) # first swap back self.swap(swap1id1, swap1id2) except: # we find something, cool... self.board.fix_orientation() self.board.heuristic_orientation() return True return False
def check_best(): curr = board.evaluate() global best global shuffle_counter global shuffle_backup # # if shuffle_counter <= 0 and curr == best: # # trying to find sequence of ANY 2 swaps that potentially increase the overall score ... # #swapper.do_double_swap() # shuffle_backup = copy.deepcopy(board) # swapper.shuffle() # shuffle_counter = 3 #if True: # DEBUG TEST ONLY #if double_swap_counter <= 0 and curr == best: # if False: # double swapping disabled for now - until not optimized # print("DOUBLE SWAP! Start...") # # trying to find sequence of ANY 2 swaps that potentially increase the overall score ... # #swapper.do_double_swap() # swapper.do_double_swap() # print("DOUBLE SWAP! End...") # double_swap_counter = 3 ui.update() if best < curr: print(f"[UI] Best score improved to {curr}") best = curr if best >= board.max_score() - 30: board.save("save " + str(uuid.uuid4()) + "_" + str(best) + ".csv") # we fill in remaining pieces to have a slightly better score if best == board.max_score(): pygame.display.set_caption(f'Puzzle SOLVED!') print("SOLVED!") # elif best == curr: # double_swap_counter -= 1 pygame.display.set_caption( f'SBest {best}/{board.max_score()} SCurr {curr}/{board.max_score()}' )
start = time.time() running_min = 0 running_sec = 0 next_explored_stats_update = start explored_stats_rate = 5 explored_str = "" best_replacer = replacer best_score_count_limit = 500 best_score_counter = best_score_count_limit best = 0 while True: replacer.step() ui.update() val = board.evaluate() if best < val: best_replacer = copy.deepcopy(replacer) #ui.board = best_board #ui.update() best = val # we fill in remaining pieces to have a slightly better score best_score_counter = best_score_count_limit else: best_score_counter -= 1 if best_score_counter <= 0: best_score_counter = best_score_count_limit replacer = best_replacer ui.board = best_replacer.board
def quick_swaps(self): before = self.board.evaluate() max_after = before max_indices = None same_indices = [] CORNERS = 0 EDGES = 1 INNER = 2 seq = [INNER, EDGES, CORNERS] random.shuffle(seq) try: for type in seq: if type == CORNERS: # see how much we gain be swapping corners ... corner_idxs = self.cached_corners_idxs random.shuffle(corner_idxs) # throw away hint pieces evals = [ self.board.evaluate_piece(i, j) for i, j in corner_idxs ] evals, corner_idxs = zip(*sorted(zip(evals, corner_idxs))) for idx1 in range(1, len(corner_idxs)): for idx2 in range(idx1): corner1 = corner_idxs[idx1] corner2 = corner_idxs[idx2] self.board.exchange(*corner1, *corner2) self.board.marks[corner1[0]][corner1[1]], self.board.marks[corner2[0]][corner2[1]] = \ self.board.marks[corner2[0]][corner2[1]], self.board.marks[corner1[0]][corner1[1]] self.board.fix_orientation() after = board.evaluate() if after > max_after: max_after = after max_indices = (corner1, corner2) raise Exception() if after == before: same_indices.append((corner1, corner2)) self.board.exchange(*corner1, *corner2) self.board.marks[corner1[0]][corner1[1]], self.board.marks[corner2[0]][corner2[1]] = \ self.board.marks[corner2[0]][corner2[1]], self.board.marks[corner1[0]][corner1[1]] elif type == EDGES: # ... or by swapping edges ... edge_idxs = self.cached_edge_idxs random.shuffle(edge_idxs) evals = [ self.board.evaluate_piece(i, j) for i, j in edge_idxs ] evals, edge_idxs = zip(*sorted(zip(evals, edge_idxs))) for idx1 in range(1, len(edge_idxs)): for idx2 in range(idx1): edge1 = edge_idxs[idx1] edge2 = edge_idxs[idx2] self.board.exchange(*edge1, *edge2) self.board.marks[edge1[0]][edge1[1]], self.board.marks[edge2[0]][edge2[1]] = \ self.board.marks[edge2[0]][edge2[1]], self.board.marks[edge1[0]][edge1[1]] self.board.fix_orientation() after = self.board.evaluate() if after > max_after: max_after = after max_indices = (edge1, edge2) raise Exception() if after == before: same_indices.append((edge1, edge2)) self.board.exchange(*edge1, *edge2) self.board.marks[edge1[0]][edge1[1]], self.board.marks[edge2[0]][edge2[1]] = \ self.board.marks[edge2[0]][edge2[1]], self.board.marks[edge1[0]][edge1[1]] elif type == INNER: # ... or by swapping inner pieces inner_idxs = self.cached_inner_idxs random.shuffle(inner_idxs) # pick only those that have score < 4 actual_inner_idxs = [] evals = [] for i, j in inner_idxs: val = self.board.evaluate_piece(i, j) if val <= 4: actual_inner_idxs.append((i, j)) evals.append(val) # evals = [self.board.evaluate_piece(i,j) for i,j in inner_idxs] evals, actual_inner_idxs = zip( *sorted(zip(evals, actual_inner_idxs))) for idx1 in range(1, len(actual_inner_idxs)): inner1 = actual_inner_idxs[idx1] for idx2 in range(idx1): inner2 = actual_inner_idxs[idx2] if evals[idx2] >= 4: break orig_dir1 = self.board.board[inner1[0]][ inner1[1]].dir orig_dir2 = self.board.board[inner2[0]][ inner2[1]].dir piece_score_before = self.board.evaluate_piece( *inner1) + self.board.evaluate_piece(*inner2) # if these pieces are next to each other and they share a color now, # then we have over counted it if self.have_common_edge(inner1, inner2): piece_score_before -= 1 self.board.exchange(*inner1, *inner2) self.board.marks[inner1[0]][inner1[1]], self.board.marks[inner2[0]][inner2[1]] = \ self.board.marks[inner2[0]][inner2[1]], self.board.marks[inner1[0]][inner1[1]] piece_score_best_after = piece_score_before for dir1 in range(4): for dir2 in range(4): self.board.board[inner1[0]][ inner1[1]].dir = dir1 self.board.board[inner2[0]][ inner2[1]].dir = dir2 piece_score_after = self.board.evaluate_piece( *inner1) piece_score_after += self.board.evaluate_piece( *inner2) # if these pieces are next to each other and they share a color now, # then we have over counted it if self.have_common_edge(inner1, inner2): piece_score_after -= 1 # after = board.evaluate() # if after > max_after: # max_after = after # max_indices = (inner1, inner2) # raise Exception() # if after == before: # same_indices.append((inner1, inner2)) if piece_score_after > piece_score_best_after: #print( # f"Switching {inner1} <-> {inner2}, score {piece_score_before} to {piece_score_after}") piece_score_best_after = piece_score_after self.board.heuristic_orientation() raise Exception() if piece_score_after == piece_score_before: same_indices.append((inner1, inner2)) self.board.exchange(*inner1, *inner2) self.board.marks[inner1[0]][inner1[1]], self.board.marks[inner2[0]][inner2[1]] = \ self.board.marks[inner2[0]][inner2[1]], self.board.marks[inner1[0]][inner1[1]] self.board.board[inner1[0]][ inner1[1]].dir = orig_dir1 self.board.board[inner2[0]][ inner2[1]].dir = orig_dir2 except: # we find something, cool... self.board.fix_orientation() return True # If we've got here, nothing more to do #print("Can't find anything else...") if same_indices: # crazy variant, lets shuffle all the indicies we can -> temporaririly can decrease the score though random.shuffle(same_indices) for same_pair in same_indices[:10]: #print(f"... exchanging pieces {same_pair[0]} with {same_pair[1]} with same result to give chance of swing into another possibilities") board.exchange(*same_pair[0], *same_pair[1]) board.marks[same_pair[0][0]][same_pair[0][1]], board.marks[same_pair[1][0]][same_pair[1][1]] = \ board.marks[same_pair[1][0]][same_pair[1][1]], board.marks[same_pair[0][0]][same_pair[0][1]] board.fix_orientation() board.heuristic_orientation() return True # same_pair = same_indices[random.randint(0, len(same_indices) - 1)] # print(f"... exchanging pieces {same_pair[0]} with {same_pair[1]} with same result to give chance of swing into another possibilities") # board.exchange(*same_pair[0], *same_pair[1]) # board.marks[same_pair[0][0]][same_pair[0][1]], board.marks[same_pair[1][0]][same_pair[1][1]] = \ # board.marks[same_pair[1][0]][same_pair[1][1]], board.marks[same_pair[0][0]][same_pair[0][1]] # board.fix_orientation() # board.heuristic_orientation() # return True else: #print("... and no pieces with same score!") return False
if not board.board[i][j]: board.put_piece(i, j, board.puzzle_def.all[id], 0) break pass elif board.puzzle_def.all[id].get_type() == TYPE_EDGE: for i, j in board.enumerate_edges(): if not board.board[i][j]: board.put_piece(i, j, board.puzzle_def.all[id], 0) break else: # INNER for i, j in board.enumerate_inner(): if not board.board[i][j]: board.put_piece(i, j, board.puzzle_def.all[id], 0) break board.fix_orientation() board.evaluate() else: board.randomize() board.fix_orientation() board.heuristic_orientation() # mark the pieces for i in range(height): for j in range(width): if board.board[i][j]: board.marks[i][j] = board.board[i][j].piece_def.id swapper = Swapper(board) ui = ui.BoardUi(board) ui.init()