자료구조
- 컴퓨터 과학에서 데이터를 효율적으로 저장, 관리, 접근하기 위한 방법을 연구하는 분야.
- 정의 : 데이터 요소들을 체계적으로 구조화하는 방식
- 목적 : 데이터의 효율적인 저장,검색/ 메모리 사용 최적화/ 알고리즘 성능 향상
- 주요 자료구조 : 배열,스택,큐,트리,그래프,해시 테이블
- 중요성: 효율적인 프로그램 설계 기초, 알고리즘 구현 핵심 요소, 대규모 데이터 처리
자료형
데이터의 최소 표현 단위 : bit
8bit = 1byte
같은 정수형이라도, bit의 사용에 따라 표현 범위가 달라진다.
U가 붙은 자료형(unsigned)는 음수를 표현하지 못함.
Int32 intValue = 0; // -21~21억까지 표현 가능
UInt32 uintValue = 0; // 0~42억까지 표현 가능
Int64 longValue = 0; // -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
UInt54 ulongValue = 0; // 0~18,446,744,073,709,551,615
float floatValue = 0.0f; //3.4E +/- 38(7자리 숫자)
배열(Array)
특징
- 장점
1. 빠른 요소 접근 : 인덱스를 통한 시간 복잡도
2. 메모리 효율성 : 연속된 메모리 할당으로 캐시 효율 높음
3. 간단한 구현 : 기본적인 프로그래밍 구조로 쉽게 사용 가능
4. 다차원 데이터 표현 : 행렬, 이미지 등의 데이터 표현에 적합
- 단점
1. 고정된 크기 : 동적 크기 조절 불가
2. 삽입과 삭제의 비효율성 : 요소 이동 필요
3. 메모리 낭비 가능성 : 선언된 ㅋ느기만큼 항상 메모리 차지
4. 연관 데이터 저장의 어려움 : 다른 자료구조에 비해 복잡한 데이터 구조 표현이 어려움
* [100] 과 [10, 10]은 메모리 공간을 똑같이 사용한다.
* 배열에서 사용되는 Contains는 매우 느린 함수다
활용(연습)
우선 사용할 4개의 함수의 배열들을 만들어준다.
//플레이어 점수를 저장하는 배열
public int[] playerScores = new int[5];
//아이템 이름을 저장하는 배열
priavte string [] itemNames = {"검", "방패", "포션", "활", "마법서"};
//적 프리팹을 저장하는 배열
public GameObject[] ememyPrefabs;
//맵의 타일 타입을 저장하는 2D 배열
private int[,] mapTiles = new int [10,10];
start 함수에 넣어 두고, 테스트할 하나의 함수 빼고는 주석 처리를 해서 연습한다.
void Start()
{
PlayerScoresExampel();
ItemInventoryExample();
EnemySpawnExample();
MapGenerationExample();
}
첫 번째로 플레이어의 점수를 랜덤으로 배정하고, 최고 점수와 평균 점수를 구해본다.
void PlayerScoresExample()
{
//플레이어 점수 할당
for (int i = 0; i < playerScores.Length; i++)
{
plyerScores[i] = Random.Range(100, 1000);
}
//최고 점수 찾기
int highScore = playerScore.Max();
Debug.Log(&"최고 점수: {highestScore}");
//평균 점수 계산
double averageScore = playerScore.Average();
Debug.Log($"평균 점수: {averageScore:F2}");
}
우선 for 반복문으로 모든 플레이어에게 100~1000까지의 점수를 랜덤으로 할당한다.
그리고 highscore라는 변수에 플레이어 스코어중 최고인 점수를 할당한다.
평균 점수는 averageScore이라는 변수에 플레이어 스코어의 평균 점수를 할당한다.
여기서 Max와 Average는 린큐를 사용한다면 제공되는 함수이다. linq를 사용하지 않을 때의 방식은 참고에 적을 것이다.
void ItemInventoryExample()
{
//랜덤 아이템 선택
int randomIndex = Random.Range(0, itemNames.Length);
string selectedItem = itemNames[randomIndex];
Debug.Log($"선택된 아이템: {selectedItem}");
string itemName = "포션";
//아이템 포함 여부
bool hasPotion1 = Contains(itemName);
Debug.Log($"포션 보유 여부: {hasPotion1}");
//특정 아이템 검색
string searchItem = "방패";
bool hasPotion2 = itemNames.Contains(searchItem);
Debug.Log($"포션 보유 여부: {hasPotion2}");
}
다음은 조금은 다른 방식인 몬스터를 랜덤 위치에 소환하는 것이다.
void EnemySpawnExample()
{
if (enemyPrefabs != null && enemyPrefabs.Length > 0)
{
//랜덤한 위치에 적 생성
Vector3.spawnPosition = new Vector3(Random.Range(-10f, 10f), 0, Random.Range(-10f, 10f));
int randomEnemyIndex = Random.Range(0 , enemyPrefabs.Length);
Instantiate(enemyPrefabs[randomEnemyIndex], spawnPosition, Quaternion,identity);
Debug.Log($"적 생성됨 : {enemyPrefabs[randomEnemyIndex].name}");
}
else
{
Debug.Log("적 프리팹이 할당되지 않았습니다);
}
}
0과 null은 다른 것이기 때문에 0도, null도 아니라면 이라는 조건을 달아준다.
스폰포지션이라는 변수를 선언하고, 새로운 위치인 (-10~10, 0, -10~10) 사이의 값에 랜덤값으로 할당한다.
여러가지 인덱스(큐브, 스피어 등의 모양이자 프리팹)을 생성하기 위해 randomEnemyIndex라는 변수를 설정하고, 프리팹의 갯수만큼의 길이에서 뽑아 쓰도록 한다. 예를들어 우리는 큐브와 스피어 만 사용했기에 0 혹은 1이라는 index가 들어갈 것이다.
Instantiate 함수를 사용해 enemyPrefabs를 생성하는데 이때 생성되는 적 프리팹은 randomEnemyIndex의 값인 0,1을 통해 결정되고, 우리의 경우 순서대로 0은 Cube, 1은 Sphere입니다.
그리고 디버그 로그를 통해 생성되었다고 알리는 코드입니다.
마지막으로 간단한 맵을 랜덤으로 생성하는 과정입니다.
void MapGenerationExample()
{
//간단한 맵 생성 ( 0: 빈 공간, 1: 벽)
for (int x = 0; x < mapTiles.GetLength(0); x++)
{
for (int y = 0; y < mapTiles.GetLength(1); y++)
{
mapTiles[x, y] = Random.value > 0.8f ? 1 : 0;
}
}
//맵 출력
//string mapString = "생성된 맵:\n";
for (int x = 0; x <mapTiles.GetLength(0); x ++)
{
for ( int y = 0; y < mapTiles.GetLength(1); y++)
{
CubeTiles [ x, y ] = mapTiles[ x, y] == 1 ? Instantiate(Cube) : Instantiate(Sphere);
}
}
}
0~1 사이의 값이반환되는 Random.value라는 것을 통해 값을 반호나하고, 0.8이 넘으면 1, 넘지 않으면 0을 mapTiles[x,y]에 할당한다.
그리고 mapTiles가 1이면 Cube를 0이라면 Sphere를 생성한다.
맵을 출력하는 방법은 위의 방식(삼항연산자의 사용) 말고도 if 문을 사용해서도 할 수 있다.
if ( mapTiles[x,y] = 1)
{
CubeTiles[x,y] = instantiate(Cube, new Vector3(x-5, y-5, 0), Quaternion.identity);
}
else
{
CubeTiles[x,y] = instantiate(Sphere, new Vector3(x-5,y-5,0), Quaternion.identity);
}
이렇게 출력하게 되면 다음과 같은 결과가 나온다.
20%의 확률로 1이 나오고, 그에따라 Sphere가 생성되며 나머지 80%의 확률로 0이 나와 Cube가 생성된다.
처음에 mapTiles를 [10,10]이라고 선언했으므로 10x10의 빼곡한 정사각형 모양의 맵이 나오게 된다.
* instantiate() 는 생성 함수이다. (복제본을 생성하는 기능)
*Quaternion.identity는 회전 값이 0인, 회전에 영향을 주지 않는 기본 요소, 항등 상태이다.
linq 없이 구현해보기
우선 위에 있는 namespace를 지우게 되면 아래와 같이 Max라는 기능이 에러가 뜨게 된다.
이를 해결할 방법은 Max를 클릭하고 Ctrl / Alt + Enter 를 눌러 using System.Linq; 를 추가해 주는 방법과
따로 Max 함수를 만들어 주는 방법이 있다.
다음은 Max와 Average를 자체적으로 만든 것이다.
int maxValue = 0;
for (var i = 0; i < playerScores.Length; i++)
{
if (playerScores[i] > maxValue)
{
maxValue = playerScore[i]
}
}
int totalValue = 0;
float averageValue = 0;
for (var i = 0; i < playerScores.Length; i++)
{
totalValue += playerScores[i]
}
averageValue = totalValue / (float)playerScores.Length;
Debug.Log(&"평균 점수1: {averageValue:F2}");
모든 값을 더한 뒤, playerScores의 길이로 나눠주어 평균 값을 찾는 방식이다.
이와 같이 기능을 만들었으면, wrider의 기능으로 감싸줘 사용할 수 있다.
*(float)는 형변환으로 하지 않으면 값이 다를 수 있다.
*:F2는 소숫점 둘째 자리까지 표현한다는 뜻이다.
GIT과 Git fork
- Git : 분산 버전 관리 시스템, 코드의 변경 이력을 추적하고 여러 개발자가 협업할 수 있도록 돕는 도구
- Fork : 특정 git 저장소를 복사하여 자신의 계정으로 가져오는 기능
줄바꿈 기능
- 기본 문자열 : \n
Console.WriteLine("첫 번째 줄\n두 번째 줄");
- Console.WriteLine();에서는 기본적으로 끝에 줄 바꿈 기능을 추가함
- Console.Write();는 그런 기능 없음.
문자열에 \n을 추가하는 것으로 줄 바꿈 가능
string message = "첫 번째 줄\n두 번째 줄";
Console.WriteLine(message);
출력 결과
첫 번째 줄
두 번째 줄
- 확장 : 여러줄은 Raw String Literals, 줄바꿈 포함 저장 StreamWriter, 문자열 분할 Split(배열분리)
더 공부해야 하는 것 : Property 등
확실히 모든 코드를 한 번씩 더 써보니까 이해가 조금은 되는 것 같음. 내일도 화이팅~
'TIL' 카테고리의 다른 글
[멋쟁이사자처럼 부트캠프 TIL회고] Unity 게임개발 16일차 (0) | 2024.12.05 |
---|---|
[멋쟁이사자처럼 부트캠프 TIL회고] Unity 게임개발 3기 15일차 (0) | 2024.12.03 |
[멋쟁이사자처럼 부트캠프 TIL회고] Unity 게임개발 3기 13일차 (0) | 2024.12.02 |
[멋쟁이사자처럼 부트캠프 TIL회고] Unity 게임개발 3기 11일차 (3) | 2024.11.29 |
[멋쟁이사자처럼 부트캠프 TIL 회고] Unity 게임개발 3기 10일차 (0) | 2024.11.28 |