IPL_Auction_simulator / app /auction_engine.py
Dinojan-13's picture
add auction engine
fb599cb
Raw
History Blame Contribute Delete
8.11 kB
import random
import copy
from datetime import datetime
from app.players import get_all_players, ROLE_ORDER
DEFAULT_SETTINGS = {
"purse_per_team": 1200, # lakhs
"min_squad_size": 18,
"max_squad_size": 25,
"max_overseas": 8,
"timer_seconds": 30,
"timer_reset_on_bid": True,
"bid_increment": 5,
"unsold_recall": True,
"auto_pass_enabled": True,
}
SET_ORDER = ["SET_A","SET_B","SET_C","SET_D","SET_E","SET_F","SET_G","SET_H","SET_I","SET_J"]
def create_room(room_code: str, host_id: str, host_name: str, settings: dict = None) -> dict:
s = copy.deepcopy(DEFAULT_SETTINGS)
if settings:
s.update(settings)
return {
"room_code": room_code,
"host_id": host_id,
"created_at": datetime.utcnow().isoformat(),
"state": "lobby",
"settings": s,
"teams": {
host_id: {
"id": host_id,
"name": host_name,
"team_name": f"{host_name}'s XI",
"purse": s["purse_per_team"],
"players": [],
"is_host": True,
"connected": True,
}
},
"players": get_all_players(),
"auction_queue": [],
"current_player_id": None,
"current_bid": 0,
"current_bidder_id": None,
"bid_history": [],
"sold_log": [],
"unsold_players": [],
"chat_messages": [],
"status_message": "Waiting for host to start.",
}
def add_team(room: dict, user_id: str, username: str, team_name: str = None) -> dict:
if user_id not in room["teams"]:
room["teams"][user_id] = {
"id": user_id,
"name": username,
"team_name": team_name or f"{username}'s XI",
"purse": room["settings"]["purse_per_team"],
"players": [],
"is_host": False,
"connected": True,
}
else:
room["teams"][user_id]["connected"] = True
return room
def get_player(room: dict, pid: str):
return next((p for p in room["players"] if p["id"] == pid), None)
def build_queue(room: dict, order: str = "set") -> list:
players = [p for p in room["players"] if p["status"] == "available"]
if order == "set":
players.sort(key=lambda p: (
SET_ORDER.index(p.get("auction_set", "SET_J"))
))
elif order == "role":
players.sort(key=lambda p: (
ROLE_ORDER.index(p["role"]) if p["role"] in ROLE_ORDER else 99
))
elif order == "marquee_first":
players.sort(key=lambda p: (
["MARQUEE","A+","A"].index(p.get("category","A"))
if p.get("category") in ["MARQUEE","A+","A"] else 99
))
elif order == "india_first":
players.sort(key=lambda p: (0 if not p["overseas"] else 1))
elif order == "random":
random.shuffle(players)
return [p["id"] for p in players]
def start_next(room: dict) -> dict:
if not room["auction_queue"]:
room["state"] = "ended"
room["status_message"] = "Auction complete!"
return room
pid = room["auction_queue"].pop(0)
player = get_player(room, pid)
if not player:
return start_next(room)
room["current_player_id"] = pid
room["current_bid"] = player["base_price"]
room["current_bidder_id"] = None
room["state"] = "auction"
room["status_message"] = f"Bidding open for {player['name']}!"
return room
def place_bid(room: dict, bidder_id: str, amount: int):
"""Returns (ok, message, room)."""
if room["state"] != "auction":
return False, "Auction not active", room
team = room["teams"].get(bidder_id)
player = get_player(room, room["current_player_id"])
if not team or not player:
return False, "Invalid state", room
settings = room["settings"]
inc = settings["bid_increment"]
min_bid = room["current_bid"] + inc if room["current_bidder_id"] else room["current_bid"]
if amount < min_bid:
return False, f"Min bid is ₹{min_bid}L", room
if team["purse"] < amount:
return False, "Insufficient purse", room
if len(team["players"]) >= settings["max_squad_size"]:
return False, "Squad full", room
if player["overseas"]:
overseas_count = sum(
1 for pid in team["players"]
if get_player(room, pid) and get_player(room, pid)["overseas"]
)
if overseas_count >= settings["max_overseas"]:
return False, "Overseas limit reached", room
if bidder_id == room["current_bidder_id"]:
return False, "You are already the highest bidder", room
room["current_bid"] = amount
room["current_bidder_id"] = bidder_id
room["bid_history"].append({
"player_id": room["current_player_id"],
"bidder_id": bidder_id,
"bidder_name": team["name"],
"amount": amount,
"ts": datetime.utcnow().isoformat(),
})
return True, f"₹{amount}L by {team['name']}", room
def sell_current(room: dict):
pid = room["current_player_id"]
bidder = room["current_bidder_id"]
if not pid or not bidder:
return mark_unsold(room)
player = get_player(room, pid)
team = room["teams"][bidder]
amount = room["current_bid"]
player["status"] = "sold"
player["bought_by"] = bidder
team["purse"] -= amount
team["players"].append(pid)
room["sold_log"].append({
"player_id": pid,
"player_name": player["name"],
"team_id": bidder,
"team_name": team["team_name"],
"price": amount,
"ts": datetime.utcnow().isoformat(),
})
room["current_player_id"] = None
room["current_bidder_id"] = None
room["current_bid"] = 0
room["status_message"] = f"🔨 SOLD! {player['name']}{team['team_name']}{amount}L"
return room
def mark_unsold(room: dict):
pid = room["current_player_id"]
if pid:
p = get_player(room, pid)
if p:
p["status"] = "unsold"
room["unsold_players"].append(pid)
room["status_message"] = f"❌ UNSOLD — {p['name']}"
room["current_player_id"] = None
room["current_bidder_id"] = None
room["current_bid"] = 0
return room
def recall_unsold(room: dict) -> dict:
for pid in room["unsold_players"]:
p = get_player(room, pid)
if p:
p["status"] = "available"
room["auction_queue"].append(pid)
room["unsold_players"] = []
room["status_message"] = "Unsold players re-added!"
return room
def final_summary(room: dict) -> dict:
summaries = []
for tid, team in room["teams"].items():
bought = []
for pid in team["players"]:
p = get_player(room, pid)
sale = next((s for s in room["sold_log"] if s["player_id"] == pid), None)
if p:
bought.append({**p, "price_paid": sale["price"] if sale else 0})
spent = room["settings"]["purse_per_team"] - team["purse"]
summaries.append({
"team": team,
"players": bought,
"spent": spent,
"purse_remaining": team["purse"],
"overseas_count": sum(1 for p in bought if p.get("overseas")),
"role_counts": {r: sum(1 for p in bought if p["role"] == r) for r in ROLE_ORDER},
})
return {
"teams": summaries,
"total_sold": len(room["sold_log"]),
"total_unsold": len(room["unsold_players"]),
"most_expensive": max(room["sold_log"], key=lambda s: s["price"], default=None),
"unsold_players": [get_player(room, pid)["name"] for pid in room["unsold_players"] if get_player(room, pid)],
}