개발일지공부아이디어
    • 3월
    • 2월
    • 1월
  • C++ 기본기 연습 프로젝트: 아이템 사전 프로그램

    26. 3. 4.

  • 03

    26. 3. 3.

  • C++ 기본기 연습 프로젝트: 카드 덱 브라우저

    26. 3. 2.

로딩 중...

C++ 기본기 연습 프로젝트: 아이템 사전 프로그램

2026. 3. 4.

1. 해시테이블 직접 구현

Pair → LinkedList(Node) → HashTable 구현

Pair.h

C++
template<typename Key, typename Value>class Pair{public:	Pair() = default;	Pair(const Key& key, const Value& value) : key(key), value(value) {}	const Key& GetKey() const { return key; }	const Value& GetValue() const { return value; }private:	Key key;	Value value;};

Node.h

C++
template<typename Key, typename Value>class LinkedList;template<typename Key, typename Value>class Node{	friend class LinkedList<Key, Value>;public:	Node(const Key& key, const Value& value) : data(key, value), next(nullptr) {}	const Pair<Key, Value>& GetData() const { return data; }	Node* GetNext() const { return next; }private:	Node* next;	Pair<Key, Value> data;};
  • 같은 파일 안이더라도 전방선언을 해줘야(line 1, 2) friend class LinkedList가 가능하다
  • 교안에선 doubly linked list로 구현돼있는데 난 단방향으로 했음

LinkedList.h

C++
template<typename Key, typename Value>class LinkedList{public:	...private:	Node<Key, Value>* head;};
  • Add()는 Node의 생성자로 동적할당한 새 노드를 헤드로 갈아끼움
C++
void Add(const Key& key, const Value& value){	Node<Key, Value>* newNode = new Node<Key, Value>(key, value);	newNode->next = head;	head = newNode;}
  • Find()는 head를 타고 내려가면서 key 대조하기
C++
Node<Key, Value>* Find(const Key& key) const{	Node<Key, Value>* current = head;	while (current)	{		if (current->data.GetKey() == key)			return current;		current = current->next;	}	return nullptr;}
  • Remove()는 링크드리스트가 1뎁스인 경우를 고려해야해서 삭제해야하는 노드가 헤든지 아닌지로 나눠줬음
C++
bool Remove(const Key& key){	// head가 삭제 대상인 경우	if (head && head->data.GetKey() == key)	{		Node<Key, Value>* toDelete = head;		head = head->next;		delete toDelete;		return true;	}	Node<Key, Value>* prev = head;	Node<Key, Value>* current = head ? head->next : nullptr;	while (current)	{		if (current->data.GetKey() == key)		{			prev->next = current->next;			delete current;			return true;		}		// 헤드와 헤드넥스트를 한칸씩 이동시켜가며 삭제 key 탐색		prev = current;		current = current->next;	}	return false;}
  • Clear()는 무작정 head부터 지우면 연결노드를 방문할 수 없기 때문에 temp 테크닉으로 살려줌
C++
void Clear(){	while (head)	{		Node<Key, Value>* temp = head;		head = head->next;		delete temp;	}}

HashTable.h

C++
class HashTable{public:	HashTable(int capacity = 101) : capacity(capacity) // 101은 소수(prime number)	{		buckets.resize(capacity);	}	~HashTable()	{		for (int i = 0; i < capacity; ++i)		{			buckets[i].Clear();		}	}		void Add(const std::string& name, const std::string& type, int value)	Item* Find(const std::string& name)	bool Remove(const std::string& name)	void List() constprivate:	int Hash(const std::string& key) const	{		unsigned int hash = 0;		for (char c : key)		{			hash = hash * 31 + c;		}		return hash % capacity;	}private:	std::vector<LinkedList<std::string, Item>> buckets;	int capacity;};
  • 해시테이블의 핵심은 private으로 감춰진 Hash()함수
  • 메시지 함수는 모두 int index = Hash(name); + ListTable API 호출이 전부임

2. 카드 브라우저 프로그램 붙이기

C++
// HashTable.hbool LoadFromFile(const std::string& filename){	std::ifstream file(filename);	if (!file.is_open())	{		return false;	}	std::string line;	std::getline(file, line); // 헤더 스킵 (name,type,value)	while (std::getline(file, line))	{		std::stringstream ss(line);		std::string name, type, valueStr;		std::getline(ss, name, ',');		std::getline(ss, type, ',');		std::getline(ss, valueStr, ',');		int value = std::stoi(valueStr);		Add(name, type, value);	}	file.close();	return true;}
  • 카드 프로그램의 Parser 그대로 가져와 HashTable.h 메시지로 붙임
C++
// HashTable.hstd::vector<Item> GetAllItems() const{	std::vector<Item> items;	for (int i = 0; i < capacity; ++i)	{		Node<std::string, Item>* current = buckets[i].GetHead();		while (current)		{			items.push_back(current->GetData().GetValue());			current = current->GetNext();		}	}	return items;}
  • LinkedList 형태로 존재하는 데이터들을 flatten해주는 함수 추가
C++
// UI.hvoid RenderUI(const std::vector<Item>& items, int selected, int offset){	system("cls");		// 왼쪽화면	Util::PutCursorOnPosition(0, 0);	std::cout << "=== 아이템 사전 (HashTable) ===\n";	std::cout << "[방향키: 이동] [ESC/Q: 명령어 모드]";		for (i = 0; i < 20; ++i)	{		int idx = (offset + i) % items.size();		// 대충 idx == selected or not 코드		std::cout << items[idx].name << " (" << items[idx].type << ")";	}		// 오른쪽 화면	if (!items.empty())	{		const Item& item = items[selected];		Util::PutCursorOnPosition(40, 3);		std::cout << "[ 아이템 상세 정보 ]";			Util::PutCursorOnPosition(40, 5);		std::cout << "Name   : " << item.name;			Util::PutCursorOnPosition(40, 6);		std::cout << "Type   : " << item.type;					Util::PutCursorOnPosition(40, 7);		std::cout << "Value  : " << item.value;	}}void CommandMode(HashTable& itemDict){	system("cls");	std::cout << "=== 명령어 모드 ===" << "\n";	// 대충 명령어 목차 코드	std::cout << "====================" << "\n" << "\n";		std::string line;	while (true)	{		std::cout << "> ";		std::getline(std::cin, line);			std::stringstream ss(line);		std::string command;		ss >> command;			if (command == "add")		{			if (ss >> name >> type >> value)			{				itemDict.Add(name, type, value);			}		}		else if (command == "find")		{			ss >> name;			Item* item = itemDict.Find(name);		}		else if (command == "remove")		{			ss >> name;			if (itemDict.Remove(name))			else		}		else if (command == "list")		{			itemDict.List();		}		else if (command == "ui")		{			return; // UI 모드로 복귀		}		else if (command == "exit")		{			exit(0);		}		else		{			std::cout << "알 수 없는 명령어입니다." << "\n";		}	}}
  • 아이템 사전 순회 모드(UI 모드)용 RenderUI(), 아이템 사전 수정 모드용 CommandMode() 분리

그래픽스 프로그래밍

  • StaticMesh
    • mesh ↔ shader 1:1 구조
    • StaticMesh 안에 여러 하위 Mesh 배열이 생김
    • 게임에선 Material을 최대한 줄이는게 좋음(초당 60번 렌더 - 셰이더를 줄여야 함)
  • Renderer::Submit
    • Actor는 mesh와 shader를 전달만 하고
    • Renderer는 전달받은 mesh와 shader를 그리기만 함
  • template<typename T, typename std::enable_if_t<std::is_base_of<Level, T>::value>>
    • SFINAE(Substitution Failure Is Not An Error): 어려운 면접 문제에 간혹 등장
    • 특정 타입을 부모로 강제하고 싶은데 템플릿 환경일 때의 방법 질문
      • std::is_base_of 를 활용하는 것이 1차 답변 (살짝 부족)
      • std::enable_if / std::enable_if_t 접목해서 의도적으로 템플릿 해석 실패하도록 유도해서 구문 오류가 발생하도록 하는 방법
  • std::enable_shared_from_this
  • Material == Shader + 속성(숫자값, 텍스처, ...)
  • 셰이더를 미리 컴파일해서 .cso로 만들어놓고 vertexShaderObject로 가져와서 런타임에 사용(상용 엔진)
  • 고도화: 리소스매니저 계층에서 딱 하나만 만들고 주소 공유
왼쪽 화살표03다음 글이 없습니다.