📌 as 와 is 연산자
class Parents { }
class Child : Parents { }
Parents parents = new Parents();
Child child = new Child();
// as 연산자
child = parents as Child;
bool isPossible = (child != null);
// output : False
// parents를 Child로 형변환이 가능하면 변환하여 리턴하고
// 불가능하면 'null' 값을 리턴한다.
// is 연산자
bool isPossible = child is Parents;
// output : True | 자식은 부모가 될 수 있는가?
bool isPossible = parents is Child;
// output : False | 부모는 자식이 될 수 있는가?
📌 형변환 하기 전에 사용하면 안전하게 가능하다.
if(child is Parents == true)
{
Parents newParents = (Parents)child;
}
🎉 한 장 요약
struct MonsterDB // 몬스터의 코드를 주면 해당하는 변수값들을 반환한다.
{
public MonsterDB(MonsterCode code, out string name, out int hp,
out int atk, out int def, out int exp, out int gold)
{
switch (code)
{
case MonsterCode.Goblin:
name = "고블린";
hp = 60;
atk = 20;
def = 5;
exp = 10;
gold = 200;
break;
case MonsterCode.Orc:
// 생략
break;
default:
break;
}
}
}
class Monster : Unit
{
string name = "";
MonsterCode monstercode; // 몬스터를 구별해줄 enum 클래스
int hp; int atk; int def; int exp; int gold;
public Monster(MonsterCode code)
{
monstercode = code;
new MonsterDB(code, out name, out hp, out atk, out def, out exp, out gold);
}
}
📌 어느 것이 코드를 덜 치고 편할까 하여서 class Goblin, class Orc
같이 각자 만드는 게 아닌 변수 값의 묶음을 가진 struct
로 초기화하여 하나의 클래스만 사용, class Monster
하나로 관리 해보았다.
✅ 몬스터의 변수들이 한 곳에 모여 있어서 밸런스를 맞추기 편하였다.
✅ enum
으로 몬스터 코드를 관리하여서 똑같은 클래스에서 오는 혼란은 딱히 없었다.
⛔ ※ 개성 없는 몬스터, 모두 같은 변수와 함수를 사용한다. 숫자 놀이 같은 느낌이었다.
⛔ 딱히 각자 클래스로 만드는 것과 비교해서 더 편한 것도 덜 치는 것도 없었다.
다음엔 이 방식으로 안 할 것 같다.
🔨 필요한 변수값이 늘어나면 매개 변수
의 코드도 길어지는데 배열로 줬다가 쓰는 것도 가능할 듯
🔨 Namespace
로 비슷한 클래스를 우르르 만들어 묶고 필요할 때만 꺼내 먹어보자
🎉 한 장 요약
https://github.com/Chu-Nyan/Project_TextGame
✅ 지금까지 배운 함수들을 효율을 떠나 전부 동원하여 사용하였다.
능동적으로 생성자, 상속, 구조체 등등 사용해 보았으며 장단점들을 알게 되었다.
✅ 구현해보고 싶던 기능, 선택지에 따른 결과를 플레이어에게 적용과 자동전투와 랜덤 텍스트 기능을 넣었다.
✅ 팀원의 도움을 받아 특정 역할의 기능에서 발생 할 수 있는 버그들을 찾아냈다.
// while문으로 exp가 levelUpExp를 넘지 않을 때까지 진행된다.
while (exp >= levelUpExp) | if (exp >= levelUpExp) | void LevelUp()
{ | { | {
LevelUp(); | LevelUp(); | exp -= levelUpExp;
} | } | }
// 이렇게 하지 않으면 levelUp을 10번 할 경험치를 얻어도 딱 한 번만 작동한다
// 그러면 exp를 얻을 때마다 1번만 레벨업을 하며 총 10번의 경험치를 획득해야지 정상화된다.
⛔ Text의 줄맞춤이 무엇보다 힘들었다. 한글의 한 글자는 char
가 맞지만 폰트는 두 글자 크기를 차지한다.
⛔ 선택 사항으로 여러가지 기능들이 제시되었지만 기간 내에 할 수 있는 정확한 견적을 내지 못했다.
그로 인해 예상 외의 기능들을 추가할 땐 기존 코드들도 수정하게 되는 경우가 있었다.
하지만 고수는 예상 밖의 상황들을 대처하는 능력도 가지고 있다.
🔨 다음 프로젝트에서는 클래스 다이어그램
, 플로우차트
먼저 꼭 작성 해볼 것!!
🎉 한 장 요약
// 선입선출 자료구조 'Queue' // 후입선출형 자료구조 'Stack'
Queue<int> queue = new Queue<int>(); Stack<int> stack = new Stack<int>();
queue.Enqueue(1); stack.Push(1);
queue.Enqueue(2); stack.Push(2);
queue.Enqueue(3); stack.Push(3);
foreach (var num in queue) foreach (var num in stack)
{ {
Console.WriteLine(num); Console.Write(num);
} }
// output : 123 // output : 321
📌 선입선출(FIFO)
먼저 입력된 요소가 먼저 출력된다.
후입선출(LIFO)
늦게 입력된 요소가 먼저 출력된다.
📌 인덱서(int[1])
, Key
로 접근하는 게 아닌 순서대로 사용하는 자료 구조이다
📌 자주 사용하는 함수
queue.Enqueue(); | stack.Push(); // 요소를 자료 구조형에 맞게 추가
|
queue.Dequeue(); | stack.Pop(); // 출력에서 제거되고 요소도 반환
|
queue.Peek(); | stack.Peek(); // 출력에서 제거하지않고 요소만 반환
|
queue.Contains(); | stack.Contains(); // 원하는 요소가 있는 지만 확인, 'bool' 반환
|
queue.Clear(); | stack.Clear(); // 모든 요소를 제거
🔨 4개의 줄을 사용하는 배틀 로그 창에 선입선출을 사용한다면 채팅창 처럼 한 줄씩 올라오는
느낌을 줄 수 있을 듯!
🎉 한 장 요약
/* 1차원 배열 */
// 선언 & 초기화
int[] arr1 = new int[2];
// [2]는 배열의 크기
int[] arr2 = new int[] { 2, 2 };
// 초기화를 하면서 배열 요소에 값을 채워줄 수있다.
// 배열의 크기는 요소 수로 결정된다.
/* 다차원 배열 */
int[,] arr3 = new int[,] // 길이 지정자 '2, 3'는 없어도 된다.
{
{ 1, 1, 1 },
{ 2, 2, 2 }
};
// 초기화는 위와 동일하게 진행하면 된다.
// 길이 지정자는 요소 수로 유추할 수 있으므로 필요 없는 것
/* ※ 가변 배열 */
int[][] arr4 = new int[][]
{
new int[] { 1, 1,},
new int[] { 2,2,2,2,}
};
// arr4[1] 요소 수 : 2, arr4[2] 요소 수 : 4
// 요소의 수를 다르게 할 수 있다.
// 배열과는 다르게 new 연산자를 사용하여야한다.
⛔ 다차원 배열을 의미도 모른채 항상 [][]
으로 만들었다
📌 배열의 장점은 인덱스로 빠르게 접근 가능 하다는 것이다.O(1)
📌 한번 정해진 배열의 크기는 고정된다.
배열은 연속되는 메모리에 저장하는 것인데 이것과 관련 있을 거라는 뇌피셜++
추가로, 요소가 한 개만 있든 꽉 차있든 메모리는 똑같다.
📌 삽입과 삭제에서 비효율적O(n)
이다. 그림처럼 일일이 하나씩 옮겨 줘야한다.
📌List의 경우 전부 동일하지만 추가에서 O(1)
이다.
🎉 한 장 요약
- 다른 사람의 코드 읽기
자료 구조들을 다양하게 사용하게 된 계기는 같은 결과물을 두고 다른 팀원은 어떻게 하였나?
였다.
나는 자료 구조를 대하여 알고는 있었다 하지만, array
와 list
만 사용하였다.
예를 들어, '🔨카드 게임에서 카드를 섞고 배분하기'를 만들어보자
List<Card> cards = new List<Card> {new Card(), new Card() };
CardShuffle(cards)
int currentCardNum = 0;
void FilpCard()
{
Card myCard = cards[currentCardNum];
currentCardNum++;
Card yourCard = cards[currentCardNum];
currentCardNum++;
}
List<Card> cards = new List<Card> { new Card(), new Card() };
Queue<Card> shuffledCards = new Queue<Card> { };
CardShuffle(cards, shuffledCards);
Card myCard = shuffledCards.Dequeue();
Card yourCard = shuffledCards.Dequeue();
// ※주의 `나중에 배웠으니 2번이 더 좋은 알고리즘이다!!`는 절대 성립할 수 없다.
// '이런저런 상황에선 2번이 더 좋은 알고리즘이다!!'가 맞는 명제이다.
✅ 이렇게 다른 사람의 코드를 읽음으로써 알고리즘을 짤 때 내가 사용할 수 있는 도구가 추가됐고
그 도구는 다른 사람의 코드를 읽음으로써 얻게 된 것
이다.
- 코~~~드 캇-타!
솔직히 제노사이드 캇-타!가 생각나서 입에 착착 감긴다.
근데 cut
가 아니라 kata
이다. 뜻은 '방법이나 과정을 연습하기 위한 일련의 동작'이다.
현재는 비기너 단계부터 하고 있지만, 과제 때문에 중급 단계로 잠깐 풀어봤다.
제한된 메모리, 실행 시간을 충족하는 알고리즘을 만들어 내는 게 절대 쉬운 일이 아니었다.
for 문
과 if
로만 해결할 수 있는 게 아니었다.
배웠지만 외면했던 고급 문법
을 사용해야지 쉽고 간편하게 풀렸다.
어쩌면 이제는 달팽이 그만 잡고 슬라임 잡으러 가야 금방 레벨 업 하지 않을까?
그런 의미로 다음주에는 시간이 날때 정렬 알고리즘을 직접 배워보자
📌 기억해야 할 이번 주 키워드
알고리즘이란?
// 문제를 해결하는 방법이나 절차를 '자세하게' 설명하는 과정
매개변수(파라미터), 인자?
CardShuffle(/*인자*/); // 호출
void CardShuffle(/*매개변수*/) {} // 함수
인덱스?
// 배열이나 리스트의 [?], ?에 입력하는 요소들의 위치