Spaces:
Sleeping
Sleeping
import numpy as np | |
from collections import deque, Counter | |
# --- Grid Transformation Functions --- | |
def remove_vertical_lines(ctx): | |
rows, cols = len(ctx.grid), len(ctx.grid[0]) | |
for obj in ctx.objects: | |
columns = {} | |
for r, c in obj[2]: | |
if c not in columns: | |
columns[c] = [] | |
columns[c].append(r) | |
for c, rows_in_col in columns.items(): | |
if len(rows_in_col) > 1: | |
unique_vals = {ctx.grid[r][c] for r in rows_in_col} | |
if len(unique_vals) == 1: | |
for r in rows_in_col: | |
ctx.grid[r][c] = 0 | |
return ctx.grid | |
def fill_object_interior(ctx): | |
""" | |
Fills the interior of each object in the GPContext grid. | |
Assumes ctx.objects has been extracted already. | |
""" | |
rows, cols = len(ctx.grid), len(ctx.grid[0]) | |
for obj in ctx.objects: | |
min_r = min(r for r, c in obj) | |
max_r = max(r for r, c in obj) | |
min_c = min(c for r, c in obj) | |
max_c = max(c for r, c in obj) | |
obj_color = ctx.grid[min_r][min_c] | |
fill_color = (obj_color + 1) % 9 or 1 # consistent color, avoid zero | |
for r in range(min_r, max_r + 1): | |
for c in range(min_c, max_c + 1): | |
if (r, c) not in obj and ctx.grid[r][c] == 0: | |
ctx.grid[r][c] = fill_color | |
return ctx.grid | |
def move_right_most_object(ctx): | |
if not ctx.objects: | |
return ctx.grid | |
# Get rightmost object: object with largest column index | |
rightmost_object = max(ctx.objects, key=lambda obj: max(y for x, y in obj[2])) | |
_, value, block = rightmost_object | |
for x, y in block: | |
ctx.grid[x][y] = 0 | |
shift = 0 | |
cols = len(ctx.grid[0]) | |
while True: | |
can_move = True | |
for x, y in block: | |
new_y = y + shift + 1 | |
if new_y >= cols or ctx.grid[x][new_y] != 0: | |
can_move = False | |
break | |
if not can_move: | |
break | |
shift += 1 | |
for x, y in block: | |
ctx.grid[x][y + shift] = value | |
return ctx.grid | |
def move_left_most_object(ctx): | |
if not ctx.objects: | |
return ctx.grid | |
# Get leftmost object: object with smallest column index | |
leftmost_object = min(ctx.objects, key=lambda obj: min(y for x, y in obj[2])) | |
_, value, block = leftmost_object | |
for x, y in block: | |
ctx.grid[x][y] = 0 | |
shift = 0 | |
while True: | |
can_move = True | |
for x, y in block: | |
new_y = y - (shift + 1) | |
if new_y < 0 or ctx.grid[x][new_y] != 0: | |
can_move = False | |
break | |
if not can_move: | |
break | |
shift += 1 | |
for x, y in block: | |
ctx.grid[x][y - shift] = value | |
return ctx.grid | |
def move_bottom_most_object(ctx): | |
if not ctx.objects: | |
return ctx.grid | |
# Get bottommost object (last one in the list after sorting by top_row) | |
bottom_object = ctx.objects[-1] | |
_, value, block = bottom_object | |
# Remove it from the grid | |
for x, y in block: | |
ctx.grid[x][y] = 0 | |
# Compute shift (same as top, move down) | |
shift = 0 | |
rows = len(ctx.grid) | |
while True: | |
can_move = True | |
for x, y in block: | |
new_x = x + shift + 1 | |
if new_x >= rows or ctx.grid[new_x][y] != 0: | |
can_move = False | |
break | |
if not can_move: | |
break | |
shift += 1 | |
# Place object | |
for x, y in block: | |
ctx.grid[x + shift][y] = value | |
return ctx.grid | |
def detect_objects(grid): | |
""" | |
Detects objects in an ARC grid. | |
Objects are contiguous regions of the same color (4-connected). | |
Returns a list of objects, where each object is a set of (row, col) coordinates. | |
""" | |
rows, cols = len(grid), len(grid[0]) | |
visited = set() | |
objects = [] | |
def bfs(start_r, start_c, color): | |
""" Perform BFS to find all connected pixels of the same color """ | |
queue = deque([(start_r, start_c)]) | |
obj_pixels = set() | |
while queue: | |
r, c = queue.popleft() | |
if (r, c) in visited: | |
continue | |
visited.add((r, c)) | |
obj_pixels.add((r, c)) | |
# Check 4-connected neighbors (up, down, left, right) | |
for dr, dc in [(-1, 0), (1, 0), (0, -1), (0, 1)]: | |
nr, nc = r + dr, c + dc | |
if 0 <= nr < rows and 0 <= nc < cols and (nr, nc) not in visited: | |
if grid[nr][nc] == color: | |
queue.append((nr, nc)) | |
return obj_pixels | |
# Iterate over the grid to find objects | |
for r in range(rows): | |
for c in range(cols): | |
if (r, c) not in visited and grid[r][c] != 0: # Ignore background (0) | |
obj = bfs(r, c, grid[r][c]) | |
objects.append(obj) | |
return objects | |
def highlight_detected_objects(grid): | |
objects = detect_objects(grid) | |
new_grid = [row[:] for row in grid] | |
for idx, obj in enumerate(objects, start=1): | |
for r, c in obj: | |
new_grid[r][c] = (idx % 9) or 1 | |
return new_grid | |
def fill_object_interior(grid): | |
""" Modifies the grid by filling the interiors of detected objects with a different color.""" | |
objects = detect_objects(grid) | |
rows, cols = len(grid), len(grid[0]) | |
new_grid = [row[:] for row in grid] # Create a copy of the grid | |
for obj in objects: | |
min_r = min(r for r, c in obj) | |
max_r = max(r for r, c in obj) | |
min_c = min(c for r, c in obj) | |
max_c = max(c for r, c in obj) | |
# Find a new fill color (incrementing the current color modulo 9 for variation) | |
obj_color = grid[min_r][min_c] | |
fill_color = (obj_color + 1) % 9 if obj_color + 1 != 0 else 1 | |
# Identify and fill the interior pixels of the object | |
for r in range(min_r, max_r + 1): | |
for c in range(min_c, max_c + 1): | |
if (r, c) not in obj and grid[r][c] == 0: # Empty space inside the object | |
new_grid[r][c] = fill_color | |
return new_grid | |
def diamirror(input_grid): | |
return np.transpose(input_grid) | |
import numpy as np | |
def get_object_bounds(grid): | |
grid = np.array(grid) | |
top, bottom = None, None | |
for i in range(grid.shape[0]): | |
if np.any(grid[i] != 0): | |
if top is None: | |
top = i | |
bottom = i | |
return top, bottom | |
def reverse_object_top_bottom(grid): | |
grid = np.array(grid) | |
top, bottom = get_object_bounds(grid) | |
if top is None or bottom is None: | |
return grid | |
grid_copy = np.copy(grid) | |
grid_copy[top:bottom+1] = np.flipud(grid[top:bottom+1]) | |
return grid_copy | |
def hmirror(input_grid: np.ndarray) -> np.ndarray: | |
return np.fliplr(input_grid) | |
def vmirrors(input_grid: np.ndarray) -> np.ndarray: | |
return np.flipud(input_grid) | |
def flip_horizontal(input_grid: np.ndarray) -> np.ndarray: | |
return np.fliplr(input_grid) | |
def flip_vertical(input_grid: np.ndarray) -> np.ndarray: | |
return np.flipud(input_grid) | |
def rotate_90(input_grid: np.ndarray) -> np.ndarray: | |
return np.rot90(input_grid, k=-1) | |
def rotate_180(input_grid: np.ndarray) -> np.ndarray: | |
return np.rot90(input_grid, k=2) | |
def rotate_270(input_grid: np.ndarray) -> np.ndarray: | |
return np.rot90(input_grid, k=1) | |
def identity(input_grid: np.ndarray) -> np.ndarray: | |
return input_grid | |
def find_center_pixel(grid): | |
"""Finds the center pixel of the input grid and returns it as a 1x1 output grid.""" | |
center_index = len(grid[0]) // 2 # Get the middle index | |
return [[grid[0][center_index]]] # Return as a 1x1 grid with the center pixel | |
# --- Object Detection and Manipulation --- | |
def detect_objects(grid): | |
"""Detects objects in the grid and returns a list of bounding boxes and pixel coordinates.""" | |
height, width = len(grid), len(grid[0]) | |
visited = set() | |
objects = [] | |
def bfs(r, c, color): | |
"""Finds all pixels belonging to an object using BFS.""" | |
queue = [(r, c)] | |
pixels = [] # Use a list instead of a set | |
min_r, max_r, min_c, max_c = r, r, c, c | |
while queue: | |
x, y = queue.pop(0) | |
if (x, y) in visited: | |
continue | |
visited.add((x, y)) | |
pixels.append((x, y)) # Append to list | |
min_r, max_r = min(min_r, x), max(max_r, x) | |
min_c, max_c = min(min_c, y), max(max_c, y) | |
for dx, dy in [(-1, 0), (1, 0), (0, -1), (0, 1)]: # Only vertical & horizontal connections | |
nx, ny = x + dx, y + dy | |
if (0 <= nx < height and 0 <= ny < width and (nx, ny) not in visited and grid[nx][ny] == color): | |
queue.append((nx, ny)) | |
return (min_r, max_r, min_c, max_c, color, pixels) # Return tuple, pixels as a list | |
for r in range(height): | |
for c in range(width): | |
if grid[r][c] != 0 and (r, c) not in visited: | |
visited.add((r, c)) | |
objects.append(bfs(r, c, grid[r][c])) # Append tuple to list | |
return objects # Ensure `objects` is a list, not a set | |
def extract_bottom_object(grid): | |
"""Extracts the bottom-most object from the grid, crops it, and returns it as a new grid.""" | |
objects = detect_objects(grid) | |
if not objects: | |
return grid | |
bottom_object = max(objects, key=lambda obj: obj[1]) # obj[1] is max_r | |
min_r, max_r, min_c, max_c, obj_color, pixels = bottom_object | |
cropped_height = max_r - min_r + 1 | |
cropped_width = max_c - min_c + 1 | |
cropped_grid = np.zeros((cropped_height, cropped_width), dtype=int) | |
for r, c in pixels: | |
cropped_grid[r - min_r, c - min_c] = obj_color | |
return cropped_grid.tolist() | |
def keep_bottom_object(grid): | |
"""Keeps only the bottom-most object and removes all others.""" | |
height, width = len(grid), len(grid[0]) | |
objects = detect_objects(grid) | |
output_grid = np.zeros((height, width), dtype=int) | |
if not objects: | |
return output_grid.tolist() | |
bottom_object = max(objects, key=lambda obj: obj[1]) # obj[1] is max_r | |
for r, c in bottom_object[5]: # obj[5] contains pixels | |
output_grid[r][c] = bottom_object[4] # obj[4] is color | |
return output_grid.tolist() | |
def recolor_to_bottom_object(grid): | |
"""Recolors all objects to match the color of the bottom-most object.""" | |
height, width = len(grid), len(grid[0]) | |
objects = detect_objects(grid) | |
output_grid = np.array(grid) | |
if not objects: | |
return output_grid.tolist() | |
bottom_object = max(objects, key=lambda obj: obj[1]) # obj[1] is max_r | |
bottom_color = bottom_object[4] # obj[4] is color | |
for min_r, max_r, min_c, max_c, obj_color, pixels in objects: | |
for r, c in pixels: | |
output_grid[r][c] = bottom_color # Change to bottom-most object's color | |
return output_grid.tolist() | |
def remove_top_bottom_objects(grid): | |
"""Removes objects that touch either the top or bottom of the grid.""" | |
height, width = len(grid), len(grid[0]) | |
objects = detect_objects(grid) | |
output_grid = np.zeros((height, width), dtype=int) | |
if not objects: | |
return output_grid.tolist() | |
min_top = min(obj[0] for obj in objects) | |
max_bottom = max(obj[1] for obj in objects) | |
for (min_r, max_r, min_c, max_c, obj_color, pixels) in objects: | |
if min_r == min_top or max_r == max_bottom: | |
continue | |
for r, c in pixels: | |
output_grid[r][c] = obj_color | |
return output_grid.tolist() | |
def extract_topmost_object(grid): | |
"""Extracts the top-most object from the grid, crops it, and returns it as a new grid.""" | |
objects = detect_objects(grid) | |
if not objects: | |
return grid | |
topmost_object = min(objects, key=lambda obj: obj[0]) # obj[0] is min_r | |
min_r, max_r, min_c, max_c, obj_color, pixels = topmost_object | |
cropped_height = max_r - min_r + 1 | |
cropped_width = max_c - min_c + 1 | |
cropped_grid = np.zeros((cropped_height, cropped_width), dtype=int) | |
for r, c in pixels: | |
cropped_grid[r - min_r, c - min_c] = obj_color | |
return cropped_grid.tolist() | |
def swap_objects(grid): | |
"""Swaps detected objects in the grid.""" | |
objects = detect_objects(grid) | |
objects = sorted(objects, key=lambda obj: obj[1]) # Sort by vertical position | |
object_positions = [obj[5] for obj in objects] # obj[5] contains pixels | |
object_colors = [obj[4] for obj in objects] # obj[4] is color | |
swapped_positions = object_positions[::-1] | |
new_grid = np.zeros_like(grid) | |
for color, new_positions in zip(object_colors, swapped_positions): | |
for r, c in new_positions: | |
new_grid[r][c] = color | |
return new_grid.tolist() | |
# --- Pixel & Color Manipulation --- | |
def transform_blue_to_red(input_grid): | |
"""Transforms all blue (1) pixels to red (2).""" | |
grid = np.array(input_grid) | |
return np.where(grid == 1, 2, grid).tolist() | |
def fill_downward(grid): | |
"""Fills non-zero pixels downward, propagating their colors downwards in each column.""" | |
height, width = len(grid), len(grid[0]) | |
output_grid = np.array(grid) | |
for col in range(width): | |
fill_color = 0 | |
for row in range(height): | |
if grid[row][col] != 0: | |
fill_color = grid[row][col] | |
if fill_color != 0: | |
output_grid[row][col] = fill_color | |
return output_grid.tolist() | |
def remove_below_horizontal_line(grid): | |
"""Detects the first fully connected horizontal line and removes everything below it.""" | |
height, width = len(grid), len(grid[0]) | |
output_grid = np.array(grid) | |
for row in range(height): | |
if np.all(output_grid[row] != 0): | |
output_grid[row + 1:] = 0 | |
break | |
return output_grid.tolist() | |
def find_center_pixel(grid): | |
"""Finds the center of the grid and returns it as a 1x1 pixel grid.""" | |
center_index = len(grid[0]) // 2 | |
return [[grid[0][center_index]]] | |
def extract_largest_row(grid): | |
"""Finds the row with the most non-zero elements and extracts it.""" | |
grid = np.array(grid) | |
max_length = 0 | |
longest_row = [] | |
for row in grid: | |
row_values = row[row > 0] | |
if len(row_values) > max_length: | |
max_length = len(row_values) | |
longest_row = row_values.tolist() | |
return [longest_row] | |
def extract_dominant_colors(grid): | |
"""Finds the two most dominant non-zero colors in the grid.""" | |
flattened = [cell for row in grid for cell in row if cell != 0] | |
color_counts = Counter(flattened) | |
if not color_counts: | |
return [[]] | |
most_common_colors = [color for color, _ in color_counts.most_common(2)] | |
return [[color for color in most_common_colors]] | |
def remove_dominant_color(grid): | |
"""Removes the most dominant color from the grid.""" | |
color_counts = Counter(cell for row in grid for cell in row if cell != 0) | |
if color_counts: | |
dominant_color = max(color_counts, key=color_counts.get) | |
else: | |
return grid | |
return [[0 if cell == dominant_color else cell for cell in row] for row in grid] | |
def find_least_dominant_pixel(grid): | |
"""Finds the least occurring non-zero pixel in the grid.""" | |
pixel_counts = {} | |
for row in grid: | |
for value in row: | |
if value != 0: | |
pixel_counts[value] = pixel_counts.get(value, 0) + 1 | |
if not pixel_counts: | |
return None | |
return min(pixel_counts, key=pixel_counts.get) | |
def remove_least_dominant_pixel(grid): | |
"""Removes the least dominant pixel from the grid.""" | |
rows, cols = len(grid), len(grid[0]) | |
least_dominant_pixel = find_least_dominant_pixel(grid) | |
if least_dominant_pixel is None: | |
return grid | |
new_grid = np.array(grid) | |
for x in range(rows): | |
for y in range(cols): | |
if grid[x][y] == least_dominant_pixel: | |
new_grid[x, y] = 0 | |
return new_grid.tolist() | |
def upscale(input_grid, upscale_factor=3): | |
"""Upscales the grid by expanding each pixel into a 3x3 block.""" | |
def expand_pixel_with_grid(pixel, input_grid): | |
if pixel == 0: | |
return np.zeros((upscale_factor, upscale_factor), dtype=int) | |
else: | |
return input_grid | |
input_rows, input_cols = len(input_grid), len(input_grid[0]) | |
output_grid = np.zeros((input_rows * upscale_factor, input_cols * upscale_factor), dtype=int) | |
for r in range(input_rows): | |
for c in range(input_cols): | |
expanded_block = expand_pixel_with_grid(input_grid[r][c], input_grid) | |
output_grid[r * upscale_factor: (r + 1) * upscale_factor, c * upscale_factor: (c + 1) * upscale_factor] = expanded_block | |
return output_grid | |
def remove_center_object(grid): | |
"""Removes anything located at the center of the grid.""" | |
height, width = len(grid), len(grid[0]) | |
center_r, center_c = height // 2, width // 2 | |
grid = np.array(grid) | |
center_value = grid[center_r, center_c] | |
if center_value != 0: | |
grid[grid == center_value] = 0 | |
return grid.tolist() | |
import numpy as np | |
def draw_horizontal_vertical(grid): | |
"""Adds a horizontal or vertical line of 8s based on object orientation.""" | |
if grid is None or len(grid) == 0 or len(grid[0]) == 0: | |
print("ERROR: Grid is empty. Cannot apply draw_horizontal_vertical.") | |
return grid | |
rows, cols = len(grid), len(grid[0]) | |
print(f"Grid Shape Before Modification: {rows}x{cols}") # Debugging Info | |
new_grid = np.array(grid) | |
for r in range(rows): | |
new_grid[r][-1] = 8 # Rightmost column | |
for c in range(cols): | |
new_grid[0][c] = 8 # Topmost row | |
return new_grid.tolist() | |