18. 레이드 페이즈 전환과 플레이어 입·퇴장 경합 (C#)
난이도 최상 해설 보기 →
결함을 모두 찾고 원인·수정안·더 나은 설계를 제시하라. 마커
(A)(B) 는 주목 위치 힌트다.
결함 코드 · C#
// ============================================================================
// [코드리뷰 문제] C# - 레이드 페이즈 전환과 플레이어 입·퇴장 경합
// ----------------------------------------------------------------------------
// 시나리오:
// - 레이드 인스턴스는 보스 페이즈(P1 -> P2 -> P3 ...)로 진행한다. 보스 HP 가
// 임계치 아래로 내려가면 다음 페이즈로 전환하며, 전환 시 추가 몹 소환,
// 강화(enrage) 버프, 플레이어 위치 리셋 같은 "페이즈 효과"를 모든 참가자에게
// 적용한다.
// - 전환을 검사/실행하는 것은 보스 전투 처리 스레드다(데미지 적중마다 검사).
// - 동시에 다른 스레드는 플레이어의 입장(지각 입장/재접속 복귀)과 퇴장(사망
// 아웃/접속종료)을 처리해 참가자 목록을 변경한다.
// - 지각 입장한 플레이어는 "현재 페이즈" 상태로 합류해야 한다(페이즈 효과를
// 놓치면 디싱크: 안 소환된 몹/안 걸린 enrage 로 전투가 어긋난다).
//
// 요구사항:
// - 페이즈 전환은 임계치를 한 번 통과할 때 정확히 한 번만 일어나야 한다.
// - 전환 도중 입·퇴장이 일어나도 예외로 죽지 않고, 새 참가자는 올바른 현재
// 페이즈 상태로 동기화돼야 한다.
// - 페이즈 효과(소환/enrage)가 누락되거나 중복 적용되면 안 된다.
//
// 과제:
// 이 코드의 잠재적 문제를 모두 찾고, 왜/어떻게 깨지는지(동시 인터리빙 포함)
// 설명하고, 수정안과 더 나은 설계를 제시하라.
// (먼저 직접 리뷰를 적은 뒤 answer.md 와 대조할 것)
// ============================================================================
using System;
using System.Collections.Generic;
public class Player
{
public long Id;
public int SyncedPhase; // 이 플레이어가 동기화된 페이즈
public void ApplyPhaseEffects(int phase) { /* 소환 인지/enrage/위치리셋 적용 */ }
public void SendPhaseState(int phase) { /* 현재 페이즈 상태 전송 */ }
}
public class RaidInstance
{
public long Boss_Hp;
public int Phase = 1;
public readonly int[] PhaseThresholds; // 각 페이즈 전환 HP 임계치
public List<Player> Members = new List<Player>();
public RaidInstance(int[] thresholds) { PhaseThresholds = thresholds; }
}
public class RaidService
{
// 보스 전투 스레드: 데미지 적중마다 호출
public void OnBossDamaged(RaidInstance raid, long dmg)
{
raid.Boss_Hp -= dmg;
// (A) 다음 페이즈 임계치 통과 검사
int next = raid.Phase + 1;
if (next <= raid.PhaseThresholds.Length &&
raid.Boss_Hp <= raid.PhaseThresholds[next - 1])
{
raid.Phase = next;
StartPhase(raid, next);
}
}
// 페이즈 전환: 모든 참가자에게 페이즈 효과 적용
private void StartPhase(RaidInstance raid, int phase)
{
// (B) 참가자 전원에게 페이즈 효과 적용
foreach (var m in raid.Members)
{
m.ApplyPhaseEffects(phase);
m.SyncedPhase = phase;
}
}
// 입장 스레드: 지각 입장/재접속 복귀
public void OnPlayerJoin(RaidInstance raid, Player p)
{
raid.Members.Add(p);
// (C) 현재 페이즈 상태로 합류
p.SendPhaseState(raid.Phase);
p.SyncedPhase = raid.Phase;
}
// 퇴장 스레드: 사망 아웃/접속종료
public void OnPlayerLeave(RaidInstance raid, Player p)
{
raid.Members.Remove(p);
}
} 결함 코드 · C++
// ============================================================================
// [코드리뷰 문제] C++ - 레이드 페이즈 전환과 플레이어 입·퇴장 경합
// ----------------------------------------------------------------------------
// 시나리오:
// - 레이드 인스턴스는 보스 페이즈(P1 -> P2 -> P3 ...)로 진행한다. 보스 HP 가
// 임계치 아래로 내려가면 다음 페이즈로 전환하며, 전환 시 추가 몹 소환,
// 강화(enrage) 버프, 위치 리셋 같은 "페이즈 효과"를 모든 참가자에게 적용한다.
// - 전환을 검사/실행하는 것은 보스 전투 처리 스레드다(데미지 적중마다 검사).
// - 동시에 다른 스레드는 플레이어 입장(지각 입장/재접속)과 퇴장(사망/접속종료)을
// 처리해 참가자 목록을 변경한다.
// - 지각 입장한 플레이어는 "현재 페이즈" 상태로 합류해야 한다(효과 누락 시 디싱크).
//
// 요구사항:
// - 페이즈 전환은 임계치를 한 번 통과할 때 정확히 한 번만 일어나야 한다.
// - 전환 도중 입·퇴장이 일어나도 크래시/UB 없이, 새 참가자는 올바른 현재
// 페이즈로 동기화돼야 한다.
// - 페이즈 효과가 누락되거나 중복 적용되면 안 된다.
//
// 과제:
// 이 코드의 잠재적 문제를 모두 찾고, 왜/어떻게 깨지는지(동시 인터리빙 포함)
// 설명하고, 수정안과 더 나은 설계를 제시하라.
// (먼저 직접 리뷰를 적은 뒤 answer.md 와 대조할 것)
// ============================================================================
#include <cstdint>
#include <vector>
#include <algorithm>
struct Player {
int64_t id = 0;
int syncedPhase = 0; // 이 플레이어가 동기화된 페이즈
void ApplyPhaseEffects(int phase) { /* 소환 인지/enrage/위치리셋 */ }
void SendPhaseState(int phase) { /* 현재 페이즈 상태 전송 */ }
};
struct RaidInstance {
int64_t bossHp = 0;
int phase = 1;
std::vector<int> phaseThresholds; // 각 페이즈 전환 HP 임계치
std::vector<Player*> members;
};
class RaidService {
public:
// 보스 전투 스레드: 데미지 적중마다 호출
void OnBossDamaged(RaidInstance& raid, int64_t dmg) {
raid.bossHp -= dmg;
// (A) 다음 페이즈 임계치 통과 검사
int next = raid.phase + 1;
if (next <= (int)raid.phaseThresholds.size() &&
raid.bossHp <= raid.phaseThresholds[next - 1]) {
raid.phase = next;
StartPhase(raid, next);
}
}
// 입장 스레드: 지각 입장/재접속
void OnPlayerJoin(RaidInstance& raid, Player* p) {
raid.members.push_back(p);
// (C) 현재 페이즈 상태로 합류
p->SendPhaseState(raid.phase);
p->syncedPhase = raid.phase;
}
// 퇴장 스레드: 사망/접속종료
void OnPlayerLeave(RaidInstance& raid, Player* p) {
auto& v = raid.members;
v.erase(std::remove(v.begin(), v.end(), p), v.end());
}
private:
// 페이즈 전환: 모든 참가자에게 페이즈 효과 적용
void StartPhase(RaidInstance& raid, int phase) {
// (B) 참가자 전원에게 페이즈 효과 적용
for (Player* m : raid.members) {
m->ApplyPhaseEffects(phase);
m->syncedPhase = phase;
}
}
}; 내 리뷰 · C#
내 답안 · 자동 저장
작성 후 위 해설 보기에서 모범 해설과 대조하세요.
내 리뷰 · C++
내 답안 · 자동 저장
작성 후 위 해설 보기에서 모범 해설과 대조하세요.