C# - 자료구조 실습 - 인벤토리

2025. 9. 25. 00:36·C#

과제 1) 필드 생성, 간단한 메서드

  • UsableItem이라는 클래스를 만들어 이름과 가격, 수량을 프라이빗 필드로 가지게 합니다. 외부와 소통이 가능하게끔 프로퍼티도 각각 만들어 줍니다
  • UsableItem만 사용할 수 있는 특별한 메소드를 하나 자유롭게 만들어 주시기 바랍니다. 인자, 반환 형태 모두 개발자 마음대로 입니다.
  • Player라는 클래스를 만들어, 해당 아이템이 자유롭게 추가될 수 있는 inventory 라는 필드를 추가해주시길 바랍니다. (배열 or List 중 본인 편한것으로)
  • Player 클래스에, 유료결제 여부를 저장할 수 있는 필드를 하나 만듭니다. 해당 참거짓을 전환 가능한 프로퍼티 혹은 메소드도 제작 바랍니다

 

UsableItem.cs

using System;

namespace Collection
{
    class UsableItem
    {
        private string _name;
        private int _price;
        private int _count;

        public string Name
        {
            get { return _name; }
            set { _name = value; }
        }

        public int Price
        {
            get { return _price; }
            set { _price = value; }
        }

        public int Count
        {
            get { return _count; }
            set { _count = value; }
        }


        public void UseItem()
        {
            Console.WriteLine("아이템 사용!");
        }
    }
}

 

 

Player.cs

using System;
using System.Collections.Generic;

namespace Collection
{
    class Player
    {
        List<UsableItem> inventory = new List<UsableItem>();

        private bool isCashed = false;
        public bool IsCashed { get { return isCashed; } set { isCashed = value;  } }
    }
}

 

 

 

과제 2) 인덱서 or 메서드 활용, 방식 자유

  • Player에게 AddItem 이라는 메소드를 하나 만들겠습니다.
    • 인자값은 UsableItem 형 하나이고, 반환값은 없습니다.
    • 플레이어에게 있는 필드 중, 유료결제 여부가 참일 경우, 인벤토리에 아이템을 Add를 자유롭게 할 수 있고, 거짓일 경우 아이템을 최대 30개까지 저장 가능 하고, 초과로 저장하려고 시도하면 콘솔 출력을 통해 추가하지 않고 거부하는 기능을 만들어주시기 바랍니다.
  • ShowInven 이라는 메서드도 만듭니다.
    • \t 와 같은 이스케이프 시퀀스를 활용하여 보유중인 아이템을 이쁘게 출력하는 메서드를 만들어 주시기 바랍니다.

 

player.cs

using System;
using System.Collections.Generic;

namespace Collection
{
    class Player
    {
        List<UsableItem> inventory;

        private bool isCashed;
        public bool IsCashed { get { return isCashed; } set { isCashed = value;  } }

        public Player()
        {
            inventory = new List<UsableItem>();
            IsCashed = false;
        }


        public void AddItem(UsableItem item)
        {
            if (isCashed)
            {
                // Add 자유롭게
                inventory.Add(item);
            }
            else
            {
                // 아이템 최대 30개 까지만 가능. 콘솔 출력 및 등록 거절
                if (inventory.Count <= 30)
                {
                    inventory.Add(item);
                }
                else
                {
                    Console.WriteLine("최대 아이템 개수 30개가 넘었습니다. 결제하세요.");
                }
            }
        }

        public void ShowInven()
        {
            // \t와 같은 이스케이프 시퀀스를 활용해 보유중인 아이템을 이쁘게 출력하는 메서드
            Console.WriteLine("------------------ Inventory ------------------");
            Console.WriteLine("\tName\t\t\tCount\t\t\tPrice");
            foreach (UsableItem item in inventory)
            {
                Console.WriteLine(item.Name + "\t\t" + item.Count + "\t\t" + item.Price );
            }
            Console.WriteLine("-----------------------------------------------");
        }
    }
}

 

 

과제 3) Item과는 사뭇 다른 Weapon 클래스

  • Weapon 클래스 생성 후, 이름과 공격력 필드를 프라이빗으로 가지고 있게 합니다. 외부 소통이 가능하게끔 프로퍼티 또한 추가해줍니다.
  • Weapon만 사용할 수 있는 특별한 메소드를 하나 자유롭게 만들어 주시기 바랍니다. 인자, 반환 형태 모두 개발자 마음대로 입니다.
using System;

namespace Collection
{
    class Weapon
    {
        private string _name;
        private int _atk;

        public string Name { get { return _name; } set { _name = value; } }
        public int Atk { get { return _atk; } set { _atk = value; } }


        public void Attack()
        {
            Console.WriteLine($"{Name} 로 공격");
        }
    }
}

 

 

테스트

program.cs

using System;
using System.CodeDom;
using System.Collections.Generic;

namespace Collection
{
    class Program
    {
        static void Main(string[] args)
        {
            Player player = new Player();

            for (int i = 0; i < 30; i++)
            {
                player.AddItem(new UsableItem($"{i} 번째 아이템", 5, 5000));
            }

            player.ShowInven();
            player.AddItem(new UsableItem("안녕0", 1, 1000));

            Console.WriteLine("----결제 완료---");
            player.IsCashed = true;
            for (int i = 30; i < 40; i++)
            {
                player.AddItem(new UsableItem($"{i} 번째 아이템", 5, 5000));
            }
            player.ShowInven();

        }
    }
}

 

 

 

여기까지는 쉬웠는데....

 

파생 심화 과제) 리팩토링

  • Player 클래스에 Weapon들을 보유할 수 있게 하겠습니다. 이를 효율적으로 관리하기 위한 본인만의 방법을 생각해 구현해보시길 바랍니다.
    • 아이템과 무기를 따로 보유하거나, 상속을 받게 하거나, 2중 배열을 쓰거나, 인덱서를 쓰거나 인터페이스를 적용시켜도, 제네릭을 써도 무방합니다. 내부가 어떠하든 바로 아래 기능만 잘 수행하면 됩니다.
    • 추가적으로 Add메서드를 리메이크 하거나, 별도의 추가 방법을 고안하셔도 좋습니다. Weapon 관련 메서드들도 필요 시 추가합니다.
  • Player 에게 UseMyItem 이란 메서드를 하나 만듭니다.
    • 인자 및 반환값은 없습니다.
    • 실행이 되면 콘솔에 유저에게 “무기 목록을 보려면 1번, 사용 가능 아이템 목록을 보려면 2번 기입” 을 출력시키고 입력받습니다
    • 유저 입력값에 따라 “???의 목록은 다음과 같습니다” 로 출력 수행
  • 이를 테스트 하기 위해 메인에서 다양한 아이템 및 무기를 추가해보는 코드 및 출력한는 코드를 작성해봅니다.

 

 

우선 Weapon과 Item을 하나의 Inventory에서 관리할 수 있는 아이디어를 생각했다.

Item이라는 추상 클래스를 만들고, Weapon과 UsableItem을 List<Item> 에 담아 관리하기로 했다.

 

 

Item.cs

namespace Collection
{
    abstract class Item
    {
        public string Name { get; set; }

        public int Price { get; set; }

        public int Count { get; set; }

        public abstract void UseItem();
    }
}

 

 

이제 Weapon과 UsableItem이 Item 을 상속 받으면서,

둘은 UseItem이 각각 다르게 구성하고 싶었다.

무기는 사용하면 착용, Usable은 사용 이라는 출력을 내는 식으로 오버라이딩 하자.

 

 

Weapon.cs

namespace Collection
{
    class Weapon : Item
    {
        public int Atk { get; set; }

        public Weapon(string inputName, int inputPrice, int inputCount, int inputAtk)
        {
            Name = inputName;
            Price = inputPrice;
            Count = inputCount;
            Atk = inputAtk;
        }

        public override void UseItem()
        {
            Console.WriteLine($"{Name} 착용!");
        }

        public void Attack()
        {
            Console.WriteLine($"{Name} 로 공격");
        }
    }
}

 

 

UsableItem.cs

namespace Collection
{
    class UsableItem : Item
    {
        public UsableItem(string inputName, int inputPrice, int inputCount)
        {
            Name = inputName;
            Price = inputPrice;
            Count = inputCount;
        }

        public override void UseItem()
        {
            Console.WriteLine("아이템 사용!");
        }
    }
}

 

 

 

이제 Player.cs의 구성이다

요구사항과는 조금 달라졌지만 아이템을 사용하는 기능을 따로 넣어서 오버라이딩 된 UseItem을 테스트 해보고 싶었다.

ShowMyItem은 요구사항과 유사하게 구성했고,

아이템 사용 모드가 실행되는 ItemUsingMode 메서드를 만들었다.

 

 

Player.cs

using System;
using System.Collections.Generic;

namespace Collection
{
    class Player
    {
        private List<Item> inventory = new List<Item>();

        public void AddItem(Item item)
        {
            if (IsCashed)
            {
                inventory.Add(item);
            }
            else
            {
                if (inventory.Count < 30)
                {
                    inventory.Add(item);
                }
                else
                {
                    Console.WriteLine("최대 아이템 개수 30개가 넘었습니다. 결제하세요.");
                }
            }
        }

        public void ShowMyItem()
        {
            bool isInvenOn = true;
            Console.WriteLine("1. 무기 목록 조회");
            Console.WriteLine("2. 아이템 목록 조회");
            Console.WriteLine("ESC. 종료");
            while(isInvenOn)
            {
                ConsoleKeyInfo key = Console.ReadKey(true);

                switch(key.Key)
                {
                    case ConsoleKey.D1:
                        Console.WriteLine("\n [ 무기 목록 ] ");
                        for (int i = 0; i < inventory.Count; i++)
                        {
                            if (inventory[i] is Weapon weapon)
                            {
                                Console.WriteLine($"{i}. {weapon.Name} \t\t Atk: {weapon.Atk}");
                            }
                        }
                        break;
                    case ConsoleKey.D2:
                        Console.WriteLine("\n [ 아이템 목록 ] ");
                        for (int i = 0; i < inventory.Count; i++)
                        {
                            if (inventory[i] is UsableItem usableItem)
                            {
                                Console.WriteLine($"{i}. {usableItem.Name} \t\t Count: {usableItem.Count} \t\t Price: {usableItem.Price}");
                            }
                        }
                        break;
                    case ConsoleKey.Escape:
                        isInvenOn = false;
                        break;
                }
            }
        }

        public void ItemUsingMode()
        {
            Console.WriteLine("사용할 아이템의 번호를 입력후 엔터. ESC 입력 후 엔터시 종료");
            int inputNum;
            bool isUsingMode = true;
            while (isUsingMode)
            {
                string input = Console.ReadLine();

                if (input.ToUpper() == "ESC")
                {
                    isUsingMode = false;
                    Console.WriteLine("아이템 사용 모드 종료");
                    break;
                }

                if (int.TryParse(input, out inputNum))
                {
                    if(inputNum >= inventory.Count)
                    {
                        Console.WriteLine("해당 번호에 아이템이 없다");  
                    }
                    else
                    {
                        ActiveItem(inputNum);
                    }
                }
                else
                {
                    Console.WriteLine("정수를 입력하거라");    
                }
            }
        }

        public void ActiveItem(int i)
        {
            Console.WriteLine($"{i} 번째 아이템 사용!!");
            var item = inventory[i];
            item.UseItem();
        }

        public bool IsCashed { get; set; }

        public Player()
        {
            IsCashed = false;
        }

        public void ShowInven()
        {
            // \t와 같은 이스케이프 시퀀스를 활용해 보유중인 아이템을 이쁘게 출력하는 메서드
            Console.WriteLine("-------------------------- Inventory --------------------------");
            Console.WriteLine("\tName\t\t\tCount\t\t\tPrice\n");
            foreach (var item in inventory)
            {
                Console.WriteLine(item.Name + "\t\t\t" + item.Count + "\t\t\t" + item.Price );
            }
            Console.WriteLine("---------------------------------------------------------------");
        }
    }
}

 

 

코드가 조금 지저분하긴 하지만... 일단 작동 우선이니까

 

Program.cs 도 수정해서 테스트 해보자

using System;

namespace Collection
{
    class Program
    {
        static void Main(string[] args)
        {
            Player player = new Player();
            Console.WriteLine("--------------테스트 시작--------------");


            for (int i = 0; i < 25; i++)
            {
                player.AddItem(new UsableItem($"{i} 번째 아이템", 5, 5000));
            }

            for (int i = 0; i < 5; i++)
            {
                player.AddItem(new Weapon($"{i} 번째 무기", 5, 5000, 77));
            }

            player.ShowInven();
            player.AddItem(new UsableItem("초과한 무기", 1, 1000));

            Console.WriteLine("----결제 완료---");
            player.IsCashed = true;
            for (int i = 30; i < 40; i++)
            {
                player.AddItem(new UsableItem($"{i} 번째 아이템", 5, 5000));
            }
            player.ShowInven();


            Console.WriteLine("\n\n아이템 사용 테스트\n\n");

            bool isGameOn = true;
            Console.WriteLine("1. 인벤토리 열기");
            Console.WriteLine("2. 아이템 사용 모드");
            Console.WriteLine("ESC. 종료");
            while (isGameOn)
            {

                ConsoleKeyInfo key = Console.ReadKey(true);
                switch (key.Key)
                {
                    case ConsoleKey.D1:
                        player.ShowMyItem();
                        break;
                    case ConsoleKey.D2:
                        player.ItemUsingMode();
                        break;
                    case ConsoleKey.Escape:
                        Console.WriteLine("\nGood Bye\n");
                        isGameOn = false;
                        break;
                }
            }
        }
    }
}

 

 

실행 결과

 

 

 

음.. 일단 미관은 별로지만 기능은 전부 잘 작동한다

 

예외 처리도 해뒀다.

아이템 삭제 관련 기능이 없기 때문에 야근이 법칙에 따라 null 인 경우에 대한 처리는 하지 않았다.

 

지금까지 배운 내용들을 조합해야해서 생각보다 이번엔 고민을 해야했다.

단일 기능 하나에 대해서 묻는다면 쉽게 구현할 수 있는데, 내가 구조를 생각해야하는 경우에 아직까지는 미흡한 듯 하다.

갈 길이 멀었다.

'C#' 카테고리의 다른 글

C# - 스택 (Stack), 큐 (Queue)  (0) 2025.09.26
C# - BFS (너비 우선 탐색) / DFS (깊이 우선 탐색)  (0) 2025.09.25
C# - 자료구조 : Indexer, List, LinkedList  (0) 2025.09.24
C# - record  (0) 2025.09.23
C# - StringBuilder  (0) 2025.09.23
'C#' 카테고리의 다른 글
  • C# - 스택 (Stack), 큐 (Queue)
  • C# - BFS (너비 우선 탐색) / DFS (깊이 우선 탐색)
  • C# - 자료구조 : Indexer, List, LinkedList
  • C# - record
ellug
ellug
Web / App / Game Dev
  • ellug
    dev.ellug
    ellug
  • 전체
    오늘
    어제
    • 분류 전체보기 (95)
      • Javascript (React, Next) (1)
      • C# (66)
      • Graphics (1)
      • Unity (25)
      • 프로그래머스 (0)
        • Lv.0 (0)
        • Lv.1 (0)
        • Lv.2 (0)
        • Lv.3 (0)
      • AI Agent (0)
      • StableDiffusion (0)
      • ETC (1)
      • 잡담 (0)
      • 유머 (0)
  • 블로그 메뉴

    • 홈
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    알고리즘
    Queue
    최적화
    unity
    콘솔
    inputsystem
    클래스
    큐
    스택
    Network
    Design Pattern
    firebase
    C#
    네트워크
    struct
    추상 클래스
    list
    interface
    class
    Abstract
    delegate
    유니티
    터미널
    console
    게임
    자료구조
    Photon
    function
    stack
    useState
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.4
ellug
C# - 자료구조 실습 - 인벤토리
상단으로

티스토리툴바