#!/usr/bin/env python3
# ======================================================
# IDOL LEAGUE – 선수 직접 선택 버전 (무제한 인원)
# · 상위 6명 포인트(10·7·5·3·2·1)
# · 랩타임 변환 및 Δ(선두 대비) 출력
# · myCompiler 등에서도 바로 실행되도록 run() 함수 사용
# ======================================================
import random
from collections import Counter
# ─────────────── 로스터 ───────────────
# team, player, Contact, Gap, HR_Power, Eye
RAW = [
# === aespa ===
("aespa","카리나",75,65,80,60), ("aespa","지젤",50,65,60,55),
("aespa","윈터",70,75,50,75), ("aespa","닝닝",65,55,65,70),
# === IVE ===
("IVE","안유진",70,60,70,65), ("IVE","가을",60,65,55,45),
("IVE","레이",55,55,60,55), ("IVE","장원영",80,55,70,50),
("IVE","리즈",65,50,60,70), ("IVE","이서",60,55,65,55),
# === NewJeans ===
("NewJeans","민지",75,70,65,45), ("NewJeans","하니",65,75,65,60),
("NewJeans","다니엘",55,65,55,55), ("NewJeans","해린",70,75,60,50),
("NewJeans","혜인",50,60,55,55),
# === LE SSERAFIM ===
("LE SSERAFIM","김채원",60,75,60,65), ("LE SSERAFIM","사쿠라",55,55,65,50),
("LE SSERAFIM","허윤진",60,55,55,65), ("LE SSERAFIM","카즈하",65,75,70,45),
("LE SSERAFIM","홍은채",65,65,60,40),
# === (G)I-dle ===
("i-dle","미연",75,60,65,70), ("i-dle","민니",65,55,65,70),
("i-dle","소연",45,55,50,75), ("i-dle","우기",65,65,60,65),
("i-dle","슈화",60,55,65,60),
# === fromis_9 ===
("fromis_9","송하영",55,75,60,70), ("fromis_9","박지원",70,55,50,80),
("fromis_9","이채영",70,60,70,55), ("fromis_9","이나경",75,60,60,60),
("fromis_9","백지헌",65,55,75,40),
# === ITZY ===
("ITZY","유나",75,70,80,55), ("ITZY","예지",60,75,60,65),
("ITZY","리아",65,45,60,70), ("ITZY","채령",45,75,65,60),
("ITZY","류진",60,70,60,60),
# === NMIXX ===
("NMIXX","릴리",55,55,55,80), ("NMIXX","해원",60,65,50,70),
("NMIXX","설윤",80,60,65,65), ("NMIXX","배이",60,55,65,55),
("NMIXX","지우",70,70,55,60), ("NMIXX","규진",60,75,60,55),
# === KISS OF LIFE ===
("KOF","쥴리",50,70,70,65), ("KOF","벨",70,65,65,70),
("KOF","나띠",60,75,75,65), ("KOF","하늘",65,60,60,65),
# === ILLIT ===
("ILLIT","윤아",55,60,55,60), ("ILLIT","민주",75,60,60,65),
("ILLIT","모카",60,65,55,55), ("ILLIT","원희",65,60,55,55),
("ILLIT","이로하",60,75,60,50),
# === STAYC ===
("STAYC","수민",50,60,50,50), ("STAYC","시은",45,50,60,65),
("STAYC","아이사",60,65,75,55), ("STAYC","세은",65,50,55,50),
("STAYC","윤",65,60,60,60), ("STAYC","재이",65,55,65,50),
# === Hearts2Hearts ===
("Hearts2Hearts","이안",75,65,50,55), ("Hearts2Hearts","지우",60,70,70,55),
("Hearts2Hearts","스텔라",50,55,60,65), ("Hearts2Hearts","유하",65,70,55,65),
("Hearts2Hearts","주은",45,70,50,55),
# === KiiiKiii ===
("KiiiKiii","이솔",65,60,60,55), ("KiiiKiii","수이",60,70,60,55),
("KiiiKiii","지유",55,55,55,70), ("KiiiKiii","하음",65,65,60,60),
("KiiiKiii","키야",55,70,65,55),
# === H1-KEY ===
("H1-KEY","서이",70,65,65,65), ("H1-KEY","리이나",70,60,70,60),
("H1-KEY","휘서",60,70,60,70), ("H1-KEY","옐",55,55,80,55),
# === BABYMONSTER ===
("BABYMONSTER","루카",50,75,65,50), ("BABYMONSTER","라미",45,60,60,70),
("BABYMONSTER","로라",65,60,60,65), ("BABYMONSTER","아현",70,70,65,75),
("BABYMONSTER","아사",65,70,65,55), ("BABYMONSTER","파리타",60,55,75,60),
# === FIFTY FIFTY ===
("FIFTY FIFTY","키나",55,55,55,60), ("FIFTY FIFTY","문샤넬",60,50,50,75),
("FIFTY FIFTY","예원",55,55,55,65), ("FIFTY FIFTY","하나",65,75,65,55),
# === MEOVV ===
("MEOVV","수인",60,70,65,55), ("MEOVV","가원",40,60,65,70),
("MEOVV","안나",75,65,60,55), ("MEOVV","나린",60,65,60,60),
("MEOVV","엘라",60,60,55,55),
# === TripleS ===
("TripleS","윤서연",60,45,60,60), ("TripleS","김채연",60,55,80,55),
("TripleS","김유연",70,35,60,40), ("TripleS","김나경",65,65,60,60),
("TripleS","신위",70,55,65,60),
# === Kep1er ===
("Kep1er","최유진",55,60,60,60), ("Kep1er","샤오팅",60,70,65,50),
("Kep1er","김채현",60,65,60,70), ("Kep1er","김다연",55,75,55,55),
("Kep1er","휴닝바히에",50,55,60,55),
# === QWER ===
("QWER","마젠타",50,40,60,35), ("QWER","쵸단",65,50,65,45),
("QWER","시연",55,55,60,70), ("QWER","히나",55,45,60,40),
# === RESCENE ===
("RESCENE","원이",65,55,60,60), ("RESCENE","리브",60,60,60,55),
("RESCENE","미나미",50,65,55,70), ("RESCENE","메이",60,55,55,55),
("RESCENE","제나",60,55,65,55),
# === LIGHTSUM ===
("LIGHTSUM","상아",55,55,55,55), ("LIGHTSUM","초원",55,60,80,75),
("LIGHTSUM","나영",60,65,60,70), ("LIGHTSUM","히나",60,50,50,45),
("LIGHTSUM","주현",55,70,60,60), ("LIGHTSUM","유정",55,55,55,55),
# === izna ===
("izna","코코",60,70,60,50), ("izna","마이",50,55,55,50),
("izna","윤지윤",55,55,60,60), ("izna","유사랑",60,65,60,55),
("izna","방지민",55,65,60,55), ("izna","정세비",65,65,70,55),
# === OH MY GIRL ===
("OHMYGIRL","효정",50,55,60,60), ("OHMYGIRL","미미",40,70,55,55),
("OHMYGIRL","유아",65,75,50,55), ("OHMYGIRL","승희",50,60,55,60),
("OHMYGIRL","아린",65,55,70,55),
# === ARTMS ===
("ARTMS","진솔",55,60,60,50), ("ARTMS","하슬",50,50,50,65),
("ARTMS","김립",55,60,60,60), ("ARTMS","희진",70,65,60,55),
("ARTMS","최리",60,60,55,50),
# === PURPLE KISS ===
("PURPLEKISS","고은",55,50,50,65), ("PURPLEKISS","도시",50,65,55,45),
("PURPLEKISS","유키",55,60,50,45), ("PURPLEKISS","채인",55,60,55,60),
# === EVERGLOW ===
("EVERGLOW","EU",55,60,60,45), ("EVERGLOW","시현",60,55,60,60),
("EVERGLOW","미아",55,60,60,60), ("EVERGLOW","아이샤",55,55,60,45),
("EVERGLOW","이런",70,55,55,50),
# === Dreamcatcher ===
("Dreamcatcher","지유",65,55,60,55), ("Dreamcatcher","수아",50,65,60,50),
("Dreamcatcher","시연",50,50,50,70), ("Dreamcatcher","유현",50,50,50,65),
("Dreamcatcher","다미",45,60,60,45),
# === Weeekly ===
("Weeekly","수진",50,55,50,55), ("Weeekly","소은",55,50,50,60),
("Weeekly","재희",65,50,50,45), ("Weeekly","지한",65,60,55,65),
("Weeekly","조아",55,50,50,45),
# === BDC ===
("BDC","이현",65,65,65,65), ("BDC","쿠미",60,60,60,50),
("BDC","미아",55,60,55,60), ("BDC","베니",45,70,60,50),
]
# ─────────────── 기본 함수 ───────────────
def lin_map(x,x0=20,x1=80,y0=0,y1=1):
return y0 + (x-x0)*(y1-y0)/(x1-x0)
def jitter(val,pct=0.3):
return val * random.uniform(1-pct, 1+pct)
def sim_season(rows, pa=650, seed=None):
if seed is not None:
random.seed(seed)
out=[]
for team,pl,c,g,h,e in rows:
avg = jitter(lin_map(c,y0=.200,y1=.330))
bb = jitter(lin_map(e,y0=.04 ,y1=.15))
hr = jitter(lin_map(h,y0=.005,y1=.06))
db = jitter(lin_map(g,y0=.03 ,y1=.09))
tp = jitter(lin_map(g,y0=.002,y1=.010))
BB=int(bb*pa); AB=pa-BB
HR=int(hr*AB); DB=int(db*AB); TP=int(tp*AB)
H = int(avg*AB); S=max(0,H-DB-TP-HR)
TB=S + 2*DB + 3*TP + 4*HR
OBP=(H+BB)/pa; SLG=TB/AB
wRC=int(((1.2*(H+BB)/pa)/.330 + (0.8*TB/AB)/.370 - 1)*100)
WAR=round((wRC-100)/10*pa/650,1)
out.append((team,pl,round(H/AB,3),round(OBP,3),
round(SLG,3),wRC,WAR))
# 정렬은 wRC+ 기준
return sorted(out,key=lambda x:x[5],reverse=True)
# ─────────────── 랩 타임 변환 파라미터 ───────────────
SCALE = 1.0 # WAR 1.0 차이 → 1.000초
BASE_CONST = 88.0 # 선두 WAR=6.0일 때 1:28.000
BASE_SLOPE = 1.5 # 선두 WAR 1↑ → 기준랩 1.5초 빨라짐
MIN_RECORD = 70.0 # 1:10.000 이하로 깎지 않음
def as_time(sec: float) -> str:
m, s = divmod(sec, 60)
return f"{int(m)}:{s:06.3f}"
def war_to_base(leader_war: float) -> float:
base = BASE_CONST - (leader_war - 6.0)*BASE_SLOPE
return max(base, MIN_RECORD)
# ─────────────── 실행부 ───────────────
def run():
# 선수 선택 안내
print("입력 형식: 팀명:선수명 여러 명을 콤마(,)로 구분")
print("예: 팀1 -> IVE:장원영, ILLIT:민주, NMIXX:지우")
print(" 팀2 -> aespa:카리나, fromis_9:이채영")
print("\n전체 선수 목록(팀:선수) 예시는 위 RAW 참고. 중복 이름 주의!")
# 선수 맵
player_map = {}
for t,p,*rest in RAW:
key = f"{t}:{p}"
player_map[key] = (t,p,*rest)
def parse_players(prompt):
line = input(prompt).strip()
if not line:
return []
keys = [x.strip() for x in line.split(",") if x.strip()]
rows = []
for k in keys:
if k not in player_map:
raise ValueError(f"'{k}' 를 찾을 수 없음 (팀명:선수명 형식 확인)")
rows.append(player_map[k])
return rows
group1_name = input("\n첫 번째 그룹 이름 (엔터 시 'GroupA'): ").strip() or "GroupA"
group2_name = input("두 번째 그룹 이름 (엔터 시 'GroupB'): ").strip() or "GroupB"
g1_rows = parse_players(f"{group1_name} 선수들 입력: ")
g2_rows = parse_players(f"{group2_name} 선수들 입력: ")
if not g1_rows or not g2_rows:
raise ValueError("양쪽 그룹 모두 최소 1명 이상 입력해야 합니다.")
# 시뮬
rows = g1_rows + g2_rows
res = sim_season(rows, seed=None)
# 포인트 계산
POINT = [10,7,5,3,2,1]
score = Counter({group1_name:0, group2_name:0})
pts_map = {row[1]:0 for row in res}
for idx,(team,pl,avg,obp,slg,wrc,war) in enumerate(res[:len(POINT)]):
gain = POINT[idx]
pts_map[pl] = gain
belong = group1_name if (team,pl) in [(r[0],r[1]) for r in g1_rows] else group2_name
score[belong]+=gain
# 랩 타임 변환
leader_war = res[0][6]
base_lap = war_to_base(leader_war)
print("\nTeam Player LAP Δ PTS")
print("-"*54)
for team, pl, avg, obp, slg, wrc, war in res:
gap_sec = (leader_war - war) * SCALE
lap_time = base_lap + gap_sec
delta = " ---" if gap_sec == 0 else f"+{gap_sec:6.3f}"
print(f"{team:10} {pl:12} {as_time(lap_time):>7} {delta} {pts_map[pl]:>3}")
print("\n그룹 포인트:")
print(f"{group1_name}: {score[group1_name]} 점")
print(f"{group2_name}: {score[group2_name]} 점")
winner = "무승부" if score[group1_name]==score[group2_name] \
else (group1_name if score[group1_name]>score[group2_name] else group2_name)
print("→ 승리 그룹:", winner)
# 그냥 실행
run()
To embed this project on your website, copy the following code and paste it into your website's HTML: