과제 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 |