damla921 commited on
Commit
9908e01
·
verified ·
1 Parent(s): 8de1c5c

Upload 3 files

Browse files
Files changed (3) hide show
  1. README.md +28 -0
  2. app.py +288 -0
  3. requirements.txt +2 -0
README.md ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 3×3 Rubik's‑Style Color Password System (Gradio)
2
+
3
+ A Hugging Face Spaces‑ready simulator. Click tiles to cycle colors in this strict order:
4
+
5
+ **Red → Yellow → Green → Blue → White → Orange → (repeat)**
6
+
7
+ Each of the 6 sides has a fixed center color (its "middle"). You can save a custom code (the full 3×3 pattern) per side, shuffle tiles, and try to unlock by recreating the saved pattern.
8
+
9
+ ## Files
10
+ - `app.py` – the Gradio app.
11
+ - `requirements.txt` – dependencies.
12
+
13
+ ## How to deploy on Hugging Face
14
+ 1. Go to **Hugging Face → New Space → Static: Gradio** (Python).
15
+ 2. Give it a name, keep defaults.
16
+ 3. Upload both files (`app.py` and `requirements.txt`) to the Space.
17
+ 4. Wait for it to build. When it’s ready, open the Space.
18
+
19
+ ## How to use
20
+ 1. Pick a **Side**. Its center tile is locked to the stated middle color.
21
+ 2. Click **🔀 Randomize** to shuffle the 8 non-center tiles.
22
+ 3. Arrange tiles by **clicking them** (each click cycles the color).
23
+ 4. Press **💾 Set Code** to save the current pattern for this side.
24
+ 5. Shuffle again and try to reproduce the code; hit **🔓 Unlock** to check.
25
+ 6. Use **Show Code Preview** if you want a small peek at the saved code.
26
+ 7. **♻️ Reset Side** or **🧹 Reset All** if needed.
27
+
28
+ Enjoy!
app.py ADDED
@@ -0,0 +1,288 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # app.py
2
+ # 3x3 Rubik's-style Color Password System Simulator
3
+ # Hugging Face Spaces ready (Gradio)
4
+ #
5
+ # How it works (quick start):
6
+ # 1) Choose a side (each has a fixed center color).
7
+ # 2) Click "Randomize" to shuffle the 8 non-center tiles.
8
+ # 3) Arrange the tiles by clicking them. Each click cycles color in this exact order:
9
+ # Red → Yellow → Green → Blue → White → Orange → (repeat)
10
+ # (Center tile is locked to the side's middle color.)
11
+ # 4) Click "Set Code" to save the current pattern as the password for that side.
12
+ # 5) Click "Randomize" again (or leave as-is), then try to re-create the saved pattern.
13
+ # 6) Click "Unlock" to check your attempt. Success will be announced.
14
+ #
15
+ # Notes:
16
+ # - Each of the 6 sides has its own center color and its own saved code.
17
+ # - "Show Code" lets you peek at the saved code preview for the selected side.
18
+ # - "Reset Side" resets only the selected side (grid and saved code).
19
+ # - "Reset All" resets everything.
20
+ #
21
+ # Made for users with zero coding experience—just upload these files
22
+ # to a Hugging Face Space (Python/Gradio), and it will run.
23
+
24
+ import gradio as gr
25
+ from PIL import Image, ImageDraw
26
+ import random
27
+
28
+ # ----- Color model -----
29
+ COLOR_ORDER = ["Red", "Yellow", "Green", "Blue", "White", "Orange"]
30
+ COLOR_HEX = {
31
+ "Red": "#e53935",
32
+ "Yellow": "#fdd835",
33
+ "Green": "#43a047",
34
+ "Blue": "#1e88e5",
35
+ "White": "#fafafa",
36
+ "Orange": "#fb8c00",
37
+ }
38
+
39
+ # Six sides with fixed middle colors (index 4 in a 0..8 grid)
40
+ SIDES = {
41
+ "Side 1 (Red middle)": "Red",
42
+ "Side 2 (Green middle)": "Green",
43
+ "Side 3 (Orange middle)": "Orange",
44
+ "Side 4 (Blue middle)": "Blue",
45
+ "Side 5 (White middle)": "White",
46
+ "Side 6 (Yellow middle)": "Yellow",
47
+ }
48
+ SIDE_NAMES = list(SIDES.keys())
49
+
50
+ TILE_SIZE = 120 # px
51
+ GRID_SIZE = 3
52
+ IMG_SIZE = TILE_SIZE * GRID_SIZE
53
+
54
+ def new_grid(center_color: str):
55
+ """Create a new 3x3 grid with the center locked to center_color and others random."""
56
+ grid = [random.choice(COLOR_ORDER) for _ in range(9)]
57
+ grid[4] = center_color
58
+ return grid
59
+
60
+ def render_grid(grid):
61
+ """Return a PIL image of the 3x3 grid."""
62
+ img = Image.new("RGB", (IMG_SIZE, IMG_SIZE), color=(30, 30, 30))
63
+ draw = ImageDraw.Draw(img)
64
+ for i, color_name in enumerate(grid):
65
+ r = i // GRID_SIZE
66
+ c = i % GRID_SIZE
67
+ x0 = c * TILE_SIZE + 2
68
+ y0 = r * TILE_SIZE + 2
69
+ x1 = (c+1) * TILE_SIZE - 2
70
+ y1 = (r+1) * TILE_SIZE - 2
71
+ fill = COLOR_HEX[color_name]
72
+ draw.rectangle([x0, y0, x1, y1], fill=fill, outline="#111111", width=4)
73
+ # subtle "bevel" lines
74
+ draw.line([x0, y0, x1, y0], fill="#000000", width=3)
75
+ draw.line([x0, y0, x0, y1], fill="#000000", width=3)
76
+ return img
77
+
78
+ def grid_image_bytes(grid):
79
+ return render_grid(grid)
80
+
81
+ def cycle_color(color_name):
82
+ idx = COLOR_ORDER.index(color_name)
83
+ return COLOR_ORDER[(idx + 1) % len(COLOR_ORDER)]
84
+
85
+ # ----- App State -----
86
+ # We keep per-side state: current grid + saved code (or None)
87
+ def init_state():
88
+ state = {}
89
+ for side, center in SIDES.items():
90
+ state[side] = {
91
+ "center": center,
92
+ "grid": new_grid(center),
93
+ "code": None, # saved pattern (list of 9 color names) or None
94
+ "unlocked": False,
95
+ }
96
+ return state
97
+
98
+ # ----- Helpers for events -----
99
+ def side_to_image(state, side_name):
100
+ return grid_image_bytes(state[side_name]["grid"])
101
+
102
+ def randomize_side(state, side_name):
103
+ center = state[side_name]["center"]
104
+ grid = state[side_name]["grid"]
105
+ # randomize non-center tiles only
106
+ for i in range(9):
107
+ if i == 4:
108
+ grid[i] = center
109
+ else:
110
+ grid[i] = random.choice(COLOR_ORDER)
111
+ state[side_name]["unlocked"] = False
112
+ return state, side_to_image(state, side_name), status_text(state, side_name), code_preview(state, side_name)
113
+
114
+ def set_code(state, side_name):
115
+ # Save current grid as the code
116
+ state[side_name]["code"] = list(state[side_name]["grid"])
117
+ state[side_name]["unlocked"] = False
118
+ return state, "Code saved for this side.", code_preview(state, side_name)
119
+
120
+ def unlock(state, side_name):
121
+ target = state[side_name]["code"]
122
+ if target is None:
123
+ return state, "No code saved yet for this side.", code_preview(state, side_name)
124
+ if state[side_name]["grid"] == target:
125
+ state[side_name]["unlocked"] = True
126
+ return state, "✅ Unlocked! Pattern matches the saved code.", code_preview(state, side_name)
127
+ else:
128
+ state[side_name]["unlocked"] = False
129
+ return state, "❌ Not yet. Keep trying!", code_preview(state, side_name)
130
+
131
+ def status_text(state, side_name):
132
+ u = state[side_name]["unlocked"]
133
+ code = state[side_name]["code"]
134
+ if u:
135
+ return "Status: ✅ Unlocked"
136
+ if code is None:
137
+ return "Status: No code saved"
138
+ return "Status: Locked (code saved, try to match & click Unlock)"
139
+
140
+ def code_preview(state, side_name):
141
+ """Return a small preview image for the saved code, or None if not set."""
142
+ code = state[side_name]["code"]
143
+ if code is None:
144
+ return None
145
+ # Tiny rendering
146
+ prev_tile = 40
147
+ size = prev_tile * GRID_SIZE
148
+ img = Image.new("RGB", (size, size), color=(30,30,30))
149
+ draw = ImageDraw.Draw(img)
150
+ for i, color_name in enumerate(code):
151
+ r = i // GRID_SIZE
152
+ c = i % GRID_SIZE
153
+ x0 = c * prev_tile + 2
154
+ y0 = r * prev_tile + 2
155
+ x1 = (c+1) * prev_tile - 2
156
+ y1 = (r+1) * prev_tile - 2
157
+ fill = COLOR_HEX[color_name]
158
+ draw.rectangle([x0, y0, x1, y1], fill=fill, outline="#111111", width=2)
159
+ return img
160
+
161
+ def reset_side(state, side_name):
162
+ center = state[side_name]["center"]
163
+ state[side_name] = {
164
+ "center": center,
165
+ "grid": new_grid(center),
166
+ "code": None,
167
+ "unlocked": False,
168
+ }
169
+ return state, side_to_image(state, side_name), status_text(state, side_name), None
170
+
171
+ def reset_all(state):
172
+ return init_state()
173
+
174
+ # Handle tile clicks on the image: gr.Image.select gives (x, y)
175
+ def on_click(state, side_name, evt: gr.SelectData):
176
+ # Determine tile from coordinates
177
+ x, y = evt.index[0], evt.index[1]
178
+ col = min(int(x // TILE_SIZE), GRID_SIZE - 1)
179
+ row = min(int(y // TILE_SIZE), GRID_SIZE - 1)
180
+ idx = row * GRID_SIZE + col
181
+ # Center is locked
182
+ if idx == 4:
183
+ return state, side_to_image(state, side_name)
184
+ # cycle color
185
+ grid = state[side_name]["grid"]
186
+ grid[idx] = cycle_color(grid[idx])
187
+ state[side_name]["unlocked"] = False
188
+ return state, side_to_image(state, side_name)
189
+
190
+ # ----- Build UI -----
191
+ with gr.Blocks(title="3x3 Rubik's-Style Color Password") as demo:
192
+ gr.Markdown(
193
+ """
194
+ # 3×3 Rubik's‑Style Color Password System
195
+ **Click tiles to cycle colors:** Red → Yellow → Green → Blue → White → Orange → (repeat).
196
+ The center tile is locked to the side's middle color.
197
+ """
198
+ )
199
+
200
+ app_state = gr.State(init_state())
201
+
202
+ with gr.Row():
203
+ side_dropdown = gr.Dropdown(choices=SIDE_NAMES, value=SIDE_NAMES[0], label="Choose Side")
204
+
205
+ with gr.Row():
206
+ grid_image = gr.Image(type="pil", label="Current Grid", height=IMG_SIZE, width=IMG_SIZE, interactive=True)
207
+ with gr.Column():
208
+ status = gr.Markdown("Status: No code saved")
209
+ with gr.Row():
210
+ btn_random = gr.Button("🔀 Randomize")
211
+ btn_set = gr.Button("💾 Set Code")
212
+ with gr.Row():
213
+ btn_unlock = gr.Button("🔓 Unlock")
214
+ btn_reset_side = gr.Button("♻️ Reset Side")
215
+ with gr.Row():
216
+ btn_reset_all = gr.Button("🧹 Reset All (All Sides)")
217
+ show_code = gr.Checkbox(label="Show Code Preview", value=True)
218
+ code_image = gr.Image(type="pil", label="Saved Code (Preview)", height=120, width=120, interactive=False)
219
+
220
+ def refresh_side(state, side_name, show_code_flag):
221
+ # update main image, status, and code preview
222
+ return (
223
+ side_to_image(state, side_name),
224
+ status_text(state, side_name),
225
+ code_preview(state, side_name) if show_code_flag else None,
226
+ )
227
+
228
+ side_dropdown.change(
229
+ refresh_side,
230
+ [app_state, side_dropdown, show_code],
231
+ [grid_image, status, code_image],
232
+ )
233
+
234
+ show_code.change(
235
+ lambda state, side, flag: code_preview(state, side) if flag else None,
236
+ [app_state, side_dropdown, show_code],
237
+ [code_image],
238
+ )
239
+
240
+ btn_random.click(
241
+ randomize_side,
242
+ [app_state, side_dropdown],
243
+ [app_state, grid_image, status, code_image],
244
+ )
245
+
246
+ btn_set.click(
247
+ set_code,
248
+ [app_state, side_dropdown],
249
+ [app_state, gr.Textbox(visible=False), code_image], # hidden toast text placeholder
250
+ )
251
+
252
+ btn_unlock.click(
253
+ unlock,
254
+ [app_state, side_dropdown],
255
+ [app_state, status, code_image],
256
+ )
257
+
258
+ btn_reset_side.click(
259
+ reset_side,
260
+ [app_state, side_dropdown],
261
+ [app_state, grid_image, status, code_image],
262
+ )
263
+
264
+ btn_reset_all.click(
265
+ lambda state: init_state(),
266
+ [app_state],
267
+ [app_state],
268
+ ).then(
269
+ refresh_side,
270
+ [app_state, side_dropdown, show_code],
271
+ [grid_image, status, code_image],
272
+ )
273
+
274
+ grid_image.select(
275
+ on_click,
276
+ [app_state, side_dropdown],
277
+ [app_state, grid_image],
278
+ )
279
+
280
+ # Initialize the first view
281
+ demo.load(
282
+ refresh_side,
283
+ [app_state, side_dropdown, show_code],
284
+ [grid_image, status, code_image],
285
+ )
286
+
287
+ if __name__ == "__main__":
288
+ demo.launch()
requirements.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ gradio>=4.44.0
2
+ Pillow>=10.0.0