import gradio as gr from itertools import permutations # ========================================== # 1. SOLVER LOGIC # ========================================== # (Standard logic, same as before) def apply_op(a, op, b): if op == '+': return a + b if op == '-': return a - b if op == '×': return a * b if op == '÷': if b == 0 or a % b != 0: return None return a // b return None def evaluate_line(n1, op1, n2, op2, n3): high_precedence = {'×', '÷'} if op2 in high_precedence and op1 not in high_precedence: right = apply_op(n2, op2, n3) if right is None: return None return apply_op(n1, op1, right) else: left = apply_op(n1, op1, n2) if left is None: return None return apply_op(left, op2, n3) def solve_puzzle(pool_str, *args): # args contains all the grid inputs in the specific order we passed them # Unpack based on the specific structure of the inputs list constructed below try: pool = [int(x.strip()) for x in pool_str.split(',')] if len(pool) != 9: return [""] * 9 except ValueError: return [""] * 9 # Unpack args. The order matches the 'inputs' list in the UI section # Rows: 1, 2, 3 r1 = [args[0], args[1], int(args[2])] r2 = [args[3], args[4], int(args[5])] r3 = [args[6], args[7], int(args[8])] # Cols: 1, 2, 3 (Top Ops) & 4, 5, 6 (Bottom Ops) & Targets c1 = [args[9], args[12], int(args[15])] c2 = [args[10], args[13], int(args[16])] c3 = [args[11], args[14], int(args[17])] row_ops = [[r1[0], r1[1]], [r2[0], r2[1]], [r3[0], r3[1]]] col_ops = [[c1[0], c1[1]], [c2[0], c2[1]], [c3[0], c3[1]]] row_targets = [r1[2], r2[2], r3[2]] col_targets = [c1[2], c2[2], c3[2]] for p in permutations(pool): # Checks if evaluate_line(p[0], row_ops[0][0], p[1], row_ops[0][1], p[2]) != row_targets[0]: continue if evaluate_line(p[3], row_ops[1][0], p[4], row_ops[1][1], p[5]) != row_targets[1]: continue if evaluate_line(p[6], row_ops[2][0], p[7], row_ops[2][1], p[8]) != row_targets[2]: continue if evaluate_line(p[0], col_ops[0][0], p[3], col_ops[0][1], p[6]) != col_targets[0]: continue if evaluate_line(p[1], col_ops[1][0], p[4], col_ops[1][1], p[7]) != col_targets[1]: continue if evaluate_line(p[2], col_ops[2][0], p[5], col_ops[2][1], p[8]) != col_targets[2]: continue return [str(x) for x in p] return ["?"] * 9 # ========================================== # 2. GRID CONFIGURATION # ========================================== # We define the grid semantically: # "SOL" = Solution Box (Non-editable output) # "OP" = Operator (Dropdown input) # "TGT" = Target (Editable input) # "EQ" = Equals Sign # "SPC" = Spacer (Empty) GRID_LAYOUT = [ ["SOL", "OP", "SOL", "OP", "SOL", "EQ", "TGT"], # Row 0 ["OP", "SPC", "OP", "SPC", "OP", "SPC", "SPC"], # Row 1 ["SOL", "OP", "SOL", "OP", "SOL", "EQ", "TGT"], # Row 2 ["OP", "SPC", "OP", "SPC", "OP", "SPC", "SPC"], # Row 3 ["SOL", "OP", "SOL", "OP", "SOL", "EQ", "TGT"], # Row 4 ["EQ", "SPC", "EQ", "SPC", "EQ", "SPC", "SPC"], # Row 5 ["TGT", "SPC", "TGT", "SPC", "TGT", "SPC", "SPC"] # Row 6 ] # CSS to make the grid look tight and clean css = """ .tight-row { gap: 5px !important; margin-bottom: 5px; } .sol-box textarea { background-color: #6366f1 !important; color: white !important; font-size: 20px !important; text-align: center !important; font-weight: bold; } .tgt-box textarea { border: 2px solid #6366f1 !important; font-size: 18px !important; text-align: center !important; font-weight: bold; } .center-html { display: flex; justify-content: center; align-items: center; font-size: 24px; font-weight: bold; height: 100%; color: #94a3b8; } """ with gr.Blocks(css=css, theme=gr.themes.Soft()) as demo: gr.Markdown("## 🧩 Programmatic Grid Solver") with gr.Row(): pool_input = gr.Textbox(label="Number Pool", value="7, 14, 4, 210, 70, 4, 49, 81, 13") solve_btn = gr.Button("🚀 Solve", variant="primary") # This list will store our generated component objects so we can access them later # to extract inputs or update outputs. grid_refs = [[None for _ in range(7)] for _ in range(7)] # We also keep a flat list of just the Solution boxes to easily map outputs solution_outputs = [] # --- THE BUILDER LOOP --- for r, row_config in enumerate(GRID_LAYOUT): with gr.Row(equal_height=True, elem_classes="tight-row"): for c, type_code in enumerate(row_config): # 1. Solution Box (Output) if type_code == "SOL": comp = gr.Textbox(interactive=False, show_label=False, elem_classes="sol-box", scale=1) solution_outputs.append(comp) # Store for output mapping grid_refs[r][c] = comp # 2. Operator (Input) elif type_code == "OP": comp = gr.Dropdown(["+", "-", "×", "÷"], value="+", container=False, scale=0.6, min_width=50) grid_refs[r][c] = comp # 3. Target (Input) elif type_code == "TGT": # Default values for demo purposes based on position def_val = "0" if r==0: def_val="227" elif r==2: def_val="20" elif r==4: def_val="74" elif r==6 and c==0: def_val="90" elif r==6 and c==2: def_val="147" elif r==6 and c==4: def_val="49" comp = gr.Textbox(value=def_val, show_label=False, container=False, elem_classes="tgt-box", scale=1) grid_refs[r][c] = comp # 4. Static Elements elif type_code == "EQ": gr.HTML('
=
', scale=0.3) elif type_code == "SPC": gr.HTML('', scale=1) # Empty Spacer # --- WIRING THE INPUTS --- # Now we need to explicitly gather the inputs in the order the solver expects. # We access them using the grid_refs matrix we populated in the loop. solver_inputs = [pool_input] # Row 1 Inputs (Op1, Op2, Target) -> Grid Coords: (0,1), (0,3), (0,6) solver_inputs.extend([grid_refs[0][1], grid_refs[0][3], grid_refs[0][6]]) # Row 2 Inputs -> Grid Coords: (2,1), (2,3), (2,6) solver_inputs.extend([grid_refs[2][1], grid_refs[2][3], grid_refs[2][6]]) # Row 3 Inputs -> Grid Coords: (4,1), (4,3), (4,6) solver_inputs.extend([grid_refs[4][1], grid_refs[4][3], grid_refs[4][6]]) # Col Ops Top -> Grid Coords: (1,0), (1,2), (1,4) solver_inputs.extend([grid_refs[1][0], grid_refs[1][2], grid_refs[1][4]]) # Col Ops Bottom -> Grid Coords: (3,0), (3,2), (3,4) solver_inputs.extend([grid_refs[3][0], grid_refs[3][2], grid_refs[3][4]]) # Col Targets -> Grid Coords: (6,0), (6,2), (6,4) solver_inputs.extend([grid_refs[6][0], grid_refs[6][2], grid_refs[6][4]]) # Execute solve_btn.click(fn=solve_puzzle, inputs=solver_inputs, outputs=solution_outputs) if __name__ == "__main__": demo.launch()