9. 아이템 강화(인챈트) 원자성과 실패 처리

난이도 상 해설 보기 →

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

결함 코드 · C#
// ============================================================================
// [코드리뷰 문제] C# - 아이템 강화(인챈트) 원자성과 실패 처리
// ----------------------------------------------------------------------------
// 시나리오:
//   - 장비를 강화한다. 강화에는 소재(stone)와 골드가 든다.
//   - 강화는 확률적으로 성공/실패한다. 성공하면 +1, 실패하면 단계 유지 또는
//     하락(정책에 따라). 어느 쪽이든 소재와 골드는 소모된다(시도 비용).
//   - 강화 결과 연출을 위해 클라이언트가 "성공/실패" 와 굴림값을 함께 보낸다
//     (클라가 먼저 연출을 돌리고 결과를 서버에 통보하는 구조).
//   - 여러 IO 스레드가 같은 플레이어의 강화 패킷을 처리할 수 있다.
//
// 요구사항:
//   - 강화는 원자적이어야 한다: (소재/골드 소모 + 단계 변경)이 함께 일어나거나
//     전혀 일어나지 않거나.
//   - 소재/골드가 부족하면 아무것도 변하지 않아야 한다.
//   - 성공/실패 결과는 서버가 권위 있게 결정해야 한다(조작 불가).
//
// 과제:
//   이 코드의 잠재적 문제를 모두 찾고, 왜 문제인지 설명하고,
//   수정안과 더 나은 설계를 제시하라.
//   (먼저 직접 리뷰를 적은 뒤 answer.md 와 대조할 것)
// ============================================================================

using System;
using System.Collections.Generic;

public class Equip
{
    public long Uid;
    public int  Level;        // 강화 단계
}

public class Player
{
    public long Id;
    public long Gold;
    public int  EnchantStones;                       // 강화석 보유 수
    public Dictionary<long, Equip> Equips = new();
    public readonly object Lock = new object();
}

public class EnchantRequest
{
    public long EquipUid;
    public bool ClientSuccess;                        // (A) 클라가 보낸 성공 여부
    public int  ClientRoll;                           // (B) 클라가 보낸 굴림값(0..9999)
}

public class EnchantService
{
    // 강화 처리. 성공하면 true 반환.
    public bool Enchant(Player p, EnchantRequest req)
    {
        lock (p.Lock)
        {
            Equip e = p.Equips[req.EquipUid];         // (C)

            int  stoneCost = e.Level + 1;             // 단계 비례 비용
            long goldCost  = (long)(e.Level + 1) * 1000;

            // (D) 소재/골드 먼저 소모
            p.EnchantStones -= stoneCost;
            p.Gold          -= goldCost;

            // (E) 결과 적용
            if (req.ClientSuccess)
            {
                e.Level += 1;                         // (F) 성공 → 단계 상승
            }
            else
            {
                // 실패 → 단계 유지(정책)
            }

            // (G) 부족했는지 사후 확인
            if (p.EnchantStones < 0 || p.Gold < 0)
                return false;

            return true;
        }
    }
}
내 리뷰 · C#
내 답안 · 자동 저장

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