오늘의 할일
1. 코드카타 정리
3. 과제
4. 궁금증 해결
정수 n의 각 자릿수를 큰 것부터 작은 순으로 정렬한 새로운 정수를 리턴, 예를 들어 n이 118372면 873211을 리턴
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
bool compare(char a, char b) {
return a > b;
}
long long solution(long long n) {
long long answer = 0;
string s = to_string(n);
sort(s.begin(), s.end(), compare);
answer = stoll(s);
return answer;
}
#pragma once
#include <iostream>
#include <string>
#include <algorithm> //sort 때문에 추가
using namespace std;
template<typename T>
class Inventory {
private:
T* pItems_;
int capacity_;
int size_;
public:
Inventory(int capacity = 10) : capacity_(capacity), size_(0) {
pItems_ = new T[capacity_];
}
~Inventory() {
delete[] pItems_;
}
Inventory(const Inventory<T>& other) : capacity_(other.capacity_), size_(other.size_) {
pItems_ = new T[capacity_];
for (int i = 0; i < size_; i++) {
pItems_[i] = other.pItems_[i];
}
}
Inventory<T>& operator=(const Inventory<T>& other) {
if (this == &other) return *this;
delete[] pItems_;
capacity_ = other.capacity_;
size_ = other.size_;
pItems_ = new T[capacity_];
for (int i = 0; i < size_; i++) {
pItems_[i] = other.pItems_[i];
}
return *this;
}
int GetSize() const { return size_; }
int GetCapacity() const { return capacity_; }
//추가
void Resize(int newCapacity) {
if (newCapacity <= capacity_) return;
T* newItems = new T[newCapacity];
for (int i = 0; i < size_; i++) {
newItems[i] = pItems_[i];
}
delete[] pItems_;
pItems_ = newItems;
int oldCapacity = capacity_;
capacity_ = newCapacity;
cout << "-> Inventory auto-expanded! (" << oldCapacity << " -> " << capacity_ << ")" << endl;
}
//수정
bool AddItem(const T& item) {
if (size_ >= capacity_) {
cout << "Adding item... (" << size_ << "/" << capacity_ << " full)" << endl;
Resize(capacity_ * 2);
}
pItems_[size_] = item;
size_++;
cout << "-> Item added" << endl << endl;
return true;
}
void RemoveLastItem() {
if (size_ > 0) {
size_--;
}
else {
cout << "Inventory is already empty!" << endl;
}
}
void RemoveItemAt(int index) {
if (index < 0 || index >= size_) return;
for (int i = index; i < size_ - 1; i++) {
pItems_[i] = pItems_[i + 1];
}
size_--;
}
T& operator[](int index) {
return pItems_[index];
}
const T& operator[](int index) const {
return pItems_[index];
}
void PrintAllItems() const {
if (size_ == 0) {
cout << "The inventory is empty." << endl;
return;
}
for (int i = 0; i < size_; i++) {
cout << (i + 1) << ". ";
pItems_[i].PrintItem();
}
}
//추가
void SortItems(bool (*compareFunc)(const T&, const T&)) {
if (size_ <= 1) return;
sort(pItems_, pItems_ + size_, compareFunc);
}
};
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include "Player.h"
#include "Warrior.h"
#include "Mage.h"
#include "Rogue.h"
#include "Archer.h"
#include "Monster.h"
#include "Inventory.h"
using namespace std;
string name;
const int SIZE = 4;
int playerstat[SIZE] = { 0 };
// {HP, MP, 공격력, 방어력}
int PotionHP = 0;
int PotionMP = 0;
int choice;
bool isGameStart = false;
struct Item {
string name;
int price = 0;
void PrintItem() const {
cout << name << " (" << price << "G)" << endl;
}
};
//추가
bool compareByPrice(const Item& a, const Item& b) {
return a.price < b.price;
}
Inventory<Item> inventory(10);
struct PotionRecipe {
string potionName;
string ingredient1;
string ingredient2;
void PrintRecipe() const {
cout << "-> " << potionName << " : " << ingredient1 << " x1, " << ingredient2 << " x1" << endl;
}
};
vector<PotionRecipe> recipes = {
{"HPPotion", "Herb", "Clear Water"},
{"MPPotion", "Slime Jelly", "Clear Water"},
{"StaminaPotioin", "Herb", "Berry"}
};
void printTitle()
{
cout << "===========================================" << endl;
cout << " [ Dungeon Escape Text RPG ]" << endl;
cout << "===========================================" << endl;
}
void statsMenu()
{
cout << "===========================================" << endl;
cout << " " << name << "'s Stats" << endl;
cout << "===========================================" << endl;
cout << "HP: " << playerstat[0] << " MP: " << playerstat[1] << endl;
cout << "Attack: " << playerstat[2] << " Defense: " << playerstat[3] << endl;
cout << endl;
}
Player* createCharacter(string name, int playerstat[]) {
cout << "< Job Selection >" << endl;
cout << name << ", choose your job!" << endl;
cout << "1. Warrior 2. Mage 3. Rogue 4. Archer" << endl;
cout << "Choose: ";
int jobChoice;
cin >> jobChoice;
Player* player = nullptr;
switch (jobChoice) {
case 1:
cout << endl;
player = new Warrior(name, playerstat[0], playerstat[1], playerstat[2], playerstat[3]);
break;
case 2:
cout << endl;
player = new Mage(name, playerstat[0], playerstat[1], playerstat[2], playerstat[3]);
break;
case 3:
cout << endl;
player = new Rogue(name, playerstat[0], playerstat[1], playerstat[2], playerstat[3]);
break;
case 4:
cout << endl;
player = new Archer(name, playerstat[0], playerstat[1], playerstat[2], playerstat[3]);
break;
default:
cout << endl;
player = new Warrior(name, playerstat[0], playerstat[1], playerstat[2], playerstat[3]);
break;
}
return player;
}
Player* statsCustom()
{
Player* player = nullptr;
while (!isGameStart) {
cout << "===========================================" << endl;
cout << " < Character Upgrade >" << endl;
cout << "1. HP UP 2. MP UP 3. Attack x2" << endl;
cout << "4. Defense x2 5. Show Stats 0. Jop Select & Start Game" << endl;
cout << "===========================================" << endl;
cout << "Choose : ";
cin >> choice;
cout << endl;
switch (choice) {
case 0:
system("cls");
printTitle();
cout << endl;
player = createCharacter(name, playerstat);
cout << endl;
cout << "Starting the game!" << endl;
cout << endl;
cout << " /| ________________" << endl;
cout << " O|===|* >________________>" << endl;
cout << " ||" << endl;
cout << endl << endl;
isGameStart = true;
break;
case 1:
if (PotionHP == 0)
{
cout << "No potions left!" << endl;
cout << endl;
break;
}
cout << "* HP increased by 20. (HP Potion used: " << PotionHP - 1 << " left)" << endl;
PotionHP -= 1;
playerstat[0] += 20;
cout << endl;
break;
case 2:
if (PotionMP == 0)
{
cout << "No potions left!" << endl;
cout << endl;
break;
}
cout << "* MP increased by 20. (MP Potion used: " << PotionMP - 1 << " left)" << endl;
PotionMP -= 1;
playerstat[1] += 20;
cout << endl;
break;
case 3:
cout << "* Attack multiplied by 2." << endl;
playerstat[2] *= 2;
cout << endl;
break;
case 4:
cout << "* Defense multiplied by 2." << endl;
playerstat[3] *= 2;
cout << endl;
break;
case 5:
system("cls");
printTitle();
cout << endl;
statsMenu();
break;
default:
cout << "Please choose another number." << endl;
cout << endl;
break;
}
}
return player;
}
void enterStats()
{
while (true)
{
cout << "Enter HP and MP: ";
cin >> playerstat[0];
cin >> playerstat[1];
if (playerstat[0] < 50 || playerstat[1] < 50)
{
cout << "HP or MP is too low. Try again." << endl;
}
else {
break;
}
}
while (true)
{
cout << "Enter Attack and Defense: ";
cin >> playerstat[2];
cin >> playerstat[3];
if (playerstat[2] < 50 || playerstat[3] < 50)
{
cout << "Attack or Defense is too low. Try again." << endl;
}
else {
break;
}
}
}
void startBattle(Player* player, Monster& monster) {
cout << endl;
cout << " [ Battle Start! ] " << player->getName() << "(" << player->getJob() << ") vs " << monster.getName() << endl;
cout << endl;
while (player->getHp() > 0 && monster.getHp() > 0) {
cout << "--- Player Turn ---" << endl;
cout << "1. Attack" << endl;
cout << "2. Use Item" << endl;
cout << "Choose: ";
int turnChoice;
cin >> turnChoice;
cout << endl;
if (turnChoice == 2) {
cout << "[ Inventory ]" << endl;
if (inventory.GetSize() == 0) {
cout << "The inventory is empty!" << endl << endl;
}
else {
for (int i = 0; i < inventory.GetSize(); i++) {
cout << (i+1) << ". " << inventory[i].name << " (" << inventory[i].price << "G)" << endl;
}
cout << "0. Cancel" << endl;
cout << "Choose item: ";
int itemChoice;
cin >> itemChoice;
cout << endl;
if (itemChoice > 0 && itemChoice <= inventory.GetSize()) {
int idx = itemChoice - 1;
string itemName = inventory[idx].name;
if (itemName == "HPPotion" || itemName == "HP Potion") {
int oldHp = player->getHp();
player->setHp(min(oldHp + 50, player->getMaxHp()));
cout << "* " << itemName << " used! HP restored by 50 (" << oldHp << " -> " << player->getHp() << ")" << endl << endl;
inventory.RemoveItemAt(idx);
}
else if (itemName == "MPPotion" || itemName == "MP Potion") {
int oldMp = player->getMp();
player->setMp(min(oldMp + 50, player->getMaxMp()));
cout << "* " << itemName << " used! MP restored by 50 (" << oldMp << " -> " << player->getMp() << ")" << endl << endl;
inventory.RemoveItemAt(idx);
}
else {
cout << "You cannot use this item in battle." << endl << endl;
}
}
else if (itemChoice == 0) {
cout << "Canceled item use." << endl << endl;
continue;
}
else {
cout << "Invalid item number!" << endl << endl;
}
}
}
else {
player->attack(&monster);
}
if (monster.getHp() <= 0) {
cout << " (Dead) ";
cout << endl << endl;
cout << "★ Victory!" << endl;
player->gainExp(monster.getExpReward());
cout << endl;
cout << " -> Got: " << monster.getDropItemName() << "!" << endl;
cout << " -> Saved to inventory." << endl << endl;
Item droppedItem;
droppedItem.name = monster.getDropItemName();
droppedItem.price = monster.getDropItemPrice();
inventory.AddItem(droppedItem);
break;
}
cout << endl << endl;
cout << "--- Monster Turn ---" << endl;
monster.attack(player);
int monsterDamage = monster.getPower() - player->getDefence();
if (monsterDamage <= 0) {
monsterDamage = 1;
}
int playerOldHp = player->getHp();
player->setHp(playerOldHp - monsterDamage);
cout << monsterDamage << " damage to " << player->getName() << "!" << endl;
cout << player->getName() << " HP : " << playerOldHp << " -> " << player->getHp();
cout << endl << endl;
if (player->getHp() <= 0) {
cout << " (Dead) " << endl;
cout << endl;
cout << " Game Over..." << endl;
break;
}
}
}
void AlchemyWorkshop() {
int ChoiceShop;
while (true) {
cout << "=== Potion Shop ===" << endl;
cout << "1. Show all recipes" << endl;
cout << "2. Search by potion name" << endl;
cout << "3. Search by ingredient" << endl;
cout << "0. Go back" << endl;
cout << endl;
cout << "Choose : ";
cin >> ChoiceShop;
cout << endl;
switch (ChoiceShop) {
case 0:
system("cls");
printTitle();
return;
case 1:
for (const PotionRecipe& PR : recipes) {
PR.PrintRecipe();
}
cout << endl;
break;
case 2:
{
string searchName;
cout << "Search potion name: ";
cin.ignore();
getline(cin, searchName);
bool isFound = false;
for (const PotionRecipe& PR : recipes) {
if (PR.potionName == searchName) {
PR.PrintRecipe();
isFound = true;
break;
}
}
if (!isFound) {
cout << "It cannot be found." << endl;
}
cout << endl;
break;
}
case 3: {
string searchIngredient;
cout << "Search ingredient: ";
cin.ignore();
getline(cin, searchIngredient);
int count = 0;
for (const PotionRecipe& PR : recipes) {
if (PR.ingredient1 == searchIngredient || PR.ingredient2 == searchIngredient)
{
PR.PrintRecipe();
count++;
}
}
if (count == 0) {
cout << "It cannot be found." << endl;
}
else {
cout << "Found " << count << " recipes." << endl;
}
cout << endl;
break;
}
default:
cout << "Please choose another number." << endl << endl;
break;
}
}
}
// 2번 수정, 4번 추가
void mainMenu(Player* player)
{
int choiceMenu;
while (true) {
cout << "=== Main Menu ===" << endl;
cout << "1. Enter Dungeon" << endl;
cout << "2. Check Inventory" << endl;
cout << "3. Potion Shop" << endl;
cout << "4. Sort Inventory (by Price)" << endl;
cout << "0. Quit" << endl;
cout << endl;
cout << "Choose : ";
cin >> choiceMenu;
cout << endl;
switch (choiceMenu) {
case 0:
system("cls");
printTitle();
cout << "Exit Game.." << endl;
return;
case 1:
{
Monster slime("Slime", 30, 20, 10, "Slime Jelly", 30, 30);
Monster professor("Professor", 40, 30, 10, "paper", 30, 70);
startBattle(player, slime);
startBattle(player, professor);
if (player->getHp() <= 0) {
return;
}
break;
}
case 2:
system("cls");
printTitle();
cout << "[ Inventory (" << inventory.GetSize() << "/" << inventory.GetCapacity() << ") ]" << endl;
inventory.PrintAllItems();
cout << endl;
break;
case 3:
system("cls");
printTitle();
AlchemyWorkshop();
break;
case 4:
system("cls");
printTitle();
if (inventory.GetSize() == 0) {
cout << "The inventory is empty." << endl << endl;
}
else {
inventory.SortItems(compareByPrice);
cout << "[ Inventory sorted by price ]" << endl;
inventory.PrintAllItems();
cout << endl;
}
break;
default:
cout << "Please choose another number." << endl << endl;
break;
}
}
}
void setPotion(int count, int* p_HPPotion, int* p_MPPotion) {
*p_HPPotion = count;
*p_MPPotion = count;
}
int main() {
printTitle();
cout << "Enter your hero's name: ";
cin >> name;
cout << endl;
enterStats();
system("cls");
printTitle();
statsMenu();
setPotion(5, &PotionHP, &PotionMP);
cout << "* You received " << PotionHP << " HP Potions and " << PotionMP << " MP Potions." << endl;
Player* player = statsCustom();
player->printPlayerStatus();
mainMenu(player);
delete player;
return 0;
}
자동 확장 (Resize):
기존 메모리보다 2배 큰 방을 new로 새로 파서 이사시킨 후, 옛날 방은 delete[]로 부수는 방식
정렬 (SortItems):
sort(시작주소, 끝주소, 비교함수)는 정렬(Introsort 알로기즘). pItems 포인터는 배열의 시작 주소/ size를 더한 pItems + size는 배열의 끝 주소
1
Q. malloc?
malloc : 메모리 임대차 계약{Memory Allocation(메모리 할당)}
-> 프로그램이 실행되는 도중에(Runtime), 필요한 만큼의 메모리 공간을 운영체제(OS)로부터 빌려오는 함수
정적 할당 (int arr[100];): 프로그램 시작 전에 "나 방 100개 필요해!"라고 미리 못 박아두는 것. (도중에 크기 변경 불가, 낭비 발생)
동적 할당 (malloc): 게임을 실행하다가 몬스터가 10마리 나타나면 10마리분, 1000마리 나타나면 1000마리분만큼 그때그때 실시간으로 방을 계약해서 빌리는 것
malloc의 기본 문법과 3대 필수 요소 -
malloc을 쓰려면 <stdlib.h> (C++에서는 <cstdlib>) 헤더가 필요
int* ptr = (int*)malloc(sizeof(int) * 10);
① 원하는 용량 계산 : sizeof(타입) 개수
malloc은 컴파일러처럼 똑똑하지 않아서 우리가 무슨 타입을 담을지 모름. 오직 "몇 바이트(Byte)를 빌려줄까?"만 물어봄.
-> 직접 sizeof(int) 10 (4바이트 × 10개 = 40바이트)처럼 정확한 바이트 크기를 계산해서 전달해야 함
② 타입 캐스팅 (형변환) : (int)
malloc은 방을 빌려준 뒤, 그 방의 주소를 void (아무 형태도 정해지지 않은 포인터)로 반환.
-> "이 방은 정수(int)들을 담을 방이야!"라고 명시적으로 (int*) 형변환(Casting) 해주기
③ 해제는 반드시 free()!
C++에 new가 있으면 delete가 있듯, C 언어에서 malloc으로 빌린 메모리는 free(ptr); 함수로 반드시 반환해야 함. 안 그러면 프로그램이 종료될 때까지 메모리를 계속 잡아먹는 메모리 누수(Memory Leak)가 발생함
#include <stdio.h>
#include <stdlib.h> // 💡 malloc과 free를 쓰기 위한 필수 헤더
int main() {
int size = 5;
// 1. int형 데이터 5개를 담을 수 있는 메모리(20바이트) 할당
int* arr = (int*)malloc(sizeof(int) * size);
// 2. 안전장치: 메모리가 부족해서 할당에 실패하면 NULL을 반환
if (arr == NULL) {
printf("메모리 할당 실패!\n");
return -1;
}
// 3. 일반 배열처럼 똑같이 사용 가능
for (int i = 0; i < size; i++) {
arr[i] = (i + 1) * 10;
printf("%d ", arr[i]); // 출력: 10 20 30 40 50
}
// 4. 사용이 끝난 메모리는 반드시 운영체제에 반납
free(arr);
// 5. 실무 꿀팁: 반납 후 포인터를 비워주어 허공을 가리키지 않게 함 (댕글링 포인터 방지)
arr = NULL;
return 0;
}
C언어 malloc vs C++ new 차이점

malloc 사용 시 절대 지켜야 할 3가지 주의점
💡 요약
malloc -> 내가 원하는 바이트(Byte) 크기만큼 메모리를 날것 그대로 빌려오는 C 언어의 강력한 원시 도구