스파르타 게임개발종합반(Unity)/TIL - 본캠프 매일 공부 기록

2024.04.23 TIL1 - VisualStudio 디버깅, 삼항 연산자, List, Dictionary, Stack, Queue, HashSet, struct

테크러너 2024. 4. 23.

C# 문법 종합반 2주차 강의 정리

 

VisualStudio 디버깅

Break Point 걸기

해당 라인의 가장 왼쪽에 동그라미 클릭해서 `break point` 걸기

해당 라인에서 `F9` 누르기

 

디버깅

한 줄씩 : `F10`

메소드로 : `F11`

 

 

 

디버그 창 안뜰 때

디버그 창

디버그 → 창 → `조사식, 자동, 지역, 호출 스택` 추가

 

 

삼항 연산자

`3항 연산자`는 if 문의 간단한 형태로, 조건식의 결과에 따라 두 값을 선택하는 연산자입니다.

(조건식) ? 참일 경우 값 : 거짓일 경우 값;

아래는 예시입니다. 예시에서 보이는 삼항 연산자와 if else 문이 동일한 역할을 합니다.

int currentExp = 1200;
int requiredExp = 2000;

# 삼항 연산자
string result = (currentExp >= requiredExp) ? "레벨업 가능" : "레벨업 불가능";
Console.WriteLine(result);


# if else 문
if (currentExp >= requiredExp)
{
    Console.WriteLine("레벨업 가능");
}
else
{
    Console.WriteLine("레벨업 불가능");
}

 

 

 

문자 하나 입력 받기

Console.Write("문자를 입력하세요: ");
char input = Console.ReadLine()[0];

 `Console.ReadLine()`은 문자열을 입력받기 때문에 문자 하나를 입력받으려면 위와 같이 사용하면 됩니다!

 

 

원하는 값 입력받을 때까지 무한 반복하기

int sum = 0;

while (true)
{
    Console.Write("숫자를 입력하세요: ");
    int input = int.Parse(Console.ReadLine());

    if (input == 0)
    {
        Console.WriteLine("프로그램을 종료합니다.");
        break;
    }

    if (input < 0)
    {
        Console.WriteLine("음수는 무시합니다.");
        continue;
    }

    sum += input;
    Console.WriteLine("현재까지의 합: " + sum);
}

Console.WriteLine("합계: " + sum);

사용자에게 계속 입력받게 할 때 사용할 수 있는 코드입니다.

0일 때 `break`로 인해 무한루프가 종료됩니다.

음수는 무시하고 `continue`로 인해 양수일 때까지 계속 숫자를 입력하라고 합니다.

 

 

Random().Next(시작할 인덱스, 끝낼 인덱스+1)

string[] choices = { "가위", "바위", "보" };
string playerChoice = "";
string computerChoice = choices[new Random().Next(0, 3)];

배열안에 랜덤을 넣을 수 있다니.. 강력하다 C#...

 

 

컬렉션

컬렉션(Collection)은 자료를 모아 놓은 데이터 구조를 의미

  • 컬렉션은 배열과 비슷한 자료 구조
  • 배열과는 다르게 크기가 가변적
  • C#에서는 다양한 종류의 컬렉션을 제공
  • 사용하기 위해서는 `System.Collections.Generic` 네임스페이스를 추가
  • `Length`대신 `Count`를 사용

List

  • `List`는 가변적인 크기를 갖는 배열
  • List를 생성할 때는 List에 담을 자료형을 지정
  • 보통 배열은 메모리 공간에 연속적으로 할당되어 있고, 리스트는 연속적이지 않다. 하지만 C#에서의 리스트는 내부 구현된 코드를 살펴보면 배열로 구현된 것을 확인할 수 있다. 즉, C#에서의 리스트는 메모리 공간에 연속적으로 할당되어 있다.
  • capacity = 전체 용량, count = 현재 공간의 크기
  • 리스트는 설정된 capacity만큼 공간을 할당해둔 후 할당한 공간보다 넘어갈시 또 capacity만큼의 공간을 복사하여 생성한다. ex) capacity가 10이면 처음 공간은 10, 다음은 20.
  • 리스트는 기본적으로 capacity가 4로 설정되어 있다.
  • 그래서 매번 4만큼을 복사하고 생성하면 효율이 좋지 않다. 처음부터 capacity로 용량을 설정해두면 복사와 생성작업 횟수가 줄어든다.
List<int> numbers = new List<int>(); // 빈 리스트 생성
numbers.Add(1); // 리스트에 데이터 추가
numbers.Add(2);
numbers.Add(3);
numbers.Remove(2); // 리스트에서 데이터 삭제

foreach(int number in numbers) // 리스트 데이터 출력
{
    Console.WriteLine(number);
}

// 출력 1 3

 

Dictionary

  • `딕셔너리(Dictionary)`는 키와 값으로 구성된 데이터를 저장
  • 딕셔너리는 중복된 키를 가질 수 없으며, `키와 값`의 쌍을 이루어 데이터를 저장
using System.Collections.Generic;

Dictionary<string, int> scores = new Dictionary<string, int>(); // 빈 딕셔너리 생성
scores.Add("Alice", 100); // 딕셔너리에 데이터 추가
scores.Add("Bob", 80);
scores.Add("Charlie", 90);
scores.Remove("Bob"); // 딕셔너리에서 데이터 삭제

foreach(KeyValuePair<string, int> pair in scores) // 딕셔너리 데이터 출력
{
    Console.WriteLine(pair.Key + ": " + pair.Value);
}

 

Stack

  • `Stack`은 `후입선출(LIFO)` 구조를 가진 자료 구조
Stack<int> stack1 = new Stack<int>();  // int형 Stack 선언

// Stack에 요소 추가
stack1.Push(1);
stack1.Push(2);
stack1.Push(3);

// Stack에서 요소 가져오기
int value = stack1.Pop(); // value = 3 (마지막에 추가된 요소)

 

Queue

  • `Queue`는 `선입선출(FIFO)` 구조를 가진 자료 구조
Queue<int> queue1 = new Queue<int>(); // int형 Queue 선언

// Queue에 요소 추가
queue1.Enqueue(1);
queue1.Enqueue(2);
queue1.Enqueue(3);

// Queue에서 요소 가져오기
int value = queue1.Dequeue(); // value = 1 (가장 먼저 추가된 요소)

 

HashSet

  • `HashSet`은 `List`와 거의 유사하지만 `중복되지 않은 요소들`로 이루어진 집합
HashSet<int> set1 = new HashSet<int>();  // int형 HashSet 선언

// HashSet에 요소 추가
set1.Add(1);
set1.Add(2);
set1.Add(3);

// HashSet에서 요소 가져오기
foreach (int element in set1)
{
    Console.WriteLine(element);
}

 

 

배열과 리스트 차이

`리스트`는 `동적으로` 크기를 조정할 수 있어 `배열`과는 다르게 `유연한 데이터 구조`를 구현할 수 있습니다. 하지만, 리스트를 무분별하게 사용하는 것은 좋지 않은 습관입니다.

  1. 메모리 사용량 증가: 리스트는 동적으로 크기를 조정할 수 있어 배열보다 많은 메모리를 사용합니다. 따라서, 많은 데이터를 다루는 경우 리스트를 무분별하게 사용하면 메모리 사용량이 급격히 증가하여 성능 저하를 유발할 수 있습니다.
  2. 데이터 접근 시간 증가: 리스트는 연결 리스트(linked list)로 구현되기 때문에, 인덱스를 이용한 데이터 접근이 배열보다 느립니다. 리스트에서 특정 인덱스의 데이터를 찾기 위해서는 연결된 노드를 모두 순회해야 하기 때문입니다. 이러한 이유로, 리스트를 무분별하게 사용하면 데이터 접근 시간이 증가하여 성능이 저하될 수 있습니다.
  3. 코드 복잡도 증가: 리스트는 동적으로 크기를 조정할 수 있기 때문에, 데이터 추가, 삭제 등의 작업이 배열보다 간편합니다. 하지만, 이러한 유연성은 코드 복잡도를 증가시킬 수 있습니다. 리스트를 사용할 때는 데이터 추가, 삭제 등의 작업을 적절히 처리하는 코드를 작성해야 하므로, 코드의 가독성과 유지보수성이 저하될 수 있습니다.

따라서, 리스트를 무분별하게 사용하는 것은 좋지 않은 습관입니다. 데이터 구조를 선택할 때는, 데이터의 크기와 사용 목적을 고려하여 배열과 리스트 중 적절한 것을 선택해야 합니다.

 

 

struct

struct Person
{
    public string Name;
    public int Age;

    public void PrintInfo()
    {
        Console.WriteLine($"Name: {Name}, Age: {Age}");
    }
}

C언어에서는 메소드는 넣지 못했는데 C#에서는 구조체안에 메소드도 넣을 수 있군요..!

 

구조체와 클래스 차이

구조체(struct)와 클래스(class)는 둘 다 데이터를 그룹화하고 이를 사용자 정의 타입으로 만들어주는 데 사용됩니다. 하지만 몇 가지 중요한 차이점이 있습니다:

상속:

클래스는 다른 클래스로부터 상속을 받을 수 있습니다. 이것은 클래스 간의 계층 구조를 만들 수 있게 합니다. 즉, 부모 클래스의 특성과 동작을 자식 클래스가 상속받아 재사용할 수 있습니다.

구조체는 상속을 지원하지 않습니다.

메모리 할당:

클래스의 인스턴스는 heap 메모리에 할당됩니다. 그래서 클래스의 인스턴스를 생성하면 new 키워드를 사용해야 하고, 메모리 관리는 가비지 컬렉터가 처리합니다.

구조체의 인스턴스는 stack 메모리에 할당될 수도 있고, heap 메모리에 할당될 수도 있습니다. stack에 할당되는 경우에는 값 형식으로 취급되어 메모리가 효율적으로 사용됩니다.

초기화:

클래스의 인스턴스는 생성자를 사용하여 초기화됩니다.

구조체의 인스턴스는 new 연산자를 사용하지 않고, 그 자체로 초기화됩니다.

값 형식 vs. 참조 형식:

구조체는 값 형식(value type)이며, 클래스는 참조 형식(reference type)입니다. 값 형식은 변수가 실제 값을 보유하고 있으며, 메모리에 저장됩니다. 참조 형식은 변수가 실제 객체를 가리키는 포인터입니다.

구조체는 작은 크기의 데이터 저장이나 단순한 데이터 구조에 적합하며, 클래스는 더 복잡한 객체를 표현하고 다양한 기능을 제공하기 위해 사용됩니다.

 

 

 

숙제

숫자 맞추기 게임 만들기

더보기
        static void Main(string[] args)
        {
            for (int i = 2; i < 10; i++)
            {
                for (int j = 1; j < 10; j++)
                {
                    Console.WriteLine($"{i} X {j} = {i * j}");
                }
            }
        }

 

틱택토 게임 만들기

더보기
namespace TicTacToe
{
    internal class Program
    {
        static char[] item = { '1', '2', '3', '4', '5', '6', '7', '8', '9' };
        static int player = 0;
        static char check;
        static int selectNum;
        static int flag = 0; // 0 게임중, 1 승리, -1 무승부
        static void Main(string[] args)
        {
            do
            {
                if (player % 2 == 0) // 플레이어 1
                {
                    check = 'X';
                }
                else // 플레이어 2
                {
                    check = 'O';                  
                }

                PrintBoard();

                Console.Write("선택할 번호 : ");
                string select = Console.ReadLine();
                bool isSelected = int.TryParse(select, out selectNum);

                if (isSelected)
                {
                    if (item[selectNum - 1] != 'X' && item[selectNum - 1] != 'O')
                    {
                        item[selectNum - 1] = check;
                        player++;
                    }
                    else
                    {
                        Console.WriteLine("이미 선택된 칸입니다. 다른칸을 선택해주세요.");
                        Console.ReadLine();
                    }
                }
                else
                {
                    Console.WriteLine("숫자를 입력해주세요.");
                }

                flag = CheckWin();

                Console.Clear(); // 화면 지우기
            } while(flag != 1 && flag != -1);

            if (flag == 1)
            {
                // player++ 때문에 값이 바꼈으니 +1 빼줘야함
                Console.WriteLine($"플레이어 {player % 2}이(가) 이겼습니다.");
            }
            else
            {
                Console.WriteLine("무승부");
            }
        }
        static void PrintBoard()
        {
            Console.WriteLine("플레이어 1: X 와 플레이어 2: O\n");
            Console.WriteLine($"플레이어 {player % 2 + 1}의 차례\n");
            Console.WriteLine("-----|-----|-----");
            Console.WriteLine($"  {item[0]}  |  {item[1]}  |  {item[2]}  ");
            Console.WriteLine("-----|-----|-----");
            Console.WriteLine($"  {item[3]}  |  {item[4]}  |  {item[5]}  ");
            Console.WriteLine("-----|-----|-----");
            Console.WriteLine($"  {item[6]}  |  {item[7]}  |  {item[8]}  ");
            Console.WriteLine("-----|-----|-----");
        }

        // 승리 조건 검사
        static int CheckWin()
        {
            // 가로
            for (int i = 0; i < 7; i += 3)
            {
                if (item[i] == item[i + 1] && item[i + 1] == item[i + 2])
                    return 1;
            }
            // 세로
            for (int i = 0; i < 3; i++)
            {
                if (item[i] == item[i + 3] && item[i + 3] == item[i + 6])
                    return 1;
            }
            // 대각선
            if (item[0] == item[4] && item[4] == item[8])
            {
                return 1;
            }
            else if (item[2] == item[4] && item[4] == item[6])
            {
                return 1;
            }

            // 무승부
            else if (item[0] != '1' && item[1] != '2' && item[2] != '3' && item[3] != '4' && item[4] != '5' && item[5] != '6' &&
                item[6] != '7' && item[7] != '8' && item[8] != '9')
            {
                return -1;
            }
            else { return 0; }
        }
    }
}

 

 

 

 

반응형

댓글