27. 파티장 위임 중에 파티장이 탈퇴/접속종료되는 상황

난이도 하 해설 보기 →

결함을 모두 찾고 원인·수정안·더 나은 설계를 제시하라. 마커 (A)(B) 는 주목 위치 힌트다.

결함 코드 · C#
// ============================================================================
// [코드리뷰 문제] C# - 파티장 위임 중에 파티장이 탈퇴/접속종료되는 상황
// ----------------------------------------------------------------------------
// 시나리오 (콘텐츠/게임로직 · 서버-클라):
//   - 파티에는 파티장(leader) 1명이 있고, 파티장만 초대/추방/해산/위임을 할 수 있다.
//   - 파티장은 다른 멤버에게 파티장을 "위임(delegate)" 할 수 있다.
//   - 위임 처리 중이거나 직후에 기존 파티장이 "탈퇴(Leave)" 하거나 접속종료(Disconnect)
//     될 수 있다(서로 다른 요청/스레드).
//   - 파티장이 떠나면 서버는 남은 멤버 중 한 명으로 파티장을 자동 승계시켜야 한다.
//
// 요구사항:
//   - 위임 대상은 "현재 그 파티에 속한, 유효한 멤버" 여야 한다(이미 나간 사람/외부인 금지).
//   - 어떤 시점에도 파티장은 정확히 1명이어야 한다(리더 0명=leaderless, 2명 금지).
//   - 파티장이 떠나면 남은 멤버가 있는 한 파티는 leaderless 가 되면 안 된다
//     (남은 멤버가 없으면 파티 해산).
//
// 과제:
//   이 코드의 잠재적 문제를 모두 찾고, 왜/어떻게 leaderless 파티·유효하지 않은 파티장·
//   리더 2명 같은 상태가 생기는지 설명하고, 수정안과 더 나은 설계를 제시하라.
//   (먼저 직접 리뷰를 적은 뒤 answer.md 와 대조할 것)
// ============================================================================

using System;
using System.Collections.Generic;

public class Party
{
    public long       PartyId;
    public long       LeaderId;
    public List<long> Members = new();   // 파티장 포함 전체 멤버
}

public class PartyService
{
    private readonly Dictionary<long, Party> _parties = new();   // partyId -> Party

    // 파티장이 다른 멤버에게 파티장 위임
    public bool Delegate(long partyId, long requesterId, long targetId)
    {
        if (!_parties.TryGetValue(partyId, out var party)) return false;
        if (party.LeaderId != requesterId) return false;   // 파티장만 위임 가능

        // (A) 위임 대상 처리를 검토하라
        party.LeaderId = targetId;
        return true;
    }

    // 멤버 탈퇴(자발적 Leave)
    public void Leave(long partyId, long playerId)
    {
        if (!_parties.TryGetValue(partyId, out var party)) return;

        party.Members.Remove(playerId);

        // (B) 떠나는 사람이 파티장일 때의 처리를 검토하라
        if (party.LeaderId == playerId)
        {
            if (party.Members.Count > 0)
                party.LeaderId = party.Members[0];
            // else: 남은 멤버가 0명인 경우의 처리를 검토하라
        }
    }

    // 접속종료(네트워크 콜백, 다른 스레드)
    public void OnDisconnect(long partyId, long playerId)
    {
        if (!_parties.TryGetValue(partyId, out var party)) return;

        // (C) 접속종료 시 처리를 검토하라
        party.Members.Remove(playerId);
    }
}
내 리뷰 · C#
내 답안 · 자동 저장

작성 후 위 해설 보기에서 모범 해설과 대조하세요.