2. 인벤토리 스택/수량 관리
난이도 중 해설 보기 →
결함을 모두 찾고 원인·수정안·더 나은 설계를 제시하라. 마커
(A)(B) 는 주목 위치 힌트다.
결함 코드 · C#
// ============================================================================
// [코드리뷰 문제] C# - 인벤토리 스택/수량 관리
// ----------------------------------------------------------------------------
// 시나리오:
// - 플레이어 인벤토리는 슬롯 배열이다. 각 슬롯에는 (itemId, count) 가 있다.
// - 같은 itemId 끼리는 한 슬롯으로 합칠 수 있다(스택). 스택 상한은 999.
// - 아이템 획득(AddItem), 두 슬롯 합치기(MergeStacks),
// 사용/판매로 수량 차감(RemoveCount) 을 지원한다.
// - amount 는 서버 로직이 넘기는 값이다. 예: 레이드 보상 일괄 지급으로
// 같은 소재 아이템을 한 번에 5000 개 지급(AddItem(itemId, 5000)),
// 상점에서 묶음 판매로 한 번에 차감 등 "정상 도메인" 입력이 들어온다.
//
// 요구사항:
// - 여러 게임 스레드가 같은 인벤토리에 동시에 접근할 수 있다(전투 보상 +
// 상점 구매가 동시에 들어옴).
// - 한 스택 수량은 1..999 범위를 벗어날 수 없다(상한 강제).
// - 인벤토리 전체 아이템 개수(서버 보유량)는 잘못 늘거나 줄어선 안 된다.
//
// 과제:
// 이 코드의 잠재적 문제를 모두 찾고, 왜 문제인지 설명하고,
// 수정안과 더 나은 설계를 제시하라.
// (먼저 직접 리뷰를 적은 뒤 answer.md 와 대조할 것)
// ============================================================================
using System;
public struct Slot
{
public uint ItemId; // 0 = 빈 슬롯
public ushort Count; // (A)
}
public class Inventory
{
private const ushort MAX_STACK = 999;
private readonly Slot[] _slots;
private readonly object _lock = new object();
public Inventory(int slotCount) { _slots = new Slot[slotCount]; }
// 슬롯 하나를 조회(UI 표시 등에서 사용)
public Slot GetSlot(int index)
{
lock (_lock)
{
return _slots[index]; // (B) 값 복사 반환
}
}
// 아이템 획득: 같은 itemId 슬롯이 있으면 거기에 더하고, 없으면 빈 슬롯에 생성
public bool AddItem(uint itemId, ushort amount)
{
lock (_lock)
{
for (int i = 0; i < _slots.Length; i++)
{
if (_slots[i].ItemId == itemId)
{
_slots[i].Count += amount; // (C)
return true;
}
}
for (int i = 0; i < _slots.Length; i++)
{
if (_slots[i].ItemId == 0)
{
_slots[i].ItemId = itemId;
_slots[i].Count = amount; // (D)
return true;
}
}
return false; // 인벤토리 가득 참
}
}
// 두 슬롯 합치기: src 의 수량을 dst 로 옮긴다(같은 아이템이라고 가정)
public bool MergeStacks(int src, int dst)
{
lock (_lock)
{
Slot a = _slots[src]; // (E) 값 복사
Slot b = _slots[dst];
ushort total = (ushort)(a.Count + b.Count); // (F)
if (total <= MAX_STACK)
{
b.Count = total;
a.ItemId = 0;
a.Count = 0;
}
else
{
b.Count = MAX_STACK;
a.Count = (ushort)(total - MAX_STACK); // (G)
}
_slots[src] = a;
_slots[dst] = b;
return true;
}
}
// 수량 차감(사용/판매)
public bool RemoveCount(int slot, ushort amount)
{
lock (_lock)
{
_slots[slot].Count -= amount; // (H)
if (_slots[slot].Count == 0)
_slots[slot].ItemId = 0;
return true;
}
}
} 결함 코드 · C++
// ============================================================================
// [코드리뷰 문제] C++ - 인벤토리 스택/수량 관리
// ----------------------------------------------------------------------------
// 시나리오:
// - 플레이어 인벤토리는 슬롯 배열이다. 각 슬롯에는 (itemId, count) 가 있다.
// - 같은 itemId 끼리는 한 슬롯으로 합칠 수 있다(스택). 스택 상한은 999.
// - 아이템 획득(AddItem), 두 슬롯 합치기(MergeStacks),
// 사용/판매로 수량 차감(RemoveCount) 을 지원한다.
// - amount 는 서버 로직이 넘기는 값이다. 예: 레이드 보상 일괄 지급으로
// 같은 소재 아이템을 한 번에 5000 개 지급(AddItem(itemId, 5000)),
// 상점에서 묶음 판매로 한 번에 차감 등 "정상 도메인" 입력이 들어온다.
//
// 요구사항:
// - 여러 게임 스레드가 같은 인벤토리에 동시에 접근할 수 있다(전투 보상 +
// 상점 구매가 동시에 들어옴).
// - 한 스택 수량은 1..999 범위를 벗어날 수 없다(상한 강제).
// - 인벤토리 전체 아이템 개수(서버 보유량)는 잘못 늘거나 줄어선 안 된다.
//
// 과제:
// 이 코드의 잠재적 문제를 모두 찾고, 왜 문제인지 설명하고,
// 수정안과 더 나은 설계를 제시하라.
// (먼저 직접 리뷰를 적은 뒤 answer.md 와 대조할 것)
// ============================================================================
#include <cstdint>
#include <vector>
#include <mutex>
constexpr uint16_t MAX_STACK = 999;
struct Slot {
uint32_t itemId = 0; // 0 = 빈 슬롯
uint16_t count = 0; // (A)
};
class Inventory {
public:
explicit Inventory(size_t slotCount) : slots_(slotCount) {}
// 아이템 획득: 같은 itemId 슬롯이 있으면 거기에 더하고, 없으면 빈 슬롯에 생성
bool AddItem(uint32_t itemId, uint16_t amount) {
std::lock_guard<std::mutex> lk(mtx_);
for (auto& s : slots_) {
if (s.itemId == itemId) {
s.count += amount; // (B)
return true;
}
}
for (auto& s : slots_) {
if (s.itemId == 0) {
s.itemId = itemId;
s.count = amount; // (C)
return true;
}
}
return false; // 인벤토리 가득 참
}
// 두 슬롯 합치기: src 의 수량을 dst 로 옮긴다(같은 아이템이라고 가정)
bool MergeStacks(size_t src, size_t dst) {
std::lock_guard<std::mutex> lk(mtx_);
Slot& a = slots_[src]; // (D)
Slot& b = slots_[dst];
uint16_t total = a.count + b.count; // (E)
if (total <= MAX_STACK) {
b.count = total;
a.itemId = 0;
a.count = 0;
} else {
b.count = MAX_STACK;
a.count = total - MAX_STACK; // (F)
}
return true;
}
// 수량 차감(사용/판매)
bool RemoveCount(size_t slot, uint16_t amount) {
std::lock_guard<std::mutex> lk(mtx_);
Slot& s = slots_[slot];
s.count -= amount; // (G)
if (s.count == 0)
s.itemId = 0;
return true;
}
private:
std::vector<Slot> slots_;
std::mutex mtx_;
}; 내 리뷰 · C#
내 답안 · 자동 저장
작성 후 위 해설 보기에서 모범 해설과 대조하세요.
내 리뷰 · C++
내 답안 · 자동 저장
작성 후 위 해설 보기에서 모범 해설과 대조하세요.