@@ -178,6 +178,52 @@ def is_allocated(scode1: str, scode2: str) -> bool:
178178 return allocations .get (scode1 , {}).get (scode2 ) is not None
179179
180180
181+ def allocate_to_centers (centers : List [Dict [str , str ]], school : Dict [str , str ], to_allot : int , remaining_cap : Dict [str , int ], stretch : bool = False ):
182+ allocated_centers = {}
183+ per_center = calc_per_center (to_allot )
184+
185+ for center in centers :
186+ school_code = school ['scode' ]
187+ center_code = center ['cscode' ]
188+ writer .writerow ([
189+ school_code ,
190+ school ['count' ],
191+ school ['name-address' ],
192+ school ['lat' ],
193+ school ['long' ],
194+ center_code ,
195+ center ['name' ],
196+ center ['address' ],
197+ center ['capacity' ],
198+ center ['distance_km' ]
199+ ])
200+
201+ if is_allocated (center_code , school_code ):
202+ continue
203+
204+ centers_cap_left = remaining_cap [center_code ]
205+
206+ if stretch :
207+ stretched_capacity = math .floor (int (center ['capacity' ]) * STRETCH_CAPACITY_FACTOR + centers_cap_left )
208+ next_allot = min (to_allot , max (stretched_capacity , MIN_STUDENT_IN_CENTER ))
209+ centers_cap_left = stretched_capacity
210+ else :
211+ next_allot = min (to_allot , per_center , max (centers_cap_left , MIN_STUDENT_IN_CENTER ))
212+
213+ if to_allot > 0 and next_allot > 0 and centers_cap_left >= next_allot :
214+ if next_allot < MIN_STUDENT_IN_CENTER and len (allocated_centers ) > 0 :
215+ # get the first center code
216+ allocate_center_code = centers [0 ]['cscode' ]
217+ else :
218+ allocate_center_code = center_code
219+ allocated_centers [allocate_center_code ] = center
220+
221+ allocate (school_code , allocate_center_code , next_allot )
222+ to_allot -= next_allot
223+ remaining_cap [center_code ] -= next_allot
224+
225+ return to_allot , allocated_centers
226+
181227parser = argparse .ArgumentParser (
182228 prog = 'center randomizer' ,
183229 description = 'Assigns centers to exam centers to students' )
@@ -234,49 +280,13 @@ def is_allocated(scode1: str, scode2: str) -> bool:
234280 centers_for_school = centers_within_distance (
235281 s , centers , PREF_DISTANCE_THRESHOLD )
236282 to_allot = int (s ['count' ])
237- per_center = calc_per_center (to_allot )
238-
239- allocated_centers = {}
240-
241- # per_center = math.ceil(to_allot / min(calc_num_centers(to_allot), len(centers_for_school)))
242- for c in centers_for_school :
243- writer .writerow ([s ['scode' ],
244- s ['count' ],
245- s ['name-address' ],
246- s ['lat' ],
247- s ['long' ],
248- c ['cscode' ],
249- c ['name' ],
250- c ['address' ],
251- c ['capacity' ],
252- c ['distance_km' ]])
253- if is_allocated (c ['cscode' ], s ['scode' ]):
254- continue
255- next_allot = min (to_allot , per_center , max (
256- centers_remaining_cap [c ['cscode' ]], MIN_STUDENT_IN_CENTER ))
257- if to_allot > 0 and next_allot > 0 and centers_remaining_cap [c ['cscode' ]] >= next_allot :
258- allocated_centers [c ['cscode' ]] = c
259- allocate (s ['scode' ], c ['cscode' ], next_allot )
260- # allocation.writerow([s['scode'], s['name-address'], c['cscode'], c['name'], c['address'], next_allot, c['distance_km']])
261- to_allot -= next_allot
262- centers_remaining_cap [c ['cscode' ]] -= next_allot
263-
264- if to_allot > 0 : # try again with relaxed constraints and more capacity at centers
265- expanded_centers = centers_within_distance (
266- s , centers , ABS_DISTANCE_THRESHOLD )
267- for c in expanded_centers :
268- if is_allocated (c ['cscode' ], s ['scode' ]):
269- continue
270- stretched_capacity = math .floor (
271- int (c ['capacity' ]) * STRETCH_CAPACITY_FACTOR + centers_remaining_cap [c ['cscode' ]])
272- next_allot = min (to_allot , max (
273- stretched_capacity , MIN_STUDENT_IN_CENTER ))
274- if to_allot > 0 and next_allot > 0 and stretched_capacity >= next_allot :
275- allocated_centers [c ['cscode' ]] = c
276- allocate (s ['scode' ], c ['cscode' ], next_allot )
277- # allocation.writerow([s['scode'], s['name-address'], c['cscode'], c['name'], c['address'], next_allot, c['distance_km']])
278- to_allot -= next_allot
279- centers_remaining_cap [c ['cscode' ]] -= next_allot
283+
284+ # per_center = math.ceil(to_allot / min(calc_num_centers(to_allot), len(centers_for_school)))
285+ to_allot , allocated_centers = allocate_to_centers (centers_for_school , s , to_allot , centers_remaining_cap )
286+
287+ if to_allot > 0 : # try again with relaxed constraints and more capacity at centers
288+ expanded_centers = centers_within_distance (s , centers , ABS_DISTANCE_THRESHOLD )
289+ to_allot , allocated_centers = allocate_to_centers (expanded_centers , s , to_allot , centers_remaining_cap , stretch_capacity = True )
280290
281291 for c in allocated_centers .values ():
282292 allocation_file .writerow ([s ['scode' ],
0 commit comments