def _get_changes_to_fit( self, destination_index: int, destination: StagingPalette ) -> Optional[List['ColorRemapsIntoStagingPalettesEvaluator.ChangeList']]: # Check this remap to see if it has a palette assigned. If it does, does it match the destination? assigned_palette = self.source.get_intention( ColorRemap.INTENTION_PALETTE) if (assigned_palette is not None) and (assigned_palette != destination_index): # We have a remap that wants to be assigned to a specific palette, and it's not this one. return None # Take the colors in the source and execute a solver to map them to the palette's colors. palette_colors = destination.color_entries solver = ConstraintSolver(self.source.color_entries, palette_colors, ColorsIntoColorsEvaluator, None) while solver.is_exhausted() == False: solver.update() # Did we have any solutions? solutions = solver.solutions if len(solutions) == 0: # No solutions means we can't fit. return None change_lists = [] # Each solution is a possible way to fit the remap into the palette for solution in solutions: # A solution is just a list of Moves. Make each solution into its own ChangeList. change_list = ColorRemapsIntoStagingPalettesEvaluator.ChangeList( solution) change_lists.append(change_list) return change_lists
color_remap={}) # COLOR REMAPS color_remaps = [font_color_remap, flags_color_remap] ############################################################################## # STAGING PALETTES staging_palette_sprites = StagingPalette(16) staging_palette_bg_only = StagingPalette(16) staging_palettes = [staging_palette_sprites, staging_palette_bg_only] ############################################################################## # SOLUTION FOR COLOR REMAPS -> STAGING PALETTES remap_to_staging_solver = ConstraintSolver( color_remaps, staging_palettes, ColorRemapsIntoStagingPalettesEvaluator, None) while (len(remap_to_staging_solver.solutions) == 0) and (remap_to_staging_solver.is_exhausted() == False): remap_to_staging_solver.update() # TODO find the best one. remap_to_staging_solution = remap_to_staging_solver.solutions[0] for move in remap_to_staging_solution: # Let the corresponding color remap process these moves. source_remap = color_remaps[move.source_index] source_remap.remap_to_staging_palette(move, staging_palettes) # Now apply the solution to the staging palettes. remap_to_staging_solver.apply_solution(remap_to_staging_solution)
interval_enemy_sprite = Interval(begin=0, end=255, length=2) interval_bg1 = Interval(begin=0, end=447, length=1) interval_bg2 = Interval(begin=256, end=447, length=1) interval_bg3 = Interval(begin=256, end=447, length=1) intervals.append(interval_font) intervals.append(interval_player_sprite) intervals.append(interval_enemy_sprite) intervals.append(interval_bg1) intervals.append(interval_bg2) intervals.append(interval_bg3) bitsets = [] VRAMPositions = BitSet(448) bitsets.append(VRAMPositions) interval_to_VRAM_solver = ConstraintSolver(sources=intervals, destinations=bitsets, evaluator_class=IntervalsToBitSetsEvaluator, debugging=True) while (len(interval_to_VRAM_solver.solutions) == 0) and (interval_to_VRAM_solver.is_exhausted() == False): interval_to_VRAM_solver.update() # How'd the solution go? solution = interval_to_VRAM_solver.solutions[0] for move in solution: # The "source" will be one of our intervals, and since we're only doing one BitSet, our "destination" will always be the VRAMPositions array. # Dig into the change list to figure out which slot was actually chosen. source_interval = intervals[move.source_index] dest_interval = move.change_list.chosen_interval if dest_interval.begin == dest_interval.end: print(f"Interval {move.source_index}: ({source_interval.begin}, {source_interval.end}) with length {source_interval.length} will occupy location {dest_interval.begin}.") else: print(f"Interval {move.source_index}: ({source_interval.begin}, {source_interval.end}) with length {source_interval.length} will occupy locations {dest_interval.begin} thru {dest_interval.end}")
############################################################################## # EXECUTE SOLVER # THIS SOLUTION MAPS PIXELS INTO PIXELS VIA SPRITES sources = [] for pixel_idx in range(len(pixel_list)): pixel_to_sprite_bitset = pixel_to_sprite_bitsets[pixel_idx] source = RasterPixelsToSpritesEvaluator.Source( pixel_to_potential_sprites_bitset=pixel_to_sprite_bitset, sprite_pixel_coverages=potential_sprite_pixel_coverage_bitsets) sources.append(source) dest_pixel_bitset = BitSet(len(pixel_list)) solver = ConstraintSolver(sources=sources, destinations=[dest_pixel_bitset], evaluator_class=RasterPixelsToSpritesEvaluator, debugging=None) solution_count = 0 best_solutions = [] best_pixels_list = None best_sprites_list = None best_sprites_on_a_line = math.inf # Solver will stop when it is either exhausted or finds this many solutions. max_solutions = 250 while (len(solver.solutions) < max_solutions) and (solver.is_exhausted() == False): solver.update()
# Treat the image as one large color remapping problem. We'll divvy up into tiles later. px_array = PixelArray(parent_image, 0, 0, parent_image.width, parent_image.height) px_array.quantize((8, 8, 8), (2, 2, 2)) # Extract all unique colors unique_pixel_values_list = px_array.generate_deterministic_unique_pixel_list() color_remap_font = ColorRemap({}, unique_pixel_values_list, special_color_remap) color_remaps.append(color_remap_font) ############################################################################## # SOLUTION FOR COLOR REMAPS -> STAGING PALETTES remap_to_staging_solver = ConstraintSolver( color_remaps, staging_palettes, ColorRemapsIntoStagingPalettesEvaluator, True) while remap_to_staging_solver.is_exhausted() == False: remap_to_staging_solver.update() # TODO find the best one. remap_to_staging_solution = remap_to_staging_solver.solutions[0] for move in remap_to_staging_solution: # Let the corresponding color remap process these moves. source_remap = color_remaps[move.source_index] source_remap.remap_to_staging_palette(move, staging_palettes) # Now apply the solution to the staging palettes. remap_to_staging_solver.apply_solution(remap_to_staging_solution)
(0, 0, 255)) dest_blue_0.intentions.attempt_set_intention(ColorEntry.INTENTION_SLOT, 0) dest_node_list.append(dest_blue_0) dest_green = ColorEntry() dest_green.intentions.attempt_set_intention(ColorEntry.INTENTION_COLOR, (0, 255, 0)) dest_node_list.append(dest_green) dest_red = ColorEntry() dest_red.intentions.attempt_set_intention(ColorEntry.INTENTION_COLOR, (255, 0, 0)) dest_node_list.append(dest_red) dest_clear_1 = ColorEntry() dest_node_list.append(dest_clear_1) dest_clear_2 = ColorEntry() dest_node_list.append(dest_clear_2) # Start the solver. solver = ConstraintSolver(source_node_list, dest_node_list, ColorsIntoColorsEvaluator, True) while False == solver.is_exhausted(): solver.update() solutions = solver.solutions print(f"Found {len(solutions)} colors-into-colors solutions.")
pattern_intention_map_flips = { Pattern.INTENTION_FLIPS_ALLOWED: Pattern.Flip.HORIZ } for pixel_array in pixel_arrays: index_array = pixel_array.generate_indexed_color_array() pattern = Pattern(index_array=index_array, initial_intentions_map=pattern_intention_map_flips) patterns.append(pattern) ############################################################################## # PATTERN SOLVING dest_map = {} dest_maps = [dest_map] solver = ConstraintSolver(sources=patterns, destinations=dest_maps, evaluator_class=PatternsIntoPatternHashMapsEvaluator, debugging=None) while ((len(solver.solutions) == 0) and (solver.is_exhausted() == False)): solver.update() # How'd we do? solution = solver.solutions[0] solver.apply_solution(solution) # Count uniques. unique_patterns = [] for move in solution: matched = move.change_list.matching_pattern_object_ref if matched is None: # We didn't match anybody else, so we're unique. src_pattern_idx = move.source_index