본문 바로가기
내 생각

리그오브레전드 팀 빌딩 프로그램

by JJong | 쫑 2024. 9. 4.

*완성이라고 하기엔 흠이 많은 프로그램입니다.


main.py
0.00MB
main.py 실행한 모습


문제 정의

롤 사설 경기에서 플레이어들의 정보를 바탕으로 균형 잡힌 팀을 자동으로 구성해주는 프로그램입니다.

 

로직 설명

  1. 플레이어들의 정보를 수집합니다. 플레이어의 정보에는 [닉네임, 랭크 티어, 주 포지션, 서브 포지션들] 이 있습니다.
  2. 포지션별로 플레이어들을 분류합니다. 인원이 적은 포지션부터 우선적으로 배정합니다.
  3. 배정되지 않은 플레이어들은 랜덤하게 남은 포지션에 할당합니다.

코드 원문은 깃허브에서 확인할 수 있습니다.

# main.py

def build_team():
    # 포지션을 담을 리스트
    positions = defaultdict(list)  # 각 포지션에 해당하는 플레이어들을 담기 위한 딕셔너리, 기본값은 빈 리스트

    for lane in total_lane:
        positions[lane]  # 각 포지션을 키로 초기화 (실제 동작은 없지만 구조를 명확히 하기 위해)

    # 포지션 리스트 채우기
    for player in players:
        name, tier, primary_pos, *secondary_pos = player  # 플레이어의 이름, 티어, 주 포지션, 서브 포지션들을 할당
        mmr = MMR.tier_to_mmr(tier)  # 플레이어의 티어를 MMR 값으로 변환
        positions[primary_pos].append((name, mmr, primary_pos))  # 주 포지션에 플레이어 추가
        for pos in secondary_pos:
            positions[pos].append((name, mmr, pos))  # 각 서브 포지션에도 플레이어를 추가

    # >> 포지션 별로 몰리는 라인도 생기고, 그렇지 않은 라인도 있을 것이다
    # 인원이 적은 라인에서 먼저 배정을 해주자.
    tmp_positions = sorted([(lane, len(positions[lane])) for lane in total_lane], key=lambda x: x[1])  
    # 각 포지션에 할당된 플레이어 수를 기반으로 포지션을 오름차순 정렬

    tm1, tm2 = {}, {}  # 팀 1과 팀 2를 위한 딕셔너리, 각 포지션의 플레이어를 저장
    assigned_players = set()  # 이미 팀에 배정된 플레이어들을 추적하기 위한 집합

    for pos, n in tmp_positions:
        random.shuffle(positions[pos])  # 해당 포지션에 있는 플레이어들의 순서를 랜덤하게 섞음

        for i in range(min(2, len(positions[pos]))):  # 각 포지션에서 최대 2명까지 플레이어를 팀에 배정
            player = positions[pos].pop()  # player = (name, mmr, position) 형태로 플레이어를 리스트에서 꺼냄
            if player[0] in assigned_players:
                continue  # 이미 배정된 플레이어는 건너뜀
            # Todo: random하게 팀 배정해야 됨. 순서대로가 아니라.
            if len(tm1) <= len(tm2):
                tm1[pos] = (player[0], player[1])  # 팀 1에 플레이어 배정
            else:
                tm2[pos] = (player[0], player[1])  # 팀 2에 플레이어 배정

            assigned_players.add(player[0])  # 팀 배정을 받은 유저로 추가

    # 배정을 받지 못한 플레이어들 처리
    remaining_players = []  # 아직 배정되지 않은 플레이어들을 담을 리스트
    for pos in total_lane:
        for player in positions[pos]:
            if player[0] not in assigned_players:
                remaining_players.append(player)  # 아직 팀에 배정되지 않은 플레이어를 추가

    random.shuffle(remaining_players)  # 남은 플레이어들을 랜덤하게 섞음

    # 빈 자리에 남은 플레이어 배정
    for pos in total_lane:
        if pos not in tm1 and remaining_players:
            p = remaining_players.pop()  # 남은 플레이어를 꺼내서
            tm1[pos] = (p[0], p[1])  # 팀 1의 빈 포지션에 배정
        if pos not in tm2 and remaining_players:
            p = remaining_players.pop()  # 남은 플레이어를 꺼내서
            tm2[pos] = (p[0], p[1])  # 팀 2의 빈 포지션에 배정

    print_team(tm1, tm2)  # 최종 팀 구성 출력

Q. 왜 포지션 리스트에 들어 있는 플레이어들을 섞는가?

random.shuffle(positions[pos])  # 해당 포지션에 있는 플레이어들의 순서를 랜덤하게 섞음

 

 

 

A. 포지션이 3명 이상 겹치는 경우도 분명 있을 것이라 판단했다. 사람들이 input 순서에 따라 라인 배정을 받는 것을 원치 않았다. 그래서 선택된 포지션을 플레이 할 수 있는 플레이어들을 셔플하고 pop을 함으로써 최대한 무작위로, 하지만 자신이 운용 가능한 라인에 배정되도록 했다.

 


개발 배경

부대에서 선임, 동기, 후임들과 롤 5:5 내전을 하게 된 재미있는 기회가 있었다. 나가면 많아야 3판이 다라서, 팀 밸런싱에 고민을 많이 했다.

팀 빌딩에는 여러 가지의 경우의 수가 나올 것이라 기대했다. 실제로 팀을 꾸리다보니, 관리하기 어려울 정도로 다양한 팀 밸런싱이 이루어졌다. 추가로 막상해보니 직접 경우의 수를 따지기가 번거롭기도 했다. 그래서 주어진 조건 안에서 랜덤한 방법으로 팀을 여러 개 뽑아내주는 프로그램이 있으면 좋겠다고 생각했다. 그러면 여러 종류의 팀을 볼 수 있을 것이고, 제안 받은 여러 안들 중 리밸런싱을 하거나 마음에 드는 것을 채택해서 바로 팀으로 결정될 수 있다는 장점이 있다고 생각했기 때문이다.


문제점

위 로직대로는 주 포지션과 서브 포지션에 대한 경계가 사실 없다. 그래서 주 포지션과 서브 포지션을 따로 보관하고 팀 배정에 활용했어야 했다.

 


 

댓글