오늘의 할일
1. 코드카타 정리
2. 팀프로젝트 정리
3. 다음 학습 목표
배열 array의 i번째 숫자부터 j번째 숫자까지 자르고 정렬했을 때, k번째에 있는 수를 구하려 합니다.
예를 들어 array가 [1, 5, 2, 6, 3, 7, 4], i = 2, j = 5, k = 3이라면
array의 2번째부터 5번째까지 자르면 [5, 2, 6, 3]입니다.
1에서 나온 배열을 정렬하면 [2, 3, 5, 6]입니다.
2에서 나온 배열의 3번째 숫자는 5입니다.
배열 array, [i, j, k]를 원소로 가진 2차원 배열 commands가 매개변수로 주어질 때, commands의 모든 원소에 대해 앞서 설명한 연산을 적용했을 때 나온 결과를 배열에 담아 return 하도록 solution 함수를 작성해주세요.
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
vector<int> solution(vector<int> array, vector<vector<int>> commands) {
vector<int> answer;
// commands에 들어있는 [i, j, k]을 처음부터 끝까지 하나씩 확인
for (int c = 0; c < commands.size(); c++) {
int i = commands[c][0]; // 시작 위치
int j = commands[c][1]; // 끝 위치
int k = commands[c][2]; // 찾을 위치 (몇 번째인지)
vector<int> temp; // 잘라낸 숫자들을 임시로 모아둘 vector
// 배열 자르기
for (int idx = i - 1; idx < j; idx++) {
temp.push_back(array[idx]); // 임시 vector에 숫자 하나씩 담기
}
// 임시 vector 정렬
// vector에 담긴 숫자들을 오름차순으로 정렬
sort(temp.begin(), temp.end());
// k번째 수 찾아서 push_back
answer.push_back(temp[k - 1]);
}
return answer;
}
AI가 작성한 코드
#include <vector>
#include <algorithm> // nth_element 사용
using namespace std;
vector<int> solution(vector<int> array, vector<vector<int>> commands) {
vector<int> answer;
// 정답 배열이 메모리를 재할당하지 않도록 미리 공간을 예약해둡니다.
answer.reserve(commands.size());
// 인덱스 대신 범위 기반 for문과 참조(&)를 사용하여 코드를 깔끔하게 만듭니다.
for (const auto& cmd : commands) {
// 1. for문으로 하나씩 담는 대신, 반복자(Iterator)를 이용해 한 번에 복사합니다.
vector<int> temp(array.begin() + cmd[0] - 1, array.begin() + cmd[1]);
// 2. 전체를 정렬하는 sort 대신, k번째 값만 찾아내는 nth_element를 사용합니다.
nth_element(temp.begin(), temp.begin() + cmd[2] - 1, temp.end());
// 3. k번째 위치에 안착한 값을 정답 바구니에 담습니다.
answer.push_back(temp[cmd[2] - 1]);
}
return answer;
}
std::nth_element (가장 중요)
전체가 정렬될 필요 없이 'k번째 숫자' 딱 하나만 알면 됨
nth_element는 전체를 정렬하지 않고, 지정한 위치(k번째)에 올바른 숫자 딱 하나만 꽂아 넣고 끝내버림(평균 시간 복잡도 O(N)). 수백만 개의 데이터를 다룰 때 연산 속도를 끌어올리는 최적화 기법
한 줄로 끝내는 벡터 복사 생성
for문을 돌면서 push_back으로 숫자를 하나씩 찔러 넣으면, 배열 크기가 커질 때마다 컴퓨터가 메모리를 이사(Reallocation)하느라 속도가 느려짐. 대신 (array.begin() + 시작, array.begin() + 끝) 처럼 주소(반복자)를 통째로 넘겨주면, 컴퓨터가 필요한 메모리 크기를 한 번에 계산해서 복사
reserve()를 통한 메모리 예약
commands의 개수만큼 정답이 나올 거라는 걸 이미 알고 있어서 시작하자마자 answer.reserve(commands.size());로 "나 이만큼 자리 쓸 거니까 미리 비워둬!"라고 선언. 이렇게 하면 데이터가 들어올 때마다 메모리를 새로 발급받는 오버헤드를 원천 차단할 수 있음
진짜 오늘 하루 종일 회의만 한 것 같음. 그래도 드디어 우리 팀 프로젝트의 전체적인 기틀이 딱 잡혀서 속은 시원하다. 맨날 '그 폐병원 게임', '좀비 프로젝트' 이렇게 부르다가 드디어 정식 타이틀이 생기니까 이제 진짜 시작이구나 싶음.
게임 이름 확정: Dead Hospital: Code Exit
회의록 보니까 이름 후보만 한 7개는 있었던 것 같은데, 결국 직관적인 게 최고라는 결론이 났음. 하도 이쁜 이름이 많아서 세번째 투표까지 해서 확정됨. 타이틀이 딱 정해지니까 앞으로 맵 조명이나 사운드를 얼마나 어둡고 건조하게 가져가야 할지 머릿속에 그림이 확 맞춰진 느낌임.
세계관이랑 스토리, 엔딩까지 다 픽스
스토리는 솔직히 뻔하지만 원래 아는 맛이 제일 무섭다고, '비밀 생체 실험 부작용' 클리셰로 배경은 당연히 인적 끊긴 대형 폐쇄 병동.
여기서 기획적으로 제일 신경 쓴 부분은 주인공 설정인데, 그냥 운 나쁘게 갇힌 일반인이 아니라 이 병원의 '마지막 실험체'로 설정했음. 이렇게 하니까 플레이어가 왜 하필 이 지옥 같은 곳에 혼자 갇혀있는지 당위성도 챙길 수 있고, 나중에 후반부 갈수록 환각을 본다거나 실험 부작용 때문에 시야가 일그러지는 식의 연출을 넣기에도 딱 좋을 것 같음.
좀비들 다 때려잡는 액션은 우리 팀 규모나 기간 생각하면 절대 불가... 철저하게 숨고 도망치는 '생존'과 '퍼즐' 베이스로...
주인공은 파밍한 총과 총알로 감염체들을 죽이고 맵 곳곳을 배회하는 감염체들 시야랑 청각을 피해서 웅크려 다니는 게 기본 이동 방식임. 최종 목표는 병원을 나갈 수 있는 유일한 비상구를 여는 건데, 이 문을 열려면 맵 곳곳에 숨겨진 '마스터 카드키'를 파밍해야 함. 그냥 줍는 게 아니라, 방탈출 류의 기믹들을 엄청 섞어둘 예정임.
엔딩 연출도 오늘 확정됨
고생해서 카드키 다 찾고 마지막 셔터 문을 열면, 지상으로 이어지는 엄청 길고 수직 사다리가 나옴. 주인공은 숨 헐떡이면서 그 사다리를 타고 올라감.
근데 끝까지 다 올라갔을 때 밖이 어떤 상황인지(망했는지, 군대가 대기 중인지)는 절대 안 보여줌. 화면이 서서히 화이트아웃 전환되면서 브금 깔리고 바로 엔딩 크레딧.
각자 찾은 거 바로 다운 안 받고, 디스코드 화면 공유 켜놓고 다 같이 검토부터 했음. "이건 너무 깨끗한 것 같다. 좀 더 더럽게 생긴 게 필요하다", "이건 엔진 버전이 안 맞는다" 이러면서 엄청 쳐냈음. 덕분에 꽤 통일성 있는 에셋들로만 뽑힘.
하루 종일 떠들고 컨셉 정하느라 기 빨렸는데, 그래도 드라이브에 에셋 압축파일들 쫙 정리된 거 보니까 되게 든든함. 기획서로만 존재하던 폐병원이 이제 좀 실체가 생기는 느낌? 내일은 취합한 에셋들 일단 깡통 프로젝트에 다 올려서 먼저 확인하고,
기본 공격 가능
공격이 적에게 맞았는지 판정 가능
적에게 실제 데미지 적용
특수공격 1개 이상 작동
쿨타임 중 공격/스킬 재사용 제한
범위 공격으로 여러 대상에게 데미지 적용 가능
권총 탄약 소비 및 재장전 가능
다른 시스템에서 데미지/무기/탄약 정보를 사용할 수 있는 기본 함수 제공
부터 해봐야겠다... 갈 길이 먼데 재밌을 것 같음.
에셋을 거의 찾았으니까 내일은 남은 에셋 다 찾으면 깃 LFS하고 각 맡은 파트 코드 작성 시작하기