James McCool commited on
Commit
ffe9064
·
1 Parent(s): 40f41b3

Enhance player swapping logic to maintain team diversity by implementing constraints that ensure at least three teams are represented in the lineup, while also considering the current player's team during replacements.

Browse files
Files changed (1) hide show
  1. src/sports/nhl_functions.py +38 -4
src/sports/nhl_functions.py CHANGED
@@ -429,7 +429,6 @@ def init_team_results(model_source: DataFrame, position_reqs: dict, salary_cap:
429
  # Add the position to our swapped tracking list
430
  swapped_positions.append(pos_to_swap)
431
 
432
- # ... existing code for finding replacement player ...
433
  # Find the assigned position (e.g., 'OF', 'SP', etc.)
434
  match = re.match(r'[A-Z]+', pos_to_swap.strip())
435
  if match:
@@ -437,6 +436,20 @@ def init_team_results(model_source: DataFrame, position_reqs: dict, salary_cap:
437
  else:
438
  continue
439
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
440
  # Handle special positions
441
  if assigned_pos == 'FLEX' or assigned_pos == 'FLEX1' or assigned_pos == 'FLEX2':
442
  util_positions = ['C', 'W', 'D']
@@ -461,6 +474,30 @@ def init_team_results(model_source: DataFrame, position_reqs: dict, salary_cap:
461
 
462
  if eligible.empty:
463
  continue
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
464
  # Randomly select a replacement
465
  replacement = eligible.sample(1).iloc[0]
466
  new_row[pos_to_swap] = replacement['Name']
@@ -479,9 +516,6 @@ def init_team_results(model_source: DataFrame, position_reqs: dict, salary_cap:
479
  # Get all position columns (exclude totals)
480
  pos_labels = [col for col in final_df.columns if col not in ['Total_Salary', 'Total_Median', 'Target_Team', 'Own']]
481
 
482
- # Create a mapping from player name to team for fast lookup
483
- player_team_map = filtered_df.set_index('Name')['Team'].to_dict()
484
-
485
  # Count target team players in each row
486
  def count_target_team(row):
487
  return sum(1 for pos in pos_labels if player_team_map.get(row[pos], None) == target_team)
 
429
  # Add the position to our swapped tracking list
430
  swapped_positions.append(pos_to_swap)
431
 
 
432
  # Find the assigned position (e.g., 'OF', 'SP', etc.)
433
  match = re.match(r'[A-Z]+', pos_to_swap.strip())
434
  if match:
 
436
  else:
437
  continue
438
 
439
+ # Get current player being swapped and their team
440
+ current_player = new_row[pos_to_swap]
441
+ current_player_team = player_team_map.get(current_player)
442
+
443
+ # Count teams in current lineup (before swap)
444
+ current_lineup_players = [new_row[pos] for pos in pos_labels]
445
+ current_teams = set(player_team_map.get(p) for p in current_lineup_players if player_team_map.get(p))
446
+
447
+ # Count how many players from the current player's team are in the lineup
448
+ players_from_same_team = sum(1 for p in current_lineup_players if player_team_map.get(p) == current_player_team)
449
+
450
+ # If this player is the only one from their team, we need to be careful
451
+ must_maintain_team = players_from_same_team == 1 and len(current_teams) <= 3
452
+
453
  # Handle special positions
454
  if assigned_pos == 'FLEX' or assigned_pos == 'FLEX1' or assigned_pos == 'FLEX2':
455
  util_positions = ['C', 'W', 'D']
 
474
 
475
  if eligible.empty:
476
  continue
477
+
478
+ # Filter eligible players to maintain 3-team constraint
479
+ if must_maintain_team:
480
+ # Must pick from same team OR ensure 3 teams remain
481
+ # Get teams that would remain after removing current player
482
+ remaining_teams = set(player_team_map.get(p) for p in current_lineup_players if p != current_player and player_team_map.get(p))
483
+
484
+ # Filter to players whose team either:
485
+ # 1. Is the same as current player (maintains that team)
486
+ # 2. Is already in remaining_teams AND remaining_teams has at least 2 other teams
487
+ def maintains_3_teams(player_team):
488
+ if player_team == current_player_team:
489
+ return True # Same team, maintains the team
490
+ if player_team in remaining_teams and len(remaining_teams) >= 3:
491
+ return True # Team already represented and we have enough teams
492
+ if player_team not in remaining_teams and len(remaining_teams) >= 2:
493
+ return True # New team, but we still have 2 other teams + this one = 3
494
+ return False
495
+
496
+ eligible = eligible[eligible['Team'].apply(maintains_3_teams)]
497
+
498
+ if eligible.empty:
499
+ continue
500
+
501
  # Randomly select a replacement
502
  replacement = eligible.sample(1).iloc[0]
503
  new_row[pos_to_swap] = replacement['Name']
 
516
  # Get all position columns (exclude totals)
517
  pos_labels = [col for col in final_df.columns if col not in ['Total_Salary', 'Total_Median', 'Target_Team', 'Own']]
518
 
 
 
 
519
  # Count target team players in each row
520
  def count_target_team(row):
521
  return sum(1 for pos in pos_labels if player_team_map.get(row[pos], None) == target_team)