Created
June 27, 2024 08:58
-
-
Save HW-Lee/f48ec5b1c74606d4ccfe985c5c762638 to your computer and use it in GitHub Desktop.
BT停車位抽籤原始碼 2024
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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