no image
내일배움캠프 15일차 TIL [TextRPG 팀프로젝트]
🗓️ 오늘 하루 일정✅ 오전09:00 ~ 13:00 : 프로젝트 작업직업별 스킬 시스템 구조 리팩토링 (SkillSet 인터페이스 기반)UseSkill 메서드 구조 변경 및 범위 공격 구현장착 시스템 FinalAtk, FinalDef 구조 반영 확인회피 확률 → 민첩 기반으로 재설계 (DodgeChance 동적 계산)🍽️ 점심시간13:00 ~ 14:00 : 점심시간✅ 오후14:00 ~ 18:00 : 팀 프로젝트 발표 준비발표용 코드 정리 및 구조 설명 작성몬스터 다수 공격 시 HP 변화 출력 개선 (prevHpDict)트러블슈팅 정리직업 클래스 구조 단순화 이슈 → 해결 과정퀘스트 클래스 역할 분리 이슈 → 해결 과정발표용 PPT 구성 요소 정리 및 작성 시작🍽️ 저녁시간18:00 ~ 19:00 :..
2025.07.18
no image
내일배움캠프 13일차 TIL [예비군 훈련 + 팀프로젝트 직업 밸런스+스킬 추가]
🗓️ 2025년 7월 16일 (수) – 오늘의 일정✅ 오전 & 오후09:00 ~ 18:00 : 예비군 훈련🍽️ 저녁시간18:00 ~ 19:00 : 저녁 식사🧘 개인시간19:00 ~ 20:00 : 개인 휴식🛠️ 팀 프로젝트 개발20:00 ~ 00:00 : 텍스트 RPG 직업 설계 및 스킬 개발직업 능력치 정리 및 보정 적용전사, 마법사, 도적, 궁수, 해적 클래스 정리각 직업별 스킬 3종 설계 및 코드 구현✅ 오늘 학습 키워드직업 클래스 설계 리팩터링능력치 자동 계산 구조 (계산 프로퍼티 활용)직업별 특성 기반 능력치 보정직업별 스킬 구조 설계 및 구현추상 메서드 오버라이드 구조✅ 오늘 학습 한 내용을 나만의 언어로 정리하기오늘은 텍스트 RPG 프로젝트에서 직업 시스템과 전투 스킬 구조를 본격적으로..
2025.07.16
no image
내일배움캠프 12일차 TIL [예비군 훈련 + 팀프로젝트 퀘스트내용 개발]
🗓️ 오늘 하루 일정 (2025년 7월 15일)✅ 오전 ~ 오후09:00 ~ 18:00 : 예비군 훈련훈련소 출석 및 전반 일정 소화🍽️ 저녁시간18:00 ~ 19:00 : 저녁식사 및 휴식💻 개인 작업 시간19:00 ~ 23:00 : 텍스트 RPG 프로젝트 작업Quest 시스템 UI 기획 및 전체 구조 수정QuestUI.cs에서 퀘스트 목록 → 상세 보기 흐름 구현Console ASCII UI 3D 형태 조정 (QUEST 박스 완성)콘솔 폭 맞춤 문제로 인한 출력 깨짐 디버깅최종적으로 깔끔한 Console.WriteLine 출력으로 리셋 및 구조 정비✅ 오늘 학습 키워드Console.WriteLine() UI 구성ASCII 아트 박스 디자인 (QUEST)퀘스트 목록 출력 및 선택 흐름List 처리..
2025.07.15
no image
내일배움캠프 11일차 TIL [예비군 훈련 + 팀프로젝트 클래스 구조 설계]
🗓️ 오늘 하루 일정✅ 오전 & 오후09:00 ~ 18:00 : 예비군 훈련🍽️ 저녁시간18:00 ~ 19:00 : 저녁식사✅ 저녁19:00 ~ 20:00 : 팀 프로젝트 회의20:00 ~ 20:30 : 팀원들과 프로젝트 계획 조율20:30 ~ 21:00 : 개인 TIL 작성✅ 심야 작업21:00 ~ 00:00 : 게임 저장 시스템 구조 설계 및 디버깅GameSaveData 클래스: 저장할 캐릭터 정보, 인벤토리, 완료 퀘스트 등 데이터 모델 정의SaveManager 클래스: JSON 저장/불러오기 기능 및 자동 경로 생성 처리실행 경로 기준 상대 경로 저장 위치 확인 (bin/Debug/net8.0/...) 및 경로 재설정Unicode 이스케이프(예: \\uC7AC\\uC740) 현상 확인 및 보기..
2025.07.15
no image
C# - Longest Increasing Subsequence
📘 300. Longest Increasing Subsequence🔹 문제 설명정수 배열 nums가 주어질 때,배열에서 오름차순으로 증가하는 가장 긴 부분 수열의 길이를 구하라.부분 수열(subsequence):(연속된 값일 필요는 없음)원래 배열에서 순서를 유지하면서 일부 원소를 건너뛰어 선택할 수 있음🔸 예시Input: nums = [10, 9, 2, 5, 3, 7, 101, 18]Output: 4설명: 가장 긴 오름차순 부분 수열은 [2, 3, 7, 101] 이므로 길이는 🔹 조건1 10⁴ 🎯 목표👉 배열에서 가장 길게 오름차순으로 증가하는 부분 수열을 찾아서그 길이를 반환하는 함수를 작성하는 것이 목표야.✅ 예시 2Input: nums = [0, 1, 0, 3, 2, 3]Output: ..
2025.07.13
C#
no image
C# - Flood Fill
🖌️ 문제 733. Flood Fill🔸 문제 설명2차원 배열 image가 주어지고,어떤 **시작 좌표 (sr, sc)**와 새로운 색상 newColor가 주어졌을 때,시작 좌표에서 연결된 같은 색상의 픽셀들을 모두 찾아서,해당 픽셀들을 newColor로 바꾸는 Flood Fill 알고리즘을 구현하라는 문제야.🔹 입력image: 2차원 배열 (각 원소는 색상을 의미하는 정수)sr, sc: 시작 픽셀의 행(row), 열(column)newColor: 바꿀 색상 (정수)🔹 조건연결된 픽셀은 상하좌우로 인접하면서 같은 색을 가진 픽셀만 포함됨대각선은 포함되지 않음 ❌🧪 예시Input:image = [[1,1,1], [1,1,0], [1,0,1]],sr = 1, sc = 1..
2025.07.13
C#
no image
C# - Largest Rectangle in Histogram
📘 문제 설명: Largest Rectangle in Histogram🔸 문제 개요너비가 1인 여러 개의 직사각형이 세로 방향으로 일렬로 나열되어 있는 히스토그램(histogram) 이 주어졌을 때,이 중 가장 넓은 직사각형의 넓이를 구하는 문제야.🔸 입력 예시heights = [2, 1, 5, 6, 2, 3]각 숫자는 해당 위치에 있는 직사각형의 높이를 의미해.→ 이 경우, 너비 1인 직사각형이 총 6개 있고, 각각 높이는 2, 1, 5, 6, 2, 3이야.🎯 목표히스토그램에서 만들 수 있는 가장 넓은 직사각형의 넓이를 반환해야 해.🔸 예시 결과입력: [2,1,5,6,2,3]출력: 10→ 높이 5와 6 사이의 두 개 직사각형(5,6)을 선택하면,가로 너비 2 × 세로 높이 5 = 10💡 핵심..
2025.07.13
C#
no image
WIL - 본 캠프 2주차(25.07.07~07.11)
📅 지난 일주일 동안 가장 인상 깊었던 배움은?이번 주 가장 인상 깊었던 배움은 텍스트 기반 RPG 프로젝트를 직접 설계하고 구현한 경험이었다.단순히 기능을 만들기보다, 상호작용하는 시스템을 어떻게 구조화할 것인지에 대한 고민이 깊었던 한 주였다.예를 들어, Item 클래스를 중심으로 상점, 인벤토리, 장착 시스템, 저장/불러오기 기능까지 유기적으로 연결하며, 자연스럽게 클래스 간의 책임 분리와 데이터 공유 방식에 대해 고민하게 되었다.또한, Item.Items라는 정적 리스트를 활용하여 아이템 정보를 한곳에서 관리하고, 아이템의 구매 상태(가격 0원 처리), 능력치 반영 방식, 저장 시의 데이터 유지 등 실제 게임 시스템을 구현하며 생기는 수많은 예외 상황들을 마주했다. 이 과정에서 값 형식/참조 형..
2025.07.13
반응형

🗓️ 오늘 하루 일정

✅ 오전

  • 09:00 ~ 13:00 : 프로젝트 작업
    • 직업별 스킬 시스템 구조 리팩토링 (SkillSet 인터페이스 기반)
    • UseSkill 메서드 구조 변경 및 범위 공격 구현
    • 장착 시스템 FinalAtk, FinalDef 구조 반영 확인
    • 회피 확률 → 민첩 기반으로 재설계 (DodgeChance 동적 계산)

🍽️ 점심시간

  • 13:00 ~ 14:00 : 점심시간

✅ 오후

  • 14:00 ~ 18:00 : 팀 프로젝트 발표 준비
    • 발표용 코드 정리 및 구조 설명 작성
    • 몬스터 다수 공격 시 HP 변화 출력 개선 (prevHpDict)
    • 트러블슈팅 정리
      • 직업 클래스 구조 단순화 이슈 → 해결 과정
      • 퀘스트 클래스 역할 분리 이슈 → 해결 과정
    • 발표용 PPT 구성 요소 정리 및 작성 시작

🍽️ 저녁시간

  • 18:00 ~ 19:00 : 저녁시간

✅ 저녁

  • 19:00 ~ 21:00 : 발표용 트러블슈팅 작성 & 마무리 피드백
    • 발표용 설명 작성: 다형성, 체력 추적, 스킬 범위 공격 등
    • 퀘스트 시스템 구조 변경 경험 정리
    • 아이템 리스트 구조 변경 내용 보완

✅ 오늘 학습 키워드

  • SkillSet 인터페이스 기반 직업 다형성
  • 범위 스킬 및 피해 대상 추적 출력
  • FinalAtk, FinalDef 개념으로 능력치 분리
  • DodgeChance = 민첩 기반 회피 확률 구현
  • 발표용 트러블슈팅 작성
  • 퀘스트 클래스 역할 분리 (Manager, UI, 데이터)

✅ 오늘 학습 한 내용을 나만의 언어로 정리하기

🎯 직업 스킬 구조의 리팩토링

  • 기존에는 Job 클래스별로 스킬을 따로 정의했는데, 유지보수가 어렵고 중복이 많았음.
  • SkillSet 인터페이스를 정의하고, 각 직업이 이를 상속해 고유 스킬을 구현하게 변경함.
  • UseSkill(int index, Player, List<Monster>, Monster mainTarget) 시그니처로 통일하여, 단일/다중 타겟 모두 처리 가능하게 함.
  • 이로써 다형성을 통한 유연한 스킬 시스템을 완성했고, 전사, 마법사, 궁수, 도적, 해적 모두 동일한 틀 안에서 관리 가능해짐.

🌀 몬스터 다수 공격 처리

  • prevHpDict = monsterSpanwed.ToDictionary(m => m, m => m.Hp) 를 활용해,
  • 스킬 사용 전 몬스터들의 체력을 저장 → 공격 후 변화가 있는 몬스터만 출력함.
  • 이 과정은 DisplayHpInfo 함수를 통해 시각적으로 체력 감소 효과를 보여줌.
  • 피해를 입은 대상만 출력되므로 플레이어의 인식이 명확해지고 몰입도 증가.

🛡️ 능력치 구조 정리

  • 기존에는 Atk, Def 등 수치가 장비 장착 시 바로 바뀌어 관리가 어려웠음.
  • Atk + ExtraAtk = FinalAtk, Def + ExtraDef = FinalDef 구조로 분리.
  • 덕분에 장착 효과와 기본 능력치를 분리해 관리할 수 있게 되었고,
  • 장착/해제/판매 시에도 안정적으로 적용됨.

🧠 회피 확률 계산 방식 개선

  • 기존에는 DodgeChance가 고정값이었는데, 민첩 Dex 수치를 기반으로 동적으로 계산하도록 변경.
  • 예: DodgeChance = Math.Min(50, Dex / 2) 처럼 민첩 수치가 높을수록 회피율도 증가하도록 설정함.
  • 이로 인해 능력치가 전투에 직접적인 영향을 주는 구조로 개선됨.

🧩 학습하며 겪었던 문제점 & 에러

① 문제정의: 직업 클래스를 Job으로 나누니 코드가 너무 복잡해졌다

🧩 문제 상황

  • 처음에는 직업마다 Job 클래스를 만들어 공격력, 방어력, 스킬 등을 직접 구현했다.
  • 예를 들어 WarriorJob, MageJob, ThiefJob 같은 식으로 클래스가 각각 존재했음.
  • 직업이 늘어날수록 코드가 급격히 길어지고, 스킬을 사용하는 방식이 서로 달라지다 보니 호출부에서 일일이 분기 처리해야 했다.

🧪 시도

// 예전 방식 - Job마다 스킬을 따로 정의하고 조건문으로 분기
if (player.Job == "전사")
    WarriorSkill.UseSkill(index, player, monster);
else if (player.Job == "마법사")
    MageSkill.UseSkill(index, player, monster);

🛠 해결 방법

  • SkillSet 인터페이스를 만들고, 각 직업 스킬 클래스에 상속시켰다.
  • 이제 직업에 따라 스킬 클래스만 다르게 생성하면, 호출부는 공통된 방식으로 처리 가능하다.

✅ 개선된 코드

// 인터페이스 기반 구조
public interface SkillSet
{
    List<string> SkillNames { get; }
    void UseSkill(int index, Player player, List<Monster> monsters, Monster mainTarget);
}

// 전사 스킬 예시
public class WarriorSkill : SkillSet
{
    public List<string> SkillNames => new() { "강타", "회전베기", "분쇄", "더블스트라이크" };

    public void UseSkill(int index, Player player, List<Monster> monsters, Monster mainTarget)
    {
        // 스킬 사용 로직 통합
    }
}

// 호출 시
SkillSet skillSet = new WarriorSkill(); // 직업에 따라 바꿔주기만 하면 됨
skillSet.UseSkill(index, player, monsters, target);

💡 새롭게 알게 된 점

  • 인터페이스를 활용하면 다형성을 통해 중복을 없애고 구조를 단순화할 수 있다.
  • 앞으로는 Job 자체를 코드로 관리하지 않고 스킬/능력치 중심으로 설계하는 게 유지보수에 더 좋다.

② 문제정의: 퀘스트 클래스를 하나로 처리했더니 역할이 꼬이고 유지보수가 힘들었다

🧩 문제 상황

  • 퀘스트 진행, UI 출력, 퀘스트 상태 갱신 등을 전부 Quest.cs 하나에서 처리하고 있었음.
  • 클래스가 너무 커져서 어떤 코드가 어떤 역할을 하는지 찾기 어렵고, 테스트하기도 힘들었음.

🧪 시도

// 문제였던 코드
public class Quest
{
    public string Title;
    public string Info;
    public int TargetCount;
    public int CurrentCount;
    public bool IsAccepted;
    public bool IsCompleted;

    public void DisplayQuestUI() { ... } // UI 코드
    public void UpdateQuestProgress(string monsterName) { ... } // 로직 코드
}

🛠 해결 방법

  • 역할을 나누어 클래스를 3개로 분리
    1. Quest.cs: 퀘스트 데이터만 담당 (제목, 설명, 진행률 등)
    2. QuestManager.cs: 진행, 완료 체크 등의 로직만 담당
    3. QuestUI.cs: 퀘스트 출력 전용 클래스

✅ 개선된 구조

// Quest.cs - 데이터만 담당
public class Quest
{
    public string Title;
    public string Info;
    public int TargetCount;
    public int CurrentCount;
    public bool IsAccepted;
    public bool IsCompleted;
}

// QuestManager.cs
public static class QuestManager
{
    public static void CheckKill(string monsterName, Player player)
    {
        foreach (var quest in player.Quests)
        {
            if (quest.IsAccepted && !quest.IsCompleted && quest.Title.Contains(monsterName))
            {
                quest.CurrentCount++;
                if (quest.CurrentCount >= quest.TargetCount)
                    quest.IsCompleted = true;
            }
        }
    }
}

// QuestUI.cs - 출력 전용
public static class QuestUI
{
    public static void DisplayQuestList(List<Quest> quests)
    {
        foreach (var quest in quests)
        {
            Console.WriteLine($"🧾 {quest.Title} - {quest.CurrentCount}/{quest.TargetCount}");
        }
    }
}

💡 새롭게 알게 된 점

  • 클래스를 기능별로 나누면, 역할이 명확해지고 코드를 찾기도 쉽고 디버깅도 수월하다.
  • *단일 책임 원칙(SRP)**의 중요성을 몸으로 체감했다.

📝 메모

  • 점점 코드가 커질수록 책임 분리와 구조화가 중요하다는 걸 실감했다.
  • 내가 만든 구조를 다시 뜯어보면서 "내가 이걸 왜 이렇게 했지?" 싶은 게 많았는데,
  • 하나씩 이유를 찾고 개선해 나가면서 기분이 좋았다!
  • 발표를 준비하면서 나도 몰랐던 내 코드의 장점을 알게 되어 더 자신감이 생겼다!

이제 예비군도 끝나서그런지 오늘 팀프로젝트 하는데 너무 즐거웠다ㅠㅜ.. 공부가 이렇게 재밌었지.. 항상 새롭게 느껴지고.. 오류 생길때는 살짝 답답할때도 있지만 하루하루 즐기면서 개발 잘 해보자ㅏ 오예ㅖ!~!!


반응형
반응형

🗓️ 2025년 7월 16일 (수) – 오늘의 일정

✅ 오전 & 오후

  • 09:00 ~ 18:00 : 예비군 훈련

🍽️ 저녁시간

  • 18:00 ~ 19:00 : 저녁 식사

🧘 개인시간

  • 19:00 ~ 20:00 : 개인 휴식

🛠️ 팀 프로젝트 개발

  • 20:00 ~ 00:00 : 텍스트 RPG 직업 설계 및 스킬 개발
    • 직업 능력치 정리 및 보정 적용
    • 전사, 마법사, 도적, 궁수, 해적 클래스 정리
    • 각 직업별 스킬 3종 설계 및 코드 구현

✅ 오늘 학습 키워드

  • 직업 클래스 설계 리팩터링
  • 능력치 자동 계산 구조 (계산 프로퍼티 활용)
  • 직업별 특성 기반 능력치 보정
  • 직업별 스킬 구조 설계 및 구현
  • 추상 메서드 오버라이드 구조

✅ 오늘 학습 한 내용을 나만의 언어로 정리하기

오늘은 텍스트 RPG 프로젝트에서 직업 시스템과 전투 스킬 구조를 본격적으로 설계하고 구현했다.

먼저 Job 클래스에 각 능력치를 계산 프로퍼티(get) 로 리팩터링하여,

장비나 추가 능력치가 변하면 자동으로 최종 능력치에 반영되도록 구조를 개선했다.

그 후 각 직업(전사, 마법사, 도적, 궁수, 해적)의 고유 특성을 기준으로

공격력, 체력, 마나, 민첩, 회피율 등 보정 규칙을 다르게 적용하여 밸런스를 맞췄다.

마지막으로 각 직업마다 3개의 고유 스킬을 SkillNames와 UseSkill() 메서드로 구현했다.

스킬마다 치명타, 연속 공격, 상태 이상, MP 소비, 조건부 보정 등 개성이 잘 반영되도록 설계했.


🧩 학습하며 겪었던 문제점 & 에러

1. 문제정의

전사의 MaxMp가 설정한 값(40)보다 Job 기본값(50)이 우선 적용되는 문제 발생

  • 시도: 기본 구조에서 MaxMp => 50 + ExtraMp로 고정되어 있었음
  • 해결 방법: 각 직업 클래스에서 MaxHp, MaxMp, Agility 등을 override하여 명확히 기본값 반영
  • 새롭게 알게 된 점: 계산 프로퍼티 방식에서도 기본값이 우선 적용되므로, 반드시 각 클래스에서 오버라이드가 필요함
  • 다시 만나게 된다면: 능력치 기준값이 기본 구조보다 낮은 경우엔 항상 오버라이드를 체크할 것

📝 메모

오늘 구조를 정비하면서 느꼈다. 처음엔 간단해 보였던 클래스 구조도 실제 구현에 들어가면 훨씬 세밀하게 설계해야 한다는 걸 배웠다. 스킬을 따로 분리하지 않고 직업 내부에서 관리한 방식이 지금 구조엔 가장 자연스럽고 깔끔했던 선택이었다. 많은 스킬을 만든다면 따로 만드는게 맞지만 굳이..

하여간 오늘도 이렇게 끝났다 예비군 훈련이 하루 남았다!! 개발을 더 많이 해야하는데..팀원들한테 너무 미안하다 ㅠㅜㅜ 금요일날 아주..밤새서 개발을 해보겠어..각오해…

 

 

직업별 능력치 밸런스 기획

📊 직업별 능력치 및 특성 보정 요약표

직업 공격력 방어력 민첩 MaxHP MaxMP 치명타 확률 치명타 배수 회피 계산 방식 능력치 보정

전사 8 9 4 140 40 10% 1.5배 민첩 × 1.0 ExtraHp × 1.5배, ExtraAttack × 1.2배
마법사 10 3 5 90 120 15% 1.8배 민첩 × 1.0 ExtraMp × 1.5배, ExtraAttack × 1.2배
도적 9 4 10 95 70 18% 1.6배 (민첩 + 보정) × 1.5배 민첩 회피 특화 (DodgeChance 직접 계산)
궁수 8 5 9 100 60 30% 2.0배 민첩 × 1.0 치명타 확률, 배수 특화
해적 8 6 6 120 60 10% 1.7배 (민첩 × 1.2) × 1.0 ExtraHp / Mp / Agility × 1.2배

🧠 직업 특성 설계 요약

직업 설계 의도 및 특성 설명

전사 체력과 방어를 기반으로 안정적인 탱커 역할 수행. 장비에 의한 HP 보정 효과가 커서 후반 생존력 뛰어남. 공격력 보정도 일부 적용해 균형 잡힘.
마법사 마나 기반의 폭딜러. 마법 데미지 스킬 활용 전제이며 MP가 장비로 많이 늘어날수록 강해짐. 체력은 낮지만 한 방이 강한 캐릭터.
도적 회피 특화 캐릭터. 민첩 수치가 회피율에 크게 반영되며, 기동성과 회피를 활용한 지속적 타격 스타일. 치명타 수치는 궁수보다 낮음.
궁수 치명타 확률과 배율이 가장 높은 캐릭터. 민첩 회피 보정은 없지만 확률 기반 한 방이 강력함. 정확성과 폭딜 중심 설계.
해적 전천후 밸런스형 캐릭터. HP, MP, 민첩 모두 고르게 보정돼 유연한 대응 가능. 극단적 강점은 없지만 안정적인 성능을 가짐.
반응형
반응형

🗓️ 오늘 하루 일정 (2025년 7월 15일)

✅ 오전 ~ 오후

  • 09:00 ~ 18:00 : 예비군 훈련
    • 훈련소 출석 및 전반 일정 소화

🍽️ 저녁시간

  • 18:00 ~ 19:00 : 저녁식사 및 휴식

💻 개인 작업 시간

  • 19:00 ~ 23:00 : 텍스트 RPG 프로젝트 작업
    • Quest 시스템 UI 기획 및 전체 구조 수정
    • QuestUI.cs에서 퀘스트 목록 → 상세 보기 흐름 구현
    • Console ASCII UI 3D 형태 조정 (QUEST 박스 완성)
    • 콘솔 폭 맞춤 문제로 인한 출력 깨짐 디버깅
    • 최종적으로 깔끔한 Console.WriteLine 출력으로 리셋 및 구조 정비

✅ 오늘 학습 키워드

  • Console.WriteLine() UI 구성
  • ASCII 아트 박스 디자인 (QUEST)
  • 퀘스트 목록 출력 및 선택 흐름
  • List<Quest> 처리와 인덱스 기반 선택
  • Console.Clear(), Console.ReadKey() 흐름 제어

✅ 오늘 학습 한 내용을 나만의 언어로 정리하기

오늘은 텍스트 RPG의 퀘스트 시스템을 좀 더 다듬고 시각적으로 보기 좋게 만들기 위해 콘솔 출력 형식을 고도화했다.

초반에는 Quest 정보를 박스 형태로 이쁘게 표현하려고 시도했지만, 이모지나 한글 등으로 인해 콘솔 출력 폭이 들쑥날쑥해져서 UI가 깨지는 문제를 마주했다.

결국 여러 방식들을 테스트하다가, 가장 안정적인 방식인 Console.WriteLine() 중심의 깔끔한 구조로 다시 돌아오기로 결정했다.

그리고 퀘스트를 1. 제목 형태로 보여주고, 번호를 선택하면 상세 정보를 출력해주는 흐름도 구현해서 사용자 인터랙션 흐름도 잡을 수 있었다.

마지막엔 QUEST라는 텍스트를 입체감 있게 ASCII 아트로 표현하는 것도 마무리해서 전체적으로 UI 완성도를 높이는 날이었다.


🧩 학습하며 겪었던 문제점 & 에러

…생략 오늘은 봐주세여..예비군 갔다가 11시까지 개발 했어여ㅠ


📝 메모

오늘은 내가 아무리 체력이 좋아도 너무 피곤했다ㅎㅎㅠㅠ..

그래도 끝까지 마무리하고 나니 기분이 후련하다.

무엇보다 도중에 ‘그냥 대충 마무리할까’ 하는 유혹을 이기고,

최소한 내가 원한 수준까지는 도달하고 잠자리에 드는 이 결심이 제일 뿌듯하다.

내일..또 예비군 훈련이 있지만 그래도 개발은 재밌다.. 예비군 훈련할때

오늘 집가서 뭐 개발하지..생각밖에 없다… 예비군 빨리 끝내고 팀원들이랑 프로젝트 진행해야지.. 예비군 때문에 팀프로젝트를 소홀히 할 수 없다. 어떻게든 더 만들고 끝내야지 하루하루.. 남은 기간 화이팅ㅠㅜ


반응형
반응형

🗓️ 오늘 하루 일정

✅ 오전 & 오후

  • 09:00 ~ 18:00 : 예비군 훈련

🍽️ 저녁시간

  • 18:00 ~ 19:00 : 저녁식사

✅ 저녁

  • 19:00 ~ 20:00 : 팀 프로젝트 회의
  • 20:00 ~ 20:30 : 팀원들과 프로젝트 계획 조율
  • 20:30 ~ 21:00 : 개인 TIL 작성

✅ 심야 작업

  • 21:00 ~ 00:00 : 게임 저장 시스템 구조 설계 및 디버깅
    • GameSaveData 클래스: 저장할 캐릭터 정보, 인벤토리, 완료 퀘스트 등 데이터 모델 정의
    • SaveManager 클래스: JSON 저장/불러오기 기능 및 자동 경로 생성 처리
    • 실행 경로 기준 상대 경로 저장 위치 확인 (bin/Debug/net8.0/...) 및 경로 재설정
    • Unicode 이스케이프(예: \\uC7AC\\uC740) 현상 확인 및 보기 편한 저장 방식 옵션 추가
    • 직렬화가 잘 되지 않던 문제를 { get; set; } 자동 속성으로 수정
    • 클래스 구조의 역할 분리와 폴더 정리까지 완료

✅ 오늘 학습 키워드

  • C# JSON 저장 시스템
  • System.Text.Json 직렬화
  • 상대 경로 vs 실행 경로
  • 디렉토리 자동 생성
  • Unicode 이스케이프
  • { get; set; } 자동 속성
  • 저장용 클래스 구조 설계 (GameSaveData, SaveManager)

✅ 오늘 학습 한 내용을 나만의 언어로 정리하기

오늘은 예비군 훈련을 마친 후, 밤 시간대를 활용해 게임 저장 시스템의 핵심 구조를 설계하고 구현했다.

먼저 GameSaveData 클래스를 통해 저장할 데이터를 설계했는데, 캐릭터 이름, 직업, 레벨, 경험치, 골드, HP/MP, 인벤토리, 완료한 퀘스트 등 저장이 필요한 항목들을 데이터 중심으로 구성했다.

그리고 SaveManager 클래스를 만들어 JSON 저장/불러오기 기능을 구현했다.

처음에는 저장 파일이 보이지 않아 당황했지만, 상대 경로의 기준이 실행 파일 위치(bin/Debug/net8.0/)라는 것을 확인하고 AppContext.BaseDirectory를 이용해 경로를 조정했다.

또한 저장 시 생성할 디렉토리가 없으면 자동으로 만들어주는 기능도 함께 처리해 실제 실행 환경에서도 문제없이 저장될 수 있도록 했다.

한 가지 흥미로운 점은 JSON으로 저장된 한글이 \\uC7AC\\uC740처럼 유니코드 이스케이프 형태로 저장된 것이었는데, 이는 System.Text.Json의 기본 동작이라는 것을 알게 되었고, 보기 편한 저장을 위해 UnsafeRelaxedJsonEscaping 옵션을 적용하는 방법도 함께 학습했다.

무엇보다 이번 작업에서는 단순히 기능만 구현한 것이 아니라, 저장 시스템의 클래스 구조를 깔끔하게 나누고 폴더별로 역할을 분리했다는 점에서 의미가 있었다.

이렇게 구조화해두면 앞으로 저장 슬롯, 자동 저장, 캐릭터 복원 같은 기능을 추가할 때 매우 편리하게 확장할 수 있다.

 

추가 클래스 구조

Challenge_JaeEun

├── Character_Folder

│   └── NewCharacter.cs

├── Job_Folder

│   ├── Job.cs (추상 클래스)

│   ├── Warrior.cs

│   ├── Archer.cs

│   ├── Mage.cs

│   └── Skill _Folder

│       └── JobSkill.cs

├── Quest_Folder

│   ├── Quest.cs

│   └── QuestManager.cs

├── SaveSystem _Folder

│   ├── GameSaveData.cs

│   └── SaveManager.cs


🧩 학습하며 겪었던 문제점 & 에러

1. 문제정의

NewCharacter 클래스에서 Job 타입을 사용하려고 했는데, 타입 인식을 못 하는 오류 발생

  • 시도
  • using 문과 네임스페이스를 점검했지만 문제는 해결되지 않았고, Job 클래스가 abstract라서 생긴 문제인지 의심도 해봄
  • 해결 방법Visual Studio가 폴더명을 타입으로 인식하면서 충돌이 발생했던 것
  • → 폴더명을 Job_Folder로 바꾸고 다시 네임스페이스를 정리하자 오류 해결됨
  • 폴더 이름과 클래스 이름이 모두 Job으로 동일했던 것이 문제였음.
  • 새롭게 알게 된 점
  • 폴더 이름과 클래스 이름이 같으면 네임스페이스 해석에서 충돌이 발생할 수 있다는 것을 처음 체감
  • 다시 만나게 된다면
  • 폴더 이름은 항상 클래스 이름과 다르게 명확하게 정리하고, 충돌이 의심되면 namespace, using을 전부 다시 확인하자

🔴 문제 상황 (오류 발생 코드)

// NewCharacter.cs
using TextRPG.Challenge_JaeEun.Character.Job;

namespace TextRPG.Challenge_JaeEun.Character
{
    public class NewCharacter
    {
        public string Name;
        public Job CharacterJob;  // ⚠ 오류: Job 클래스를 찾지 못함
    }
}
// Job.cs
namespace TextRPG.Challenge_JaeEun.Character.Job
{
    public abstract class Job
    {
        public string JobName;
    }
}

문제 원인: Job이라는 클래스 이름과 Job이라는 폴더 이름이 동일하여,

Visual Studio가 네임스페이스와 타입을 혼동함 → Job 타입을 인식하지 못함

✅ 해결 방법 (폴더명을 Job_Folder로 변경)

// NewCharacter.cs
using TextRPG.Challenge_JaeEun.Character.Job_Folder;

namespace TextRPG.Challenge_JaeEun.Character
{
    public class NewCharacter
    {
        public string Name;
        public Job CharacterJob;  // ✅ 오류 사라짐
    }
}
// Job.cs
namespace TextRPG.Challenge_JaeEun.Character.Job_Folder
{
    public abstract class Job
    {
        public string JobName;
    }
}

2. 문제정의

SaveToJson()을 호출했는데 저장된 파일이 프로젝트 폴더에 보이지 않음

  • 시도
  • 경로 설정은 "Challenge_JaeEun/JSON_Data"로 했고, 파일 생성도 성공 메시지가 출력되어 있음
  • 해결 방법→ AppContext.BaseDirectory를 사용해 원하는 위치로 경로 재지정하고 해결
  • 확인 결과, 저장은 잘 되었지만 **상대 경로 기준이 실행 위치(bin/Debug/net8.0/)**였다는 사실을 몰랐던 것
  • 새롭게 알게 된 점또한, Directory.CreateDirectory()를 활용하면 없는 폴더도 자동 생성되므로 에러 없이 저장이 가능하다는 것도 배움
  • 상대 경로는 소스코드 위치가 아니라 실행 파일 위치 기준으로 동작한다는 점
  • 다시 만나게 된다면
  • 경로 문제를 만났을 땐 반드시 File.Exists(), Directory.Exists()로 경로 실존 여부를 확인하고, 실행 기준 경로를 먼저 파악하자

🔴 문제 상황 (파일은 저장되지만 안 보임)

private static readonly string SaveDirectory = "Challenge_JaeEun/JSON_Data";
private static readonly string SavePath = Path.Combine(SaveDirectory, "save.json");

File.WriteAllText(SavePath, json);

문제 원인: 상대 경로 기준은 **실행 파일 위치 (bin/Debug/net8.0/)**라서,

프로젝트 폴더에는 파일이 보이지 않음


✅ 해결 방법 (경로를 프로젝트 루트로 변경)

// 실행 기준에서 프로젝트 폴더로 올라간 다음 경로 설정
private static readonly string SaveDirectory = Path.Combine(AppContext.BaseDirectory, @"..\\..\\..\\Challenge_JaeEun\\JSON_Data");
private static readonly string SavePath = Path.Combine(SaveDirectory, "save.json");

Directory.CreateDirectory(SaveDirectory);
File.WriteAllText(SavePath, json);

이렇게 하면 실제 프로젝트 폴더 내부에 JSON이 저장됨, 그리고

경로 오류도 사라짐!


📝 메모

오늘은 정신적으로도, 체력적으로도 정말 밀도 있는 하루였다.

하루 종일 예비군 훈련을 받고 나니 진이 빠졌지만,

밤에는 오히려 더 집중이 잘 돼서 저장 시스템 설계를 깊이 있게 고민할 수 있었다.

사소한 문제라고 생각했던 Job 네임스페이스 오류나,

파일이 저장되지 않는다고 착각했던 경로 이슈처럼

사실 알고 보면 "몰랐던 게 아니라 오해했던 것들"이 많았다.

하지만 그런 문제를 직접 하나하나 풀어내면서,

구조를 쌓고, 클래스를 나누고, 저장 흐름을 통제하는 이 과정이 너무 재밌었다.

오늘은 기능뿐 아니라 클래스를 명확하게 나누고 폴더 구조도 정리한 날이었다.

이렇게 하나씩 쌓아올리다 보면 정말 좋은 프로젝트가 될 거라는 기대가 생긴다.

오늘도 잘했고, 내일도 잘할 수 있다!!! 💪 예비군 2일차 화이팅 ㅠㅜ.. 코딩이 더 재밌다..차라리 공부를ㅠㅜ..


반응형
반응형

📘 300. Longest Increasing Subsequence

🔹 문제 설명

정수 배열 nums가 주어질 때,

배열에서 오름차순으로 증가하는 가장 긴 부분 수열의 길이를 구하라.

  • 부분 수열(subsequence):(연속된 값일 필요는 없음)
  • 원래 배열에서 순서를 유지하면서 일부 원소를 건너뛰어 선택할 수 있음

🔸 예시

Input: nums = [10, 9, 2, 5, 3, 7, 101, 18]
Output: 4

설명: 가장 긴 오름차순 부분 수열은 [2, 3, 7, 101] 이므로 길이는 

🔹 조건

  • 1 <= nums.length <= 2500
  • 10⁴ <= nums[i] <= 10⁴

🎯 목표

👉 배열에서 가장 길게 오름차순으로 증가하는 부분 수열을 찾아서

길이를 반환하는 함수를 작성하는 것이 목표야.


✅ 예시 2

Input: nums = [0, 1, 0, 3, 2, 3]
Output: 4
설명: [0, 1, 2, 3] 이 가장 길다

🧠 핵심 개념

이 문제는 전형적인 동적 계획법 (DP) 또는 이진 탐색을 이용한 최적화 문제야.

  • 기본 DP 풀이: O(n²)
  • 이진 탐색 최적화: O(n log n)
using System;

public class Program
{
    public static void Main()
    {
        int[] nums = new int[] { 10, 9, 2, 5, 3, 7, 101, 18 };

        Console.WriteLine("Input Array: " + string.Join(", ", nums));

        int result = FindLengthOfLIS(nums);

        Console.WriteLine("Longest Increasing Subsequence Length: " + result);
    }

    public static int FindLengthOfLIS(int[] nums)
    {
        int n = nums.Length;
        if (n == 0) return 0;

        int[] dp = new int[n];
        for (int i = 0; i < n; i++)
            dp[i] = 1;  // 최소 자기 자신

        for (int i = 1; i < n; i++)
        {
            for (int j = 0; j < i; j++)
            {
                if (nums[j] < nums[i])
                {
                    dp[i] = Math.Max(dp[i], dp[j] + 1);
                }
            }
        }

        int maxLength = 0;
        for (int i = 0; i < n; i++)
            maxLength = Math.Max(maxLength, dp[i]);

        return maxLength;
    }
}
반응형

C# - Flood Fill

Dev_Jen
|2025. 7. 13. 23:56
반응형

🖌️ 문제 733. Flood Fill

🔸 문제 설명

2차원 배열 image가 주어지고,

어떤 **시작 좌표 (sr, sc)**와 새로운 색상 newColor가 주어졌을 때,

시작 좌표에서 연결된 같은 색상의 픽셀들을 모두 찾아서,

해당 픽셀들을 newColor로 바꾸는 Flood Fill 알고리즘을 구현하라는 문제야.


🔹 입력

  • image: 2차원 배열 (각 원소는 색상을 의미하는 정수)
  • sr, sc: 시작 픽셀의 행(row), 열(column)
  • newColor: 바꿀 색상 (정수)

🔹 조건

  • 연결된 픽셀은 상하좌우로 인접하면서 같은 색을 가진 픽셀만 포함됨
  • 대각선은 포함되지 않음 ❌

🧪 예시

Input:
image = [[1,1,1],
         [1,1,0],
         [1,0,1]],
sr = 1, sc = 1, newColor = 2

Output:
[[2,2,2],
 [2,2,0],
 [2,0,1]]

설명:

  • 시작점 (1,1)의 색은 1
  • 이 색과 연결된 상하좌우 방향의 픽셀을 찾아서 2로 바꿈
  • image[2][2]은 색이 1이지만 연결되지 않았기 때문에 제외

🎯 목표

시작점과 연결된 모든 같은 색의 픽셀을 찾아서, 모두 newColor로 바꾼 2차원 배열을 리턴하는 함수 구현하기!


💡 핵심 개념

  • Flood Fill은 대표적인 그래프 탐색 문제야.
  • 방식은 DFS(깊이 우선 탐색) 또는 BFS(너비 우선 탐색) 중 하나를 사용해 구현할 수 있어.
  • DFS가 간단하고 구현도 쉬워서 자주 사용돼.
public class Program
{
    public static void Main(string[] args)
    {
        // 이미지 배열 예시 선언 (2차원 배열)
        int[][] image = new int[][]
        {
            new int[] {1, 1, 1},
            new int[] {1, 1, 0},
            new int[] {1, 0, 1}
        };

        // 시작 위치와 새 색상 정의
        int sr = 1;
        int sc = 1;
        int newColor = 2;

        Console.WriteLine("Before Flood Fill:");
        PrintImage(image);

        FloodFill(image, sr, sc, newColor);

        Console.WriteLine("\\nAfter Flood Fill:");
        PrintImage(image);
    }

    public static void FloodFill(int[][] image, int sr, int sc, int newColor)
    {
        int originalColor = image[sr][sc];

        if (originalColor == newColor)
        {
            return;
        }

        void Fill(int row, int col)
        {
            if (row < 0 || row >= image.Length || col < 0 || col >= image[0].Length)
                return;

            if (image[row][col] != originalColor)
                return;

            image[row][col] = newColor;

            Fill(row - 1, col); // 위
            Fill(row + 1, col); // 아래
            Fill(row, col - 1); // 왼쪽
            Fill(row, col + 1); // 오른쪽
        }

        Fill(sr, sc);
    }

    public static void PrintImage(int[][] image)
    {
        for (int i = 0; i < image.Length; i++)
        {
            for (int j = 0; j < image[i].Length; j++)
            {
                Console.Write(image[i][j] + " ");
            }
            Console.WriteLine();
        }
    }
}

반응형
반응형

📘 문제 설명: Largest Rectangle in Histogram

🔸 문제 개요

너비가 1인 여러 개의 직사각형이 세로 방향으로 일렬로 나열되어 있는 히스토그램(histogram) 이 주어졌을 때,

이 중 가장 넓은 직사각형의 넓이를 구하는 문제야.

🔸 입력 예시

heights = [2, 1, 5, 6, 2, 3]

각 숫자는 해당 위치에 있는 직사각형의 높이를 의미해.

→ 이 경우, 너비 1인 직사각형이 총 6개 있고, 각각 높이는 2, 1, 5, 6, 2, 3이야.


🎯 목표

히스토그램에서 만들 수 있는 가장 넓은 직사각형의 넓이를 반환해야 해.

🔸 예시 결과

입력: [2,1,5,6,2,3]
출력: 10

→ 높이 5와 6 사이의 두 개 직사각형(5,6)을 선택하면,

가로 너비 2 × 세로 높이 5 = 10


💡 핵심 아이디어

이 문제는 스택(Stack) 을 활용해서 풀면 효율적으로 해결할 수 있어.

브루트포스 방식은 시간 복잡도가 O(n²)지만,

스택을 사용하면 O(n) 에 해결 가능


📌 주요 개념 요약

개념 설명

히스토그램 막대그래프처럼 세로 막대들이 나열된 형태
직사각형 넓이 특정 높이 × 가능한 너비
스택 사용 이유 왼쪽/오른쪽으로 확장 가능한 구간을 빠르게 계산 가능
시간복잡도 O(n) (한 번의 스택 순회로 해결)
class Program
{
    public static int[] heights = [2, 1, 5, 6, 2, 3];

    public static void Main(string[] args)
    {
        // 넓이의 최댓값을 저장할 변수
        int maxArea = 0;

        // 인덱스를 저장할 스택 생성
        Stack<int> indexStack = new Stack<int>();

        // heights 배열을 List로 바꾸고 마지막에 높이 0짜리 막대 추가
        List<int> heightList = new List<int>();
        for (int i = 0; i < heights.Length; i++)
        {
            heightList.Add(heights[i]);
        }
        heightList.Add(0);  // 남은 스택 정리를 위한 트릭

        // 전체 막대를 하나씩 검사
        for (int i = 0; i < heightList.Count; i++)
        {
            int currentHeight = heightList[i];

            // 스택이 비어 있지 않고, 현재 막대 높이가
            // 스택 top에 해당하는 막대보다 작다면 넓이 계산
            while (indexStack.Count > 0 &&
                   currentHeight < heightList[indexStack.Peek()])
            {

                // 스택에서 pop된 인덱스를 기준으로 직사각형 만들기
                int poppedIndex = indexStack.Pop();
                int poppedHeight = heightList[poppedIndex];

                int width;

                // 스택이 비어 있다면 왼쪽 끝(0)부터 현재 인덱스 i 전까지 가능
                if (indexStack.Count == 0)
                {
                    width = i;  // 0부터 i-1까지 너비
                }
                else
                {
                    // 오른쪽은 현재 i, 왼쪽은 스택 top 다음부터 가능
                    int leftIndex = indexStack.Peek();
                    width = i - leftIndex - 1;
                }

                int area = poppedHeight * width;

                // 최대 넓이 갱신
                if (area > maxArea)
                {
                    maxArea = area;
                }
            }

            // 현재 인덱스를 스택에 저장
            indexStack.Push(i);
        }

    }
}
반응형
반응형

📅 지난 일주일 동안 가장 인상 깊었던 배움은?

이번 주 가장 인상 깊었던 배움은 텍스트 기반 RPG 프로젝트를 직접 설계하고 구현한 경험이었다.

단순히 기능을 만들기보다, 상호작용하는 시스템을 어떻게 구조화할 것인지에 대한 고민이 깊었던 한 주였다.
예를 들어, Item 클래스를 중심으로 상점, 인벤토리, 장착 시스템, 저장/불러오기 기능까지 유기적으로 연결하며, 자연스럽게 클래스 간의 책임 분리와 데이터 공유 방식에 대해 고민하게 되었다.

또한, Item.Items라는 정적 리스트를 활용하여 아이템 정보를 한곳에서 관리하고, 아이템의 구매 상태(가격 0원 처리), 능력치 반영 방식, 저장 시의 데이터 유지 등 실제 게임 시스템을 구현하며 생기는 수많은 예외 상황들을 마주했다. 이 과정에서 값 형식/참조 형식, 깊은 복사와 얕은 복사, 메모리 흐름 등 이론적으로 배웠던 개념들이 실전에서 어떻게 작동하는지를 몸으로 익힐 수 있었다.

특히, 던전 시스템과 레벨업 구조 설계는 알고리즘적 사고까지 동반되어 더욱 인상 깊었다. 클리어 횟수에 따라 레벨이 오르고, 난이도에 따른 실패 확률과 보상 계산을 직접 수식으로 구현하면서, 단순한 조건문이 아닌 논리적인 흐름을 갖는 시스템을 어떻게 설계해야 하는지 큰 통찰을 얻었다.

이번 주는 말 그대로 "하나의 게임 시스템을 내가 직접 완성해보았다"는 확신을 얻은 시간이었다.
그 과정에서 기능을 나열하는 개발자에서, 구조를 고민하는 개발자로 조금씩 변해가는 나를 느낄 수 있었던 것이 가장 큰 배움이었다.

❗배움까지 다가가는데 어떤 어려움이 있었지?

이번 주는 정말 배움이 많았던 만큼, 그 배움에 도달하기까지의 어려움도 적지 않았다.
가장 큰 어려움은 복잡한 시스템을 어떻게 나누고 연결할지를 감 잡는 것이었다.

예를 들어, Item 클래스 하나로 상점과 인벤토리, 플레이어 장비를 동시에 관리하고 싶었는데, 정작 기능을 만들다 보니 어디서 무엇을 참조하고 수정해야 하는지가 자꾸 꼬였다.
처음에는 Item 리스트를 각각 따로 두었고, 구매한 아이템과 장착한 아이템을 서로 연동하지 못해 데이터 일관성이 무너지는 문제가 발생했다.

또한, 저장과 불러오기 기능을 구현할 때는 장착한 장비의 능력치가 적용되지 않거나 사라지는 현상이 발생해서 한참을 디버깅해야 했다.
장비가 저장은 되었지만, 다시 불러오면 플레이어 능력치에 반영이 되지 않는 이유를 찾느라 LoadPlayer() 함수의 구조를 여러 번 뜯어고치기도 했다.

무엇보다 어려웠던 건, 문제의 원인이 단순히 “코드가 틀렸다”가 아니라 설계 구조가 잘못되어 생기는 문제라는 사실이었다.
기존의 습관대로 빠르게 기능을 붙이기만 하면 오히려 나중에 수정이 불가능한 코드가 된다는 걸 뼈저리게 느꼈다.

하지만 그런 어려움 덕분에, "애초에 어떻게 설계할지를 더 먼저 고민해야 한다"는 교훈을 얻게 되었고, 클래스 간의 역할 분리와 데이터 흐름에 대한 감각을 조금씩 익힐 수 있었다.

 

💡과정에서 나는 무엇을 깨달았고, 어떤 감정/생각이 들었었지?

이번 주 과정을 통해 내가 가장 크게 깨달은 건, ‘몰랐던 게 아니라, 모르는 줄도 몰랐던 것들이 많았구나’ 하는 사실이었다.
처음엔 구조체와 클래스의 차이를 안다고 생각했고, 저장과 불러오기 기능도 단순히 파일만 다루면 될 줄 알았다. 하지만 실제로 하나하나 구현해보니, 값이 어디 저장되고, 어떻게 참조되며, 어떤 흐름으로 게임 내 시스템에 영향을 주는지 전혀 감이 없었다는 걸 깨달았다.

한참 동안 디버깅하면서 "왜 저장은 됐는데 장착 효과는 안 살아나지?"라는 단순한 문제에 몇 시간씩 매달리기도 했고, Item.Items 리스트의 정적 구조가 시스템 전반에 어떤 영향을 주는지 몸으로 부딪히며 익혀야 했다.

그 과정은 답답하고 벽에 부딪히는 느낌이 들기도 했지만, 동시에 하나씩 해결해나가면서
‘내가 진짜 조금씩 개발자에 가까워지고 있구나’ 하는 벅찬 감정도 함께였다!!

특히 저장한 데이터를 불러오면서 플레이어 능력치에 장비 효과까지 정확히 반영되었을 때, 스스로에게 “와, 내가 이걸 해냈네”라는 말을 하게 됐다.
그 순간이 이번 주 가장 뿌듯했던 기억으로 남았다.

나는 여전히 부족하지만, 부딪히고 고치고, 다시 해보는 과정 속에서 진짜 실력이 쌓이는 거구나 하는 걸 이 한 주 동안 온몸으로 느꼈다.

✍️ 메모

  • 기능 하나를 만들기 전에 데이터가 어떻게 흐르고, 어디에 저장되며, 어떤 객체가 책임을 가져야 하는지 먼저 생각하자.
  • 저장/불러오기 기능은 단순한 파일 저장이 아니라, 객체의 상태를 어떻게 재구성할 것인가에 대한 문제임을 알게 되었다.
  • 정적 리스트나 참조 형식을 사용할 땐, 공유되는 데이터의 생명 주기와 영향 범위를 명확히 파악해야 한다.
  • Item.Items, Player, Inventory, Shop 간의 관계를 설계하면서 실제 게임 시스템의 기반 구조에 대한 감각이 생기기 시작했다.
  • 설계를 수정하는 데 시간이 걸리더라도, 올바른 방향을 잡고 나면 유지보수나 디버깅 시간이 훨씬 줄어든다는 걸 체감했다.
  • 내가 모르는 걸 부끄러워하지 않고, 차분히 파고드는 습관을 계속 이어가자.

🌿 WIL - 시스템을 이해하는 힘, 그리고 성장

이번 주는 단순히 기능을 구현하는 한 주가 아니었다.
텍스트 기반 RPG 프로젝트를 만들며 처음으로 내가 직접 전체 구조를 설계하고 연결해나가는 경험을 했다.
상점, 인벤토리, 장착 시스템, 저장과 불러오기까지… 모든 요소가 Item 클래스를 중심으로 엮여 있었고, 그만큼 설계 하나가 시스템 전체에 미치는 영향도 컸다.

하지만 이 모든 걸 이해하게 되기까지는 쉽지 않은 시간들이 있었다.
저장은 되지만 장비 효과가 반영되지 않는 문제, 같은 데이터를 서로 다른 객체에서 참조할 때 발생하는 혼란, 능력치가 사라지는 원인을 찾기 위한 수많은 디버깅...
그 과정에서 나는 단순히 문법을 아는 것과 시스템을 이해하는 것의 차이를 뼈저리게 느꼈다.

그럼에도 불구하고 하나하나 부딪히며 고쳐나갔고, 마침내 내가 만든 시스템이 제대로 작동하는 걸 눈으로 확인했을 때
"아, 나 진짜 해냈다"는 생각이 들며 뿌듯함과 자부심이 함께 밀려왔다.
'모르는 걸 부끄러워하지 않고 끝까지 파고들면 반드시 얻을 수 있다'는 믿음이 생겼다.

이제 나는 기능을 나열하는 개발자가 아니라, 구조를 고민하고 흐름을 설계할 줄 아는 개발자가 되고 싶다.
그리고 그 출발점에 이번 주가 있다는 사실이 참 고맙고 소중하게 느껴진다.

🌱 앞으로도 하나씩 차분하게, 천천히, 그러나 확실하게 나아가자!!!!!!

 

📅 이번 주 TIL 목록

 

TIL - 내일배움캠프 6일차 TIL [기초 문법 강의 수강](25.07.07)

오늘의 일정오전11:00 ~ 13:00 : C# 기초 문법 강의 1~3주차 수강 학습주요 학습 내용:C# 소개 및 .NET 개요Visual Studio 개발 환경 설정Hello World 출력 및 기본 문법 구조 이해기본 자료형 선언 및 초기화 (in

dev-jen.tistory.com

 

 

TIL - 내일배움캠프 7일차 TIL [C# 튜플과 LINQ로 배우는 컬렉션 활용 + Snake 게임 제작기]

🗓️ 오늘 하루 일정✅ 오전09:00 ~ 09:10 : 팀원들과 소통 및 자기소개09:10 ~ 11:30 : 개인 공부스네이크 게임 제작맵 구현, Snake 리스트로 표현, 키 입력 처리 구현 등11:30 ~ 13:00 : C# 체크리스트 강의

dev-jen.tistory.com

 

 

 

내일배움캠프 9일차 TIL [텍스트 RPG 개발]

🗓️ 오늘 하루 일정✅ 오전09:00 ~ 11:30 : 텍스트 RPG 기능 개발 (던전 기능 설계 및 레벨업 시스템 구상)11:30 ~ 13:00 : C# 체크리스트 강의 Day 3 수강주제: 메서드주요 내용: 메서드 선언과 호출, 매개

dev-jen.tistory.com

 

 

TIL - 내일배움캠프 10일차 TIL [텍스트RPG, 정렬과 탐색 알고리즘]

🗓️ 2025년 7월 11일 (금) 오늘 하루 일정✅ 오전09:00 ~ 11:30알고리즘 기초 개념 학습시간 복잡도 vs 공간 복잡도정렬 알고리즘 개요 및 종류선택 정렬, 삽입 정렬, 버블 정렬, 퀵 정렬, 병합 정렬 정

dev-jen.tistory.com

 

📅 이번 주 Study 목록

 

C# - C#과 .NET의 시작, 개발 환경 구축과 Hello World

📘 챕터 1. C# 소개와 개발 환경 설정🧩 C# 언어의 개요C#은 마이크로소프트에서 개발한 객체지향 프로그래밍 언어이다.형식에 엄격하며, 안전성과 효율성을 고려한 구조를 갖추고 있다.C, C++, Jav

dev-jen.tistory.com

 

 

C# - C# 기본 구조 완전 정복: 출력, 주석, 자동완성

📘 C# 기본 구조 완전 정복 — 출력, 주석, 자동완성🧩 C# 코드 구조 이해하기C# 프로그램은 반드시 클래스와 메서드로 구성되며, 진입점인 Main 메서드에서 실행이 시작된다.기본 콘솔 애플리케

dev-jen.tistory.com

 

 

C# - 자료형과 변수의 기초 — 선언, 리터럴, 코드 스타일

📘 자료형과 변수의 기초 — 선언, 리터럴, 코드 스타일🧩 C# 기본 자료형 개념C#은 자료형에 대해 엄격한 형식 시스템을 가진 언어로, 모든 변수는 선언 시 반드시 자료형을 명시해야 한다.자료

dev-jen.tistory.com

 

 

C# - 형변환과 입력, 연산자 그리고 문자열 활용

📘 형변환과 입력, 연산자 그리고 문자열 활용🔄 형변환의 개념C#은 형식이 엄격한 언어이기 때문에 서로 다른 자료형 간의 대입이나 연산을 수행할 때 형변환이 필요하다.형변환에는 명시적

dev-jen.tistory.com

 

 

C# - 사용자로부터 입력 받기, 계산기 만들기, 온도 변환기 만들기, BMI 계산기 만들기

사용자로부터 입력 받기///이름, 나이 - 입력, 출력Console.Write("이름 입력 : ");string name = Console.ReadLine();Console.Write("나이 입력 : ");int age = int.Parse(Console.ReadLine());Console.WriteLine($"이름 : {name}, 나이 : {ag

dev-jen.tistory.com

 

 

C# - 조건문과 반복문 - 조건문과 반복문 완전 정복 - 기초 개념부터 실습까지 + 삼항 연산자

📘 조건문과 반복문 1 - if, else if, 중첩 조건문, switch, 삼항 연산자🔍 조건문 개요조건문은 주어진 조건식의 결과에 따라 프로그램의 제어 흐름을 변경하는 제어문이다.if 문if 문은 조건식이 참

dev-jen.tistory.com

 

 

C# - 배열과 컬렉션 정리 - 1차원부터 다차원, 리스트부터 딕셔너리까지 + 예제

📘 배열과 컬렉션배열1차원 배열동일한 데이터 유형을 연속적으로 저장하며, 인덱스를 통해 요소에 접근할 수 있다. 배열은 선언 시 고정된 크기를 가지며, 크기 이상의 데이터는 저장할 수 없

dev-jen.tistory.com

 

 

C# - 메서드와 구조체 완전 정복: 재사용성부터 구조 설계 + 구조체 메모리

🧩 메서드란 무엇인가?✅ 메서드의 정의메서드(Method)는 프로그램에서 특정한 작업을 수행하도록 정의된 코드 블록이다.복잡한 코드를 기능별로 분리하여 모듈화함으로써 코드의 재사용성, 가

dev-jen.tistory.com

 

 

C# - 틱택토 게임

using System;class Program{ static char[] board = { '1', '2', '3', '4', '5', '6', '7', '8', '9' }; static int turn = 1; // 홀수: X, 짝수: O static bool gameEnded = false; static void Main(string[] args) { while (!gameEnded) { Console.Clear(); DisplayBo

dev-jen.tistory.com

 

 

C# - 객체지향 프로그래밍(OOP) + 클래스와 객체 + 상속과 다형성

🧱 클래스와 객체의 핵심 개념 정리📌 객체지향 프로그래밍(OOP)의 4가지 핵심 원칙캡슐화(Encapsulation)관련된 데이터와 기능을 하나의 단위로 묶고 외부로부터 숨긴다. 필드와 메서드를 클래스

dev-jen.tistory.com

 

 

C# - 고급 문법 정복하기 (제너릭, ref/out)

🛠️ C# 고급 문법 정복하기 (제너릭, ref/out)📦 제너릭(Generic) - 타입에 유연한 코드 만들기제너릭이란?클래스나 메서드가 다양한 자료형을 처리할 수 있도록 해주는 기능 형태로 사용하며, 코드

dev-jen.tistory.com

 

 

C# - Console SnakeGame(콘솔 스네이크 게임) + 활용 예제

이번 과제로 스네이크 게임을 만들게 되었다 만들면서 느낀거지만.... 코딩테스트 준비를 열심히 해야겠다는 생각이 들었다ㅠㅜ.. GPT의 도움을 많이 받았고 이걸 통해서 활용 예제도 많이 다뤄

dev-jen.tistory.com

 

 

C# - Tuple(튜플) vs Struct(구조체)

✅ 튜플이란?서로 다른 타입의 데이터를 한 번에 묶어서 저장할 수 있는 구조배열이나 리스트처럼 하나의 타입만 저장하는 게 아니라,여러 값을 하나의 단위로 다룰 수 있어🔸 기본 예제var perso

dev-jen.tistory.com

 

 

C# - ConsoleKey(콘솔키)

✅ ConsoleKey란?ConsoleKey는 C#에서 키보드의 실제 키를 표현하기 위한 **열거형(enum)**이야.예를 들어, 키보드의 화살표 키, Enter, A, B, 숫자 1~9, ESC 등은모두 ConsoleKey의 값으로 표현할 수 있어.✅ 사용

dev-jen.tistory.com

 

 

C# - List(tuple) vs Dictionary

한참 리스트의 튜플로 코드로 장난치고 있었는데 그럼 딕셔너리와의 엄청난 치이점이 뭘까.. 싶었다물론 리스트와 딕셔너리도 비슷하게 사용할 수 있다.List items = new List{ (0, "나무칼"), (1, "나무

dev-jen.tistory.com

 

 

C# - 스택 프레임이란? (Stack Frame) vs 스택(Stack)

🧠 스택 프레임이란?함수를 호출할 때마다 생기는 임시 메모리 공간이자 작업 단위 블록각 함수마다 **자신만의 공간(프레임)**을 갖고, 거기서 매개변수, 지역 변수, 복귀 주소 등을 저장해✅

dev-jen.tistory.com

 

 

C# - Linq(Language Integrated Query)

🧠 LINQ란?LINQ는 "Language Integrated Query"의 약자로,C# 코드 안에서 SQL처럼 데이터를 쉽게 조회하고 가공할 수 있게 해주는 문법이야.✅ LINQ의 목적배열, 리스트, 딕셔너리, 데이터베이스 등 여러 종류

dev-jen.tistory.com

 

 

C# - C#으로 간단한 아이템 매니저 구현하기 - List와 LINQ로 컬렉션 관리 연습

public class ItemInstance{ public int id; // 유니크한 아이디 public int itemId; // 같은 종류의 아이템끼리 공유하는 ID // 기타 필요한 속성들...}public class ItemManager{ private List _items; public ItemManager(List items) { _ite

dev-jen.tistory.com

 

 

C# - 콘솔 블랙잭 게임 & 사용되는 예제들

1. 게임 기획게임 목표 정의 (21점을 넘지 않으면서 딜러보다 높은 점수 획득)플레이어 수 (1인 vs 딜러)승패 조건 정의카드 규칙 요약 (A=1 또는 11, J/Q/K=10, 숫자카드=해당 숫자)2. 기본 구조 설계클

dev-jen.tistory.com

 

C# - 인터페이스와 열거형 (Interface, enum)

✅ 인터페이스란 무엇인가요?객체지향 프로그래밍을 공부하면서 인터페이스는 정말 많이 등장하는 개념이다.클래스와 비슷해 보이지만, 사용하는 목적이 분명히 다르다.이번 글에서는 인터페

dev-jen.tistory.com

 

 

C# - 예외처리(Exception Handling)

✅ 예외 처리(Exception Handling) - 프로그램을 안전하게 지키는 방패C#을 비롯한 대부분의 언어에서는 **예외(Exception)**라는 개념이 있다.예외는 프로그램 실행 중에 발생하는 예상하지 못한 상황을

dev-jen.tistory.com

 

 

C# - 값형(Value Type)과 참조형(Reference Type) 그리고 박싱(Boxing) & 언박싱(Unboxing)

📦 값형과 참조형, 그리고 박싱과 언박싱 완전 정복하기!이번엔 C#을 공부하면서 헷갈리기 쉬운 개념 중 하나인**값형(Value Type)**과 참조형(Reference Type), 그리고그 사이에서 왔다갔다 하는 박싱(Bo

dev-jen.tistory.com

 

 

C# - 델리게이트와 람다, 함수도 변수처럼! + LINQ

🎯 델리게이트와 람다 - 함수도 변수처럼 다룰 수 있다?!이번엔 드디어 **델리게이트(delegate)**와 람다(lambda) 개념에 대해 배웠다.처음엔 "함수를 변수처럼 넘긴다고?" 싶어서 어려웠는데,직접 써

dev-jen.tistory.com

 

 

C# - Nullable 타입과 null 조건 연산자

❓ C# Nullable 타입과 null 조건 연산자 완전 정복프로그래밍을 하다 보면 "값이 없을 수도 있는 상황"이 자주 발생한다.예를 들어, 점수가 없을 수도 있고, 데이터가 존재하지 않을 수도 있다.이럴

dev-jen.tistory.com

 

 

C# - StringBuilder - 문자열 성능 최적화

🧱 StringBuilder - 문자열 성능 최적화의 열쇠C#에서 문자열을 다룰 때 가장 흔하게 쓰는 건 string 타입이다.그런데 문자열을 반복해서 붙이고 수정할 일이 많아지면,string을 계속 쓰는 건 성능적으

dev-jen.tistory.com

 

 

C# - TextRPGGame(Console)

🧙‍♂️ 텍스트 기반 RPG 게임 (Text RPG)간단한 콘솔 기반의 텍스트 RPG 게임입니다.2일간 집중 개발하여 기본적인 전투, 아이템, 레벨업, 저장/불러오기 등의 기능을 구현했습니다. ✨ 주요 기능

dev-jen.tistory.com

 

 

C# - Big-O 표기법 정리 – 알고리즘 성능의 기준

📊 Big-O 표기법 완벽 정리 – 알고리즘 성능의 기준1. Big-O란 무엇인가?Big-O 표기법은 **알고리즘의 효율성(시간 또는 공간 사용량)**을 수학적으로 표현하는 방식이다.입력의 크기 n에 따라 알고

dev-jen.tistory.com

 

 

C# - 시간 복잡도 vs 공간 복잡도

1. 개념 정리⏱️ 시간 복잡도 (Time Complexity)알고리즘이 실행되는 데 걸리는 연산 횟수를 입력 크기 n에 따라 수학적으로 표현한 것O(n), O(n²), O(log n)처럼 Big-O 표기법으로 나타냄실제 시간(초)이

dev-jen.tistory.com

 

 

C# - 정렬 알고리즘 – 선택, 삽입, 퀵, 병합 정렬 비교

🔀 정렬 알고리즘 – 선택, 삽입, 퀵, 병합 정렬 비교1. 정렬 알고리즘이란?정렬 알고리즘은 **주어진 데이터를 일정한 순서(예: 오름차순, 내림차순)**로 재배열하는 알고리즘이다.알고리즘의 기

dev-jen.tistory.com

 

 

C# - 삽입 정렬 (Insertion Sort)

📥 삽입 정렬 (Insertion Sort) – 직관적이고 효율적인 정렬 방법1. 개념삽입 정렬은 카드 정렬과 비슷한 방식으로 작동한다.두 번째 원소부터 시작해서, 앞쪽 정렬된 구간에 자신이 들어갈 자리를

dev-jen.tistory.com

 

 

C# - 퀵 정렬 (Quick Sort)

⚡ 퀵 정렬 (Quick Sort) – 빠르고 강력한 분할 정복 정렬 알고리즘1. 개념퀵 정렬은 분할 정복(Divide and Conquer) 전략을 사용하는 정렬 알고리즘이다.중간 기준값(피벗)을 선택하여 작은 값은 왼쪽,

dev-jen.tistory.com

 

 

C# - 병합 정렬 (Merge Sort)

🧩 병합 정렬 (Merge Sort) – 항상 안정적인 분할 정복 정렬1. 개념병합 정렬은 분할 정복(Divide and Conquer) 알고리즘의 대표 예시이다.배열을 반으로 나누고, 나눈 배열을 각각 정렬한 후, 두 정렬된

dev-jen.tistory.com

 

 

C# - 정렬 알고리즘 비교 요약

🧠 정렬 알고리즘 비교 요약 & 선택 가이드✅ 1. 주요 정렬 알고리즘 비교표알고리즘평균 시간 복잡도최악 시간 복잡도공간 복잡도정렬 안정성특징선택 정렬O(n²)O(n²)O(1)❌ 불안정구조 단순, 교

dev-jen.tistory.com

 

 

C# - 탐색 알고리즘 정리 – 선형 탐색 vs 이진 탐색

🔍 탐색 알고리즘 정리 – 선형 탐색 vs 이진 탐색1. 탐색 알고리즘이란?탐색 알고리즘은 주어진 데이터에서 원하는 값을 찾는 알고리즘이다.정렬된 데이터든 아니든, 가장 기본이 되는 핵심 알

dev-jen.tistory.com

 

 

C# - 그래프 탐색 알고리즘 – DFS vs BFS

🌐 그래프 탐색 알고리즘 – DFS vs BFS1. 그래프 탐색이란?그래프 탐색 알고리즘은 노드와 간선으로 이루어진 구조에서 특정 노드까지 도달하거나 모든 노드를 방문하는 알고리즘이다.대표적으

dev-jen.tistory.com

 

 

C# - 다익스트라 알고리즘 (Dijkstra Algorithm)

🚀 다익스트라 알고리즘 (Dijkstra Algorithm)1. 개념다익스트라 알고리즘은 가중치가 있는 그래프에서 한 정점에서 다른 모든 정점까지의 최단 거리를 구하는 알고리즘이다.음수 간선이 없을 때 사

dev-jen.tistory.com

 

 

C# - 벨만-포드 알고리즘 (Bellman-Ford Algorithm) vs 다익스트라

🛤️ 벨만-포드 알고리즘 (Bellman-Ford Algorithm)1. 개념벨만-포드 알고리즘은 **음의 가중치(음수 간선)**가 있는 그래프에서도 단일 시작점으로부터 최단 거리를 구할 수 있는 알고리즘이다.시간 복

dev-jen.tistory.com

 

 

C# - 플로이드-워셜 알고리즘 (Floyd-Warshall)

🌉 플로이드-워셜 알고리즘 (Floyd-Warshall)1. 개념플로이드-워셜 알고리즘은 모든 노드 쌍 간의 최단 거리를 구하는 알고리즘이다.음수 간선이 있어도 동작하지만, 음수 사이클이 있으면 사용 불

dev-jen.tistory.com

 

 

C# - 알고리즘 핵심 개념 정리(DP, Greedy, Divide and Conquer, Backtracking, Union-Find, Disjoint Set, DFS, BFS)

1. 🧠 동적 계획법 (Dynamic Programming, DP)개념복잡한 문제를 작은 하위 문제로 나누어 풀고, 결과를 저장해 재사용조건: 최적 부분 구조, 중복 부분 문제구현 방식Top-down: 재귀 + 메모이제이션Bottom-up

dev-jen.tistory.com

반응형