38. 크래프팅 다중 재료 슬롯 동시 소모 (검사-차감 비원자)

난이도 중 해설 보기 →

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

결함 코드 · C#
// [시나리오] MMORPG 아이템 제작(크래프팅) — 여러 재료 슬롯 동시 소모 (서버-클라)
// 제작 레시피는 서로 다른 인벤토리 슬롯에 담긴 여러 재료(예: 슬롯3에 "철광석" 5개,
// 슬롯7에 "가죽" 2개)를 동시에 요구한다. 제작 요청이 들어오면 각 재료 슬롯의 보유
// 수량을 먼저 모두 검사한 뒤, 검사를 통과하면 슬롯별로 순서대로 수량을 차감하고
// 완성품을 지급한다. 같은 플레이어가 매크로/더블클릭 등으로 같은 레시피를
// 짧은 간격으로 여러 번 요청할 수 있고, 각 요청은 네트워크 스레드풀의 서로 다른
// 워커에서 병렬로 처리된다.
//
// [요구사항]
//   - 각 재료 슬롯에서 실제로 차감되는 총량은 그 슬롯의 보유량을 넘어설 수 없다
//     (슬롯 수량은 음수가 될 수 없다).
//   - 제작 1회는 레시피가 요구하는 모든 재료를 "전부 차감하거나 전부 차감하지
//     않거나" 둘 중 하나여야 한다(일부만 차감된 채 남으면 안 된다).
//
// [과제] CraftingHandler.OnCraft 를 검토하고, 같은 플레이어가 같은 레시피를 동시에
//        여러 번 요청할 때 위 요구사항이 어떻게 어긋날 수 있는지 원인과 수정안을
//        제시하라. 표시된 (A)(B) 지점에 주목하라.

using System;
using System.Collections.Generic;

class InventorySlot
{
    public int SlotId;
    public string ItemId;
    public int Quantity;
}

class Recipe
{
    public string ResultItemId;
    // (슬롯 인덱스, 필요 수량)
    public List<(int SlotId, int NeedQty)> Ingredients;
}

class CraftingHandler
{
    // playerId -> (slotId -> 슬롯)
    private readonly Dictionary<int, Dictionary<int, InventorySlot>> _inventories = new();

    private Dictionary<int, InventorySlot> GetInventory(int playerId) => _inventories[playerId];

    private void GrantResult(int playerId, string itemId) { /* 완성품 지급 */ }

    // 여러 워커 스레드에서 동시에 호출된다 (같은 playerId 로도 동시에 들어올 수 있음).
    public bool OnCraft(int playerId, Recipe recipe)
    {
        var inv = GetInventory(playerId);

        // (A)
        foreach (var (slotId, needQty) in recipe.Ingredients)
        {
            if (!inv.TryGetValue(slotId, out var slot) || slot.Quantity < needQty)
                return false;
        }

        // (B)
        foreach (var (slotId, needQty) in recipe.Ingredients)
        {
            var slot = inv[slotId];
            slot.Quantity -= needQty;
        }

        GrantResult(playerId, recipe.ResultItemId);
        return true;
    }
}
내 리뷰 · C#
내 답안 · 자동 저장

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