File size: 7,373 Bytes
a32ce1a
 
 
 
acdd1bb
a32ce1a
acdd1bb
a32ce1a
 
 
 
 
0df47bb
a32ce1a
 
 
 
 
 
0df47bb
 
 
a32ce1a
0df47bb
 
 
a32ce1a
49adc3e
acdd1bb
 
a32ce1a
 
acdd1bb
 
49adc3e
acdd1bb
 
49adc3e
 
 
acdd1bb
49adc3e
 
 
 
 
 
 
 
a32ce1a
 
acdd1bb
a32ce1a
 
 
fc56a10
a32ce1a
 
 
 
acdd1bb
a32ce1a
acdd1bb
a32ce1a
 
49adc3e
a32ce1a
 
acdd1bb
 
 
 
49adc3e
acdd1bb
49adc3e
 
 
 
 
 
 
 
 
 
 
acdd1bb
40d4f0c
49adc3e
acdd1bb
 
 
 
 
 
 
 
 
 
 
 
40d4f0c
 
 
49adc3e
acdd1bb
0df47bb
49adc3e
 
0df47bb
acdd1bb
 
 
 
 
 
49adc3e
acdd1bb
49adc3e
 
 
 
acdd1bb
49adc3e
acdd1bb
 
 
49adc3e
acdd1bb
49adc3e
 
acdd1bb
49adc3e
acdd1bb
49adc3e
acdd1bb
 
 
 
 
 
 
 
 
 
 
 
 
49adc3e
 
 
acdd1bb
f1e7496
acdd1bb
 
 
 
 
 
 
 
49adc3e
acdd1bb
 
82f0837
acdd1bb
 
 
 
 
 
 
 
 
 
 
 
 
 
a32ce1a
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
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('<div class="center-html">=</div>', 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()