aartstudio commited on
Commit
424ae4c
·
verified ·
1 Parent(s): fd75788

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +279 -0
  2. requirements.txt +2 -0
app.py ADDED
@@ -0,0 +1,279 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # VARK Simple Parking Grid Demo
2
+ # Paste this file as app.py in a Hugging Face Space (Gradio SDK)
3
+
4
+ import time
5
+ from dataclasses import dataclass, field
6
+ from typing import Dict, List, Optional, Tuple
7
+
8
+ import gradio as gr
9
+ import matplotlib.pyplot as plt
10
+ import matplotlib.patches as patches
11
+
12
+ # -----------------------------
13
+ # Config
14
+ # -----------------------------
15
+ ROWS = 4
16
+ COLS = 5
17
+ PLATFORM_COUNT = 16
18
+ DROP_POINT = (0, 0) # row, col
19
+ STEP_DELAY = 0.08
20
+
21
+ # -----------------------------
22
+ # Data models
23
+ # -----------------------------
24
+ @dataclass
25
+ class Platform:
26
+ pid: int
27
+ r: int
28
+ c: int
29
+ car_id: Optional[int] = None
30
+ home: Tuple[int, int] = (0, 0)
31
+
32
+ @dataclass
33
+ class State:
34
+ platforms: Dict[int, Platform] = field(default_factory=dict)
35
+ occupancy: Dict[Tuple[int, int], Optional[int]] = field(default_factory=dict)
36
+ cars: Dict[int, int] = field(default_factory=dict) # car_id -> platform_id
37
+ log: List[str] = field(default_factory=list)
38
+
39
+ # -----------------------------
40
+ # Helpers
41
+ # -----------------------------
42
+ def in_bounds(r, c):
43
+ return 0 <= r < ROWS and 0 <= c < COLS
44
+
45
+ def manhattan(a, b):
46
+ return abs(a[0] - b[0]) + abs(a[1] - b[1])
47
+
48
+ # -----------------------------
49
+ # Init
50
+ # -----------------------------
51
+ def init_state():
52
+ st = State()
53
+
54
+ # four empty cells
55
+ empty = {(0, 4), (1, 2), (3, 0), (3, 4)}
56
+
57
+ for r in range(ROWS):
58
+ for c in range(COLS):
59
+ st.occupancy[(r, c)] = None
60
+
61
+ pid = 1
62
+ for r in range(ROWS):
63
+ for c in range(COLS):
64
+ if (r, c) in empty:
65
+ continue
66
+ if pid > PLATFORM_COUNT:
67
+ continue
68
+ p = Platform(pid=pid, r=r, c=c, home=(r, c))
69
+ st.platforms[pid] = p
70
+ st.occupancy[(r, c)] = pid
71
+ pid += 1
72
+
73
+ st.log.append("System initialised: 4x5 grid, 16 platforms, 4 empty cells")
74
+ st.log.append(f"Drop / Pick point at {DROP_POINT}")
75
+ return st
76
+
77
+ # -----------------------------
78
+ # Rendering
79
+ # -----------------------------
80
+ def render(st):
81
+ fig, ax = plt.subplots(figsize=(7, 5))
82
+
83
+ for r in range(ROWS):
84
+ for c in range(COLS):
85
+ ax.add_patch(patches.Rectangle((c, ROWS - 1 - r), 1, 1, fill=False))
86
+
87
+ dr, dc = DROP_POINT
88
+ ax.add_patch(patches.Rectangle((dc, ROWS - 1 - dr), 1, 1, fill=False, linewidth=3))
89
+ ax.text(dc + 0.5, ROWS - dr - 0.15, "DROP / PICK", ha="center", va="top", fontsize=9)
90
+
91
+ for p in st.platforms.values():
92
+ label = f"P{p.pid}"
93
+ if p.car_id is not None:
94
+ label += f"\nCar {p.car_id}"
95
+ ax.text(p.c + 0.5, ROWS - 1 - p.r + 0.5, label, ha="center", va="center")
96
+
97
+ ax.set_xlim(0, COLS)
98
+ ax.set_ylim(0, ROWS)
99
+ ax.set_aspect("equal")
100
+ ax.axis("off")
101
+ return fig
102
+
103
+ # -----------------------------
104
+ # Movement logic (4-direction only)
105
+ # -----------------------------
106
+ def step_towards(src, dst):
107
+ r, c = src
108
+ tr, tc = dst
109
+ if r < tr:
110
+ return r + 1, c
111
+ if r > tr:
112
+ return r - 1, c
113
+ if c < tc:
114
+ return r, c + 1
115
+ if c > tc:
116
+ return r, c - 1
117
+ return r, c
118
+
119
+
120
+ def move_one(st, pid, target):
121
+ p = st.platforms[pid]
122
+ cur = (p.r, p.c)
123
+ if not in_bounds(*target):
124
+ return
125
+
126
+ occ = st.occupancy[target]
127
+ if occ is None:
128
+ st.occupancy[cur] = None
129
+ p.r, p.c = target
130
+ st.occupancy[target] = pid
131
+ else:
132
+ other = st.platforms[occ]
133
+ p.r, other.r = other.r, p.r
134
+ p.c, other.c = other.c, p.c
135
+ st.occupancy[(p.r, p.c)] = pid
136
+ st.occupancy[(other.r, other.c)] = occ
137
+
138
+
139
+ def animate_move(st, pid, dst):
140
+ p = st.platforms[pid]
141
+ while (p.r, p.c) != dst:
142
+ nxt = step_towards((p.r, p.c), dst)
143
+ move_one(st, pid, nxt)
144
+ yield st
145
+ time.sleep(STEP_DELAY)
146
+
147
+ # -----------------------------
148
+ # Business logic
149
+ # -----------------------------
150
+ def free_platform(st):
151
+ free = [p for p in st.platforms.values() if p.car_id is None]
152
+ if not free:
153
+ return None
154
+ free.sort(key=lambda p: manhattan((p.r, p.c), DROP_POINT))
155
+ return free[0].pid
156
+
157
+
158
+ def drop_off(st, car_id):
159
+ if car_id in st.cars:
160
+ st.log.append(f"Car {car_id} already parked")
161
+ yield st
162
+ return
163
+
164
+ if len(st.cars) >= PLATFORM_COUNT:
165
+ st.log.append("Garage full (16 cars)")
166
+ yield st
167
+ return
168
+
169
+ pid = free_platform(st)
170
+ if pid is None:
171
+ st.log.append("No empty platform available")
172
+ yield st
173
+ return
174
+
175
+ st.log.append(f"Dispatch P{pid} to DROP for Car {car_id}")
176
+ for _ in animate_move(st, pid, DROP_POINT):
177
+ yield st
178
+
179
+ st.platforms[pid].car_id = car_id
180
+ st.cars[car_id] = pid
181
+ st.log.append(f"Car {car_id} loaded onto P{pid}")
182
+
183
+ home = st.platforms[pid].home
184
+ for _ in animate_move(st, pid, home):
185
+ yield st
186
+
187
+ st.log.append(f"Car {car_id} stored")
188
+ yield st
189
+
190
+
191
+ def pick_up(st, car_id):
192
+ if car_id not in st.cars:
193
+ st.log.append(f"Car {car_id} not found")
194
+ yield st
195
+ return
196
+
197
+ pid = st.cars[car_id]
198
+ st.log.append(f"Dispatch P{pid} for PICK UP of Car {car_id}")
199
+
200
+ for _ in animate_move(st, pid, DROP_POINT):
201
+ yield st
202
+
203
+ st.platforms[pid].car_id = None
204
+ del st.cars[car_id]
205
+ st.log.append(f"Car {car_id} unloaded")
206
+
207
+ home = st.platforms[pid].home
208
+ for _ in animate_move(st, pid, home):
209
+ yield st
210
+
211
+ st.log.append(f"P{pid} returned to grid")
212
+ yield st
213
+
214
+ # -----------------------------
215
+ # UI handlers
216
+ # -----------------------------
217
+ def reset_ui():
218
+ st = init_state()
219
+ return st, render(st), "\n".join(st.log), f"{len(st.cars)} / 16"
220
+
221
+
222
+ def ui_drop(st, car):
223
+ try:
224
+ cid = int(car)
225
+ except:
226
+ st.log.append("Invalid car ID")
227
+ yield st, render(st), "\n".join(st.log), f"{len(st.cars)} / 16"
228
+ return
229
+
230
+ for s in drop_off(st, cid):
231
+ yield s, render(s), "\n".join(s.log[-12:]), f"{len(s.cars)} / 16"
232
+
233
+
234
+ def ui_pick(st, car):
235
+ try:
236
+ cid = int(car)
237
+ except:
238
+ st.log.append("Invalid car ID")
239
+ yield st, render(st), "\n".join(st.log), f"{len(st.cars)} / 16"
240
+ return
241
+
242
+ for s in pick_up(st, cid):
243
+ yield s, render(s), "\n".join(s.log[-12:]), f"{len(s.cars)} / 16"
244
+
245
+ # -----------------------------
246
+ # Gradio App
247
+ # -----------------------------
248
+ with gr.Blocks(title="VARK Parking Grid Demo") as demo:
249
+ state = gr.State(init_state())
250
+
251
+ gr.Markdown("""
252
+ 4x5 grid parking system demo
253
+
254
+ - 16 movable platforms
255
+ - 4 empty cells
256
+ - Platforms move only up / down / left / right
257
+ - DROP OFF brings an empty platform to the drop point
258
+ - PICK UP retrieves a car by ID
259
+ """)
260
+
261
+ car_id = gr.Textbox(label="Car ID", value="101")
262
+ capacity = gr.Textbox(label="Capacity", value="0 / 16", interactive=False)
263
+
264
+ with gr.Row():
265
+ drop_btn = gr.Button("DROP OFF")
266
+ pick_btn = gr.Button("PICK UP")
267
+ reset_btn = gr.Button("RESET")
268
+
269
+ plot = gr.Plot()
270
+ log = gr.Textbox(lines=14, interactive=False)
271
+
272
+ plot.value = render(state.value)
273
+ log.value = "\n".join(state.value.log)
274
+
275
+ reset_btn.click(reset_ui, outputs=[state, plot, log, capacity])
276
+ drop_btn.click(ui_drop, inputs=[state, car_id], outputs=[state, plot, log, capacity])
277
+ pick_btn.click(ui_pick, inputs=[state, car_id], outputs=[state, plot, log, capacity])
278
+
279
+ demo.queue().launch()
requirements.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ gradio>=4.0.0
2
+ matplotlib