Slyracoon23 commited on
Commit
1982bdd
Β·
1 Parent(s): a0d6d4a

Add ARC-AGI Interactive Puzzle Viewer with Git LFS for dataset files

Browse files
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ *.json filter=lfs diff=lfs merge=lfs -text
arc-prize-2025-dataset/arc-agi_evaluation_challenges.json ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:bee6bffea3dc7bcc8fabb5b8e947e1a4950a5087b988f41eee3e57053d2053ad
3
+ size 9190477
arc-prize-2025-dataset/arc-agi_evaluation_solutions.json ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:84be4f4f39b79e82c36d565fc878830988b094917f052ee7069aef30b33ca8f1
3
+ size 223838
arc-prize-2025-dataset/arc-agi_test_challenges.json ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:232264c58f825ee77327dcfc9f4e5cb2f83b8d997eb69032be1bf2205bbe1a83
3
+ size 1015295
arc-prize-2025-dataset/arc-agi_training_challenges.json ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:0a8511f909adc0380fc9b33b42c166c1d2e2de06ead60bee65b153b8c772d916
3
+ size 37629560
arc-prize-2025-dataset/arc-agi_training_solutions.json ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:9f07a38bd25af5e83aa5bf85c5cb1a1fefdb30f6a755256fa65429e697ca97f9
3
+ size 658743
arc-prize-2025-dataset/sample_submission.json ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:6b372dce41ad86a941ccdcbebb2b1926fd4f011d77c824ff421d77730f169a9a
3
+ size 19936
arc_puzzle_gradio_viewer.py ADDED
@@ -0,0 +1,516 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import json
3
+ import numpy as np
4
+ import plotly.graph_objects as go
5
+ from plotly.subplots import make_subplots
6
+ import os
7
+ from typing import List, Dict, Any, Tuple
8
+ import hashlib
9
+
10
+ # Constants
11
+ ARC_COLORS = [
12
+ '#000000', # 0: black
13
+ '#0074D9', # 1: blue
14
+ '#FFDC00', # 2: yellow
15
+ '#FF4136', # 3: red
16
+ '#2ECC40', # 4: green
17
+ '#AAAAAA', # 5: gray
18
+ '#F012BE', # 6: magenta
19
+ '#FF851B', # 7: orange
20
+ '#7FDBFF', # 8: light blue
21
+ '#870C25', # 9: dark red
22
+ ]
23
+
24
+ # UI Constants
25
+ BASE_FIGURE_SIZE = 250
26
+ MAX_FIGURE_SIZE = 400
27
+ GRID_LINE_WIDTH = 2
28
+ GRID_LINE_COLOR = "white"
29
+ DEFAULT_FONT_SIZE = 14
30
+ LARGE_FONT_SIZE = 16
31
+ SMALL_FONT_SIZE = 12
32
+ PLACEHOLDER_COLOR = "#7f8c8d"
33
+ TITLE_COLOR = "#2c3e50"
34
+
35
+ # Layout Constants
36
+ SUBPLOT_HORIZONTAL_SPACING = 0.05
37
+ SUBPLOT_VERTICAL_SPACING = 0.1
38
+ FIGURE_MARGIN = dict(l=10, r=10, t=40, b=10)
39
+ SUBPLOT_MARGIN = dict(l=20, r=20, t=60, b=20)
40
+ HEIGHT_PER_ROW_TRAIN = 200
41
+ HEIGHT_PER_ROW_TEST = 300
42
+ MIN_FIGURE_HEIGHT = 400
43
+
44
+ # Dataset files
45
+ DATASET_FILES = [
46
+ 'arc-prize-2025-dataset/arc-agi_training_challenges.json',
47
+ 'arc-prize-2025-dataset/arc-agi_evaluation_challenges.json'
48
+ ]
49
+
50
+ # Global cache
51
+ PUZZLE_CACHE = None
52
+ FIGURE_CACHE = {}
53
+
54
+ # Header HTML
55
+ HEADER_HTML = """
56
+ <div style="text-align: center; padding: 15px; background: linear-gradient(90deg, #74b9ff, #0984e3); border-radius: 8px; margin-bottom: 15px;">
57
+ <h1 style="color: white; margin: 0; font-size: 1.8em;">🧩 ARC-AGI Interactive Puzzle Viewer</h1>
58
+ <p style="color: white; margin: 5px 0 0 0; font-size: 1em;">Explore ARC-AGI challenges with interactive hover-enabled grids</p>
59
+ </div>
60
+ """
61
+
62
+ CSS_STYLES = """
63
+ .gradio-container {
64
+ max-width: none !important;
65
+ }
66
+ .plot-container {
67
+ overflow: auto !important;
68
+ }
69
+ """
70
+
71
+ def load_puzzles() -> Dict[str, Any]:
72
+ """Load puzzles from dataset files with caching."""
73
+ global PUZZLE_CACHE
74
+
75
+ if PUZZLE_CACHE is not None:
76
+ return PUZZLE_CACHE
77
+
78
+ puzzles = {}
79
+ print("πŸ”„ Loading puzzles from dataset...")
80
+
81
+ for file in DATASET_FILES:
82
+ if os.path.exists(file):
83
+ try:
84
+ with open(file, 'r') as f:
85
+ data = json.load(f)
86
+ puzzles.update(data)
87
+ print(f"βœ… Loaded {len(data)} puzzles from {file}")
88
+ except Exception as e:
89
+ print(f"❌ Error loading {file}: {e}")
90
+
91
+ PUZZLE_CACHE = puzzles
92
+ print(f"🎯 Total puzzles cached: {len(puzzles)}")
93
+ return puzzles
94
+
95
+ def create_grid_hash(grid: List[List[int]]) -> str:
96
+ """Create a unique hash for a grid to use as cache key."""
97
+ return hashlib.md5(str(grid).encode()).hexdigest()
98
+
99
+ def create_hover_text(grid: np.ndarray) -> List[List[str]]:
100
+ """Create hover text for grid cells."""
101
+ hover_text = []
102
+ for i in range(grid.shape[0]):
103
+ hover_row = []
104
+ for j in range(grid.shape[1]):
105
+ hover_row.append(f"Row: {i}<br>Col: {j}<br>Value: {grid[i][j]}")
106
+ hover_text.append(hover_row)
107
+ return hover_text
108
+
109
+ def add_grid_lines(fig: go.Figure, grid_shape: Tuple[int, int], subplot_row: int = None, subplot_col: int = None):
110
+ """Add white grid lines to a figure or subplot."""
111
+ rows, cols = grid_shape
112
+
113
+ # Add horizontal lines
114
+ for i in range(rows + 1):
115
+ fig.add_shape(
116
+ type="line",
117
+ x0=-0.5, x1=cols-0.5, y0=i-0.5, y1=i-0.5,
118
+ line=dict(color=GRID_LINE_COLOR, width=GRID_LINE_WIDTH),
119
+ row=subplot_row, col=subplot_col
120
+ )
121
+
122
+ # Add vertical lines
123
+ for j in range(cols + 1):
124
+ fig.add_shape(
125
+ type="line",
126
+ x0=j-0.5, x1=j-0.5, y0=-0.5, y1=rows-0.5,
127
+ line=dict(color=GRID_LINE_COLOR, width=GRID_LINE_WIDTH),
128
+ row=subplot_row, col=subplot_col
129
+ )
130
+
131
+ def create_heatmap_trace(grid: np.ndarray) -> go.Heatmap:
132
+ """Create a heatmap trace for a grid."""
133
+ colorscale = [[i/9, color] for i, color in enumerate(ARC_COLORS)]
134
+ hover_text = create_hover_text(grid)
135
+
136
+ return go.Heatmap(
137
+ z=grid,
138
+ colorscale=colorscale,
139
+ showscale=False,
140
+ hovertemplate='%{text}<extra></extra>',
141
+ text=hover_text,
142
+ zmin=0,
143
+ zmax=9,
144
+ hoverongaps=False
145
+ )
146
+
147
+ def create_placeholder_figure(text: str, title: str = "", height: int = 300, width: int = 300) -> go.Figure:
148
+ """Create a placeholder figure with text annotation."""
149
+ fig = go.Figure()
150
+ fig.add_annotation(
151
+ text=text,
152
+ x=0.5, y=0.5,
153
+ showarrow=False,
154
+ font=dict(size=DEFAULT_FONT_SIZE, color=PLACEHOLDER_COLOR)
155
+ )
156
+ fig.update_layout(
157
+ title=dict(text=title, font=dict(size=DEFAULT_FONT_SIZE, color=TITLE_COLOR)) if title else None,
158
+ xaxis=dict(visible=False),
159
+ yaxis=dict(visible=False),
160
+ height=height,
161
+ width=width,
162
+ margin=FIGURE_MARGIN,
163
+ paper_bgcolor="white",
164
+ plot_bgcolor="white"
165
+ )
166
+ return fig
167
+
168
+ def calculate_figure_dimensions(grid_shape: Tuple[int, int]) -> Tuple[int, int]:
169
+ """Calculate optimal figure dimensions based on grid shape."""
170
+ rows, cols = grid_shape
171
+ if rows == 0 or cols == 0:
172
+ return BASE_FIGURE_SIZE, BASE_FIGURE_SIZE
173
+
174
+ aspect_ratio = cols / rows
175
+
176
+ if aspect_ratio > 1:
177
+ # Wide grid
178
+ fig_width = min(BASE_FIGURE_SIZE * aspect_ratio, MAX_FIGURE_SIZE)
179
+ fig_height = BASE_FIGURE_SIZE
180
+ else:
181
+ # Tall grid
182
+ fig_width = BASE_FIGURE_SIZE
183
+ fig_height = min(BASE_FIGURE_SIZE / aspect_ratio, MAX_FIGURE_SIZE)
184
+
185
+ return int(fig_width), int(fig_height)
186
+
187
+ def create_grid_figure(grid: List[List[int]], title: str = "Grid") -> go.Figure:
188
+ """Create an interactive Plotly heatmap for a grid with hover functionality."""
189
+ if not grid or len(grid) == 0:
190
+ return create_placeholder_figure("Empty Grid", title)
191
+
192
+ # Create cache key
193
+ grid_hash = create_grid_hash(grid)
194
+ cache_key = f"{grid_hash}_{title}"
195
+
196
+ if cache_key in FIGURE_CACHE:
197
+ cached_fig = FIGURE_CACHE[cache_key]
198
+ cached_fig.update_layout(title=dict(text=title, font=dict(size=DEFAULT_FONT_SIZE, color=TITLE_COLOR)))
199
+ return cached_fig
200
+
201
+ grid_array = np.array(grid)
202
+ fig_width, fig_height = calculate_figure_dimensions(grid_array.shape)
203
+
204
+ fig = go.Figure(data=create_heatmap_trace(grid_array))
205
+ add_grid_lines(fig, grid_array.shape)
206
+
207
+ fig.update_layout(
208
+ title=dict(text=title, font=dict(size=DEFAULT_FONT_SIZE, color=TITLE_COLOR)),
209
+ xaxis=dict(visible=False, range=[-0.5, grid_array.shape[1]-0.5]),
210
+ yaxis=dict(visible=False, autorange="reversed", range=[-0.5, grid_array.shape[0]-0.5]),
211
+ height=fig_height,
212
+ width=fig_width,
213
+ margin=FIGURE_MARGIN,
214
+ showlegend=False,
215
+ paper_bgcolor="white",
216
+ plot_bgcolor="white"
217
+ )
218
+
219
+ # Cache the figure
220
+ FIGURE_CACHE[cache_key] = go.Figure(fig)
221
+ return fig
222
+
223
+ def create_unknown_output_figure() -> go.Figure:
224
+ """Create a clean, simple figure for unknown output."""
225
+ fig = go.Figure()
226
+
227
+ # Simple dashed border rectangle
228
+ fig.add_shape(
229
+ type="rect",
230
+ x0=0.1, y0=0.15, x1=0.9, y1=0.85,
231
+ line=dict(color=PLACEHOLDER_COLOR, width=2, dash="dash"),
232
+ fillcolor="rgba(248, 249, 250, 0.1)"
233
+ )
234
+
235
+ # Red question mark
236
+ fig.add_annotation(
237
+ text="?",
238
+ x=0.5, y=0.6,
239
+ showarrow=False,
240
+ font=dict(size=60, color="#e74c3c", family="Arial Black, Arial, sans-serif")
241
+ )
242
+
243
+ # "Output Unknown" text
244
+ fig.add_annotation(
245
+ text="Output Unknown",
246
+ x=0.5, y=0.35,
247
+ showarrow=False,
248
+ font=dict(size=LARGE_FONT_SIZE, color=PLACEHOLDER_COLOR, family="Arial, sans-serif")
249
+ )
250
+
251
+ fig.update_layout(
252
+ title=dict(text="Output", font=dict(size=DEFAULT_FONT_SIZE, color=TITLE_COLOR)),
253
+ xaxis=dict(visible=False, range=[0, 1]),
254
+ yaxis=dict(visible=False, range=[0, 1]),
255
+ height=300,
256
+ width=300,
257
+ margin=FIGURE_MARGIN,
258
+ paper_bgcolor="white",
259
+ plot_bgcolor="white"
260
+ )
261
+
262
+ return fig
263
+
264
+ def update_subplot_layout(fig: go.Figure, total_subplots: int, cols: int):
265
+ """Update layout for all subplots in a figure."""
266
+ for i in range(1, total_subplots + 1):
267
+ row_idx = (i - 1) // cols + 1
268
+ col_idx = (i - 1) % cols + 1
269
+ fig.update_xaxes(visible=False, row=row_idx, col=col_idx)
270
+ fig.update_yaxes(visible=False, autorange="reversed", row=row_idx, col=col_idx)
271
+
272
+ def create_combined_figure(examples: List[Dict], section_title: str, example_type: str) -> go.Figure:
273
+ """Create a combined figure showing all examples in a section."""
274
+ if not examples:
275
+ return go.Figure()
276
+
277
+ # Calculate subplot layout
278
+ n_examples = len(examples)
279
+ total_subplots = n_examples * 2 # Each example has input + output
280
+
281
+ # Layout preference based on example type
282
+ cols = min(2 if example_type == "test" else 4, total_subplots)
283
+ rows = ((total_subplots - 1) // cols) + 1
284
+
285
+ # Create subplot titles
286
+ subplot_titles = []
287
+ for i, example in enumerate(examples):
288
+ subplot_titles.extend([
289
+ f"{example_type.title()} {i+1} - Input",
290
+ f"{example_type.title()} {i+1} - Output"
291
+ ])
292
+
293
+ fig = make_subplots(
294
+ rows=rows,
295
+ cols=cols,
296
+ subplot_titles=subplot_titles,
297
+ horizontal_spacing=SUBPLOT_HORIZONTAL_SPACING,
298
+ vertical_spacing=SUBPLOT_VERTICAL_SPACING
299
+ )
300
+
301
+ plot_idx = 1
302
+ for i, example in enumerate(examples):
303
+ row_idx = (plot_idx - 1) // cols + 1
304
+ col_idx = (plot_idx - 1) % cols + 1
305
+
306
+ # Add input subplot
307
+ input_grid = np.array(example['input']) if example['input'] else np.array([[]])
308
+ if input_grid.size > 0 and input_grid.ndim == 2:
309
+ fig.add_trace(create_heatmap_trace(input_grid), row=row_idx, col=col_idx)
310
+ add_grid_lines(fig, input_grid.shape, row_idx, col_idx)
311
+ plot_idx += 1
312
+
313
+ # Add output subplot
314
+ row_idx = (plot_idx - 1) // cols + 1
315
+ col_idx = (plot_idx - 1) % cols + 1
316
+
317
+ if 'output' in example and example['output']:
318
+ output_grid = np.array(example['output'])
319
+ fig.add_trace(create_heatmap_trace(output_grid), row=row_idx, col=col_idx)
320
+ add_grid_lines(fig, output_grid.shape, row_idx, col_idx)
321
+ else:
322
+ # Add placeholder for unknown output
323
+ fig.add_annotation(
324
+ text="❓<br>Unknown",
325
+ x=0.5, y=0.5,
326
+ showarrow=False,
327
+ font=dict(size=SMALL_FONT_SIZE, color=PLACEHOLDER_COLOR),
328
+ xref=f"x{plot_idx}",
329
+ yref=f"y{plot_idx}"
330
+ )
331
+ plot_idx += 1
332
+
333
+ # Update layout
334
+ height_per_row = HEIGHT_PER_ROW_TEST if example_type == "test" else HEIGHT_PER_ROW_TRAIN
335
+
336
+ fig.update_layout(
337
+ title=dict(
338
+ text=section_title,
339
+ font=dict(size=LARGE_FONT_SIZE, color=TITLE_COLOR),
340
+ x=0.5
341
+ ),
342
+ height=max(MIN_FIGURE_HEIGHT, rows * height_per_row),
343
+ margin=SUBPLOT_MARGIN,
344
+ paper_bgcolor="white",
345
+ plot_bgcolor="white"
346
+ )
347
+
348
+ update_subplot_layout(fig, plot_idx - 1, cols)
349
+ return fig
350
+
351
+ def format_puzzle_option(puzzle_id: str, puzzle_data: Dict) -> str:
352
+ """Format puzzle option for dropdown."""
353
+ train_count = len(puzzle_data.get('train', []))
354
+ test_count = len(puzzle_data.get('test', []))
355
+ return f"{puzzle_id} - {train_count} training, {test_count} test examples"
356
+
357
+ def parse_puzzle_id(puzzle_selection: str) -> str:
358
+ """Extract puzzle ID from dropdown selection."""
359
+ return puzzle_selection.split(' - ')[0] if puzzle_selection else ""
360
+
361
+ def calculate_puzzle_metadata(examples: List[Dict]) -> Tuple[int, List[str], List[str]]:
362
+ """Calculate metadata for puzzle examples."""
363
+ total_cells = 0
364
+ input_sizes = []
365
+ output_sizes = []
366
+
367
+ for example in examples:
368
+ if example.get('input'):
369
+ input_grid = example['input']
370
+ h, w = len(input_grid), len(input_grid[0]) if input_grid else 0
371
+ input_sizes.append(f"{h}Γ—{w}")
372
+ total_cells += h * w
373
+
374
+ if example.get('output'):
375
+ output_grid = example['output']
376
+ h, w = len(output_grid), len(output_grid[0]) if output_grid else 0
377
+ output_sizes.append(f"{h}Γ—{w}")
378
+ total_cells += h * w
379
+
380
+ return total_cells, input_sizes, output_sizes
381
+
382
+ def get_complexity_rating(max_cells: int) -> str:
383
+ """Get complexity rating based on maximum cells."""
384
+ if max_cells <= 25:
385
+ return "🟒 Simple"
386
+ elif max_cells <= 100:
387
+ return "🟑 Medium"
388
+ else:
389
+ return "πŸ”΄ Complex"
390
+
391
+ def get_puzzle_list() -> List[str]:
392
+ """Get list of available puzzles for dropdown."""
393
+ puzzles = load_puzzles()
394
+ if not puzzles:
395
+ return []
396
+
397
+ puzzle_options = [format_puzzle_option(pid, data) for pid, data in puzzles.items()]
398
+ return sorted(puzzle_options)
399
+
400
+ def display_puzzle_examples(puzzle_selection: str) -> Tuple[go.Figure, go.Figure, str]:
401
+ """Display all examples for a selected puzzle with interactive plots."""
402
+ if not puzzle_selection or puzzle_selection == "Select a puzzle...":
403
+ empty_fig = create_placeholder_figure("Select a puzzle to view its examples", height=300)
404
+ return empty_fig, empty_fig, "Select a puzzle to view its examples"
405
+
406
+ puzzle_id = parse_puzzle_id(puzzle_selection)
407
+ puzzles = load_puzzles()
408
+
409
+ if puzzle_id not in puzzles:
410
+ return go.Figure(), go.Figure(), "Puzzle not found"
411
+
412
+ puzzle = puzzles[puzzle_id]
413
+ train_examples = puzzle.get('train', [])
414
+ test_examples = puzzle.get('test', [])
415
+
416
+ # Calculate puzzle metadata
417
+ all_examples = train_examples + test_examples
418
+ total_cells, input_sizes, output_sizes = calculate_puzzle_metadata(all_examples)
419
+
420
+ # Find unique grid sizes and complexity
421
+ all_sizes = input_sizes + output_sizes
422
+ unique_sizes = list(set(all_sizes))
423
+
424
+ info_text = f"**🎯 Puzzle ID:** `{puzzle_id}`\n\n"
425
+ info_text += f"**πŸ“Š Structure:**\n"
426
+ info_text += f"β€’ Training Examples: {len(train_examples)}\n"
427
+ info_text += f"β€’ Test Examples: {len(test_examples)}\n"
428
+ info_text += f"β€’ Total Grids: {len(train_examples) * 2 + len(test_examples)}\n"
429
+ info_text += f"β€’ Total Cells: {total_cells:,}\n\n"
430
+
431
+ if unique_sizes:
432
+ info_text += f"**πŸ“ Grid Dimensions:**\n"
433
+ sorted_sizes = sorted(unique_sizes, key=lambda x: int(x.split('Γ—')[0]) * int(x.split('Γ—')[1]))
434
+ info_text += f"β€’ Sizes Found: {', '.join(sorted_sizes)}\n"
435
+
436
+ # Calculate complexity
437
+ max_cells = max([int(size.split('Γ—')[0]) * int(size.split('Γ—')[1]) for size in unique_sizes])
438
+ complexity = get_complexity_rating(max_cells)
439
+ info_text += f"β€’ Complexity: {complexity} (max {max_cells} cells)\n\n"
440
+
441
+ info_text += "πŸ’‘ **Tip:** Hover over grid cells to see their coordinates and values!"
442
+
443
+ # Create combined figures
444
+ train_fig = create_combined_figure(train_examples, "πŸ“š Training Examples", "train") if train_examples else go.Figure()
445
+ test_fig = create_combined_figure(test_examples, "πŸ§ͺ Test Examples", "test") if test_examples else go.Figure()
446
+
447
+ return train_fig, test_fig, info_text
448
+
449
+ def create_interface() -> gr.Blocks:
450
+ """Create the Gradio interface."""
451
+ puzzle_options = get_puzzle_list()
452
+
453
+ with gr.Blocks(
454
+ title="🧩 ARC-AGI Interactive Puzzle Viewer",
455
+ theme=gr.themes.Soft(),
456
+ css=CSS_STYLES
457
+ ) as interface:
458
+
459
+ gr.HTML(HEADER_HTML)
460
+
461
+ with gr.Row():
462
+ with gr.Column(scale=1):
463
+ puzzle_dropdown = gr.Dropdown(
464
+ choices=["Select a puzzle..."] + puzzle_options,
465
+ value="Select a puzzle...",
466
+ label="🎯 Select a Puzzle",
467
+ info=f"Choose from {len(puzzle_options)} available puzzles"
468
+ )
469
+
470
+ puzzle_info = gr.Markdown(
471
+ value="Select a puzzle to view its details and examples.",
472
+ label="πŸ“Š Puzzle Information"
473
+ )
474
+
475
+ with gr.Column(scale=2):
476
+ train_plot = gr.Plot(
477
+ label="πŸ“š Training Examples",
478
+ container=True
479
+ )
480
+
481
+ test_plot = gr.Plot(
482
+ label="πŸ§ͺ Test Examples",
483
+ container=True
484
+ )
485
+
486
+ # Set up the callback
487
+ puzzle_dropdown.change(
488
+ fn=display_puzzle_examples,
489
+ inputs=[puzzle_dropdown],
490
+ outputs=[train_plot, test_plot, puzzle_info]
491
+ )
492
+
493
+ return interface
494
+
495
+ def main():
496
+ """Main function to run the Gradio app."""
497
+ print("πŸš€ Starting ARC-AGI Interactive Puzzle Viewer...")
498
+ print("πŸ“ Dataset location: arc-prize-2025-dataset/")
499
+
500
+ # Pre-load puzzles
501
+ puzzles = load_puzzles()
502
+ print(f"βœ… Ready with {len(puzzles)} puzzles!")
503
+
504
+ # Create and launch interface
505
+ interface = create_interface()
506
+
507
+ print("🌐 Launching Gradio interface...")
508
+ interface.launch(
509
+ server_name="0.0.0.0",
510
+ server_port=7860,
511
+ show_error=True,
512
+ share=False
513
+ )
514
+
515
+ if __name__ == "__main__":
516
+ main()