Skip to content

Instantly share code, notes, and snippets.

@HW-Lee
Created June 27, 2024 08:58
Show Gist options
  • Save HW-Lee/f48ec5b1c74606d4ccfe985c5c762638 to your computer and use it in GitHub Desktop.
Save HW-Lee/f48ec5b1c74606d4ccfe985c5c762638 to your computer and use it in GitHub Desktop.
BT停車位抽籤原始碼 2024
import sys
import numpy as np
import json
import pandas
from io import StringIO
import re
import time
from itertools import chain
"""
Caveat#1: It's fair as long as the supply is sufficient. (i.e. supply >= demand)
- When the demand is over the supply, the result where someone gets multiple spots while someone
gets none might occur, and it's not fair when we hope everyone can get at least one spot.
Caveat#2: The spot ids must be unique.
- Adding by 300 for bicycle spots to avoid duplicate.
Caveat#3: The way telling e-scooters from fuel-driven ones is by checking the notes.
- 1E1F and 2F look identical in "number of scooters" columns.
- E, F, M stand for e-scooters, general scooters, and motors respectively.
"""
pandas.set_option("display.max_rows", None)
pandas.set_option("display.max_columns", None)
SPOTS = {
"F": ("一般機車位", list(range(4, 22)) + list(range(35, 119))), # 4-21, 35-118
"E": ("電動機車位", [1] + list(range(22, 35))), # 1, 22-34
"M": ("重機車位", [144, 145]), # 144-145
"B": ("腳踏車位", list(range(301, 314)) + list(range(322, 339)) + list(range(150, 153))), # 301-313, 322-338, 150-152
}
PATTERN = "(\\d+)([EFM])"
def process_name(name):
p = "A\\d{1}-(?P<floor>\\d+)F"
m = re.match(p, name)
return "{}-{:02d}F".format(name.split("-")[0], int(m.groupdict()["floor"]))
def org_by_name(result):
r = {}
result = sorted(result, key=lambda x: x[1])
for spot_id, name in result:
if not name in r:
r[name] = []
r[name].append(str(spot_id))
return r
def zip_adapt(a, b):
if len(a) == len(b):
return zip(a, b)
l = min(len(a), len(b))
return zip(a[:l], b[:l])
def run(csv_path):
scooter_numbers = np.delete(np.arange(154) + 1, list(range(133, 136)) + list(range(142, 145)))
bike_numbers = np.delete(np.arange(42) + 1, list(range(13, 21)) + list(range(38, 42)))
queues = {k: [] for k in SPOTS}
df = pandas.read_csv(csv_path)
for r in df.to_dict(orient="records"):
if "需要幾腳踏車位" in r:
n_bike_required = r["需要幾腳踏車位"]
if n_bike_required == 1:
queues["B"].append(process_name(r["戶別"]))
elif n_bike_required == 0:
pass
else:
raise(ValueError("戶別 {} 要求的腳踏車位數不符規定。".format(process_name(r["戶別"]))))
if "備註" in r and isinstance(r["備註"], str):
for e in re.findall(PATTERN, r["備註"]):
queues[e[1]] += [process_name(r["戶別"])] * int(e[0])
for k in SPOTS:
name, spot_ids = SPOTS[k]
print("{}號碼:{} 共 {} 車位 (共需 {} 車位)".format(name, spot_ids, len(spot_ids), len(queues[k])))
print("---------------------------------------------")
print("車位分配結果(照車位號排序)\n")
result = {k: np.random.permutation(v) for k, v in queues.items()}
result = list(chain(*[list(zip_adapt(SPOTS[k][1], result[k])) for k in result]))
result = sorted(result, key=lambda x: x[0])
df_org_by_spot_id = pandas.DataFrame(result, columns=["車位號", "戶別"])
print(df_org_by_spot_id.to_string(index=False))
df_org_by_spot_id.to_csv("車位分配結果-照車位號排序.csv", index=False)
print("---------------------------------------------")
print("車位分配結果(照戶別排序)\n")
result = org_by_name(result)
df_org_by_name = pandas.DataFrame.from_dict(result, orient="index")
df_org_by_name.columns = ["車位{}".format(x) for x in range(len(df_org_by_name.columns))]
df_org_by_name.fillna("", inplace=True)
print(df_org_by_name)
df_org_by_name.to_csv("車位分配結果-照戶別排序.csv")
if __name__ == "__main__":
run(sys.argv[1])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment