#include <string>
#include <vector>
using namespace std;
int solution(int storey) {
int answer = 0;
int maxDividor = 1;
int dividor = 1;
while(maxDividor < storey)
{
maxDividor *= 10;
}
while(dividor <= maxDividor)
{
int nowNum = storey / dividor;
nowNum %= 10;
int nextNum = storey / (dividor * 10);
nextNum %= 10;
if(nowNum > 5
|| (nowNum == 5 && nextNum >= 5))
{
answer += (10 - nowNum);
storey += (10 - nowNum) * dividor;
}
else
{
answer += nowNum;
storey -= nowNum * dividor;
}
dividor *= 10;
}
if(storey != 0)
{
answer++;
}
return answer;
}
주말이 지나 오늘 코드를 보니 문제점을 알겠습니다.
maxDividor을 구할 때 storey보다 커질 때 까지 maxDividor * 10을 하고 있는데,
maxDividor은 storey 보다 작거나 같은 값이니 10을 마지막에 나누어 주어야 하네요.
수정된 코드 - 통과됨
#include <string>
#include <vector>
using namespace std;
int solution(int storey) {
int answer = 0;
int maxDividor = 1;
int dividor = 1;
while(maxDividor <= storey)
{
maxDividor *= 10;
}
maxDividor /= 10;
while(dividor <= maxDividor)
{
int nowNum = storey / dividor;
nowNum %= 10;
int nextNum = storey / (dividor * 10);
nextNum %= 10;
if(nowNum > 5
|| (nowNum == 5 && nextNum >= 5))
{
answer += (10 - nowNum);
storey += (10 - nowNum) * dividor;
}
else
{
answer += nowNum;
storey -= nowNum * dividor;
}
dividor *= 10;
}
if(storey != 0)
{
answer++;
}
return answer;
}
아 이거 정답 처리 받았던 문제였네요.
잘못 풀었다.
이 문제가 이전에 풀다 말았던 문제네요.
#include <string>
#include <vector>
#include <queue>
using namespace std;
struct Node
{
pair<int, int> prevPos;
pair<int, int> curPos;
};
bool CheckPInRange(const vector<string>& map, pair<int, int> pos)
{
vector<pair<int,int>> dir = {{0,1}, {0, -1}, {-1, 0}, {1, 0}};
queue<Node> nodes;
Node node;
node.prevPos = pos;
node.curPos = pos;
while(!nodes.empty())
{
Node curNode = nodes.front();
nodes.pop();
pair<int, int> prev = curNode.prevPos;
pair<int, int> cur = curNode.curPos;
for(int i = 0; i < 4; i++)
{
pair<int, int> newPos = cur;
newPos.first += cur.first + dir[i].first;
newPos.second += cur.second + dir[i].second;
if(newPos.first < 0 || newPos.first >= 5
|| newPos.second < 0 || newPos.second >= 5)
{
continue;
}
else if(map[newPos.first][newPos.second] == 'X')
{
continue;
}
else if(newPos == prev)
{
continue;
}
else if(map[newPos.first][newPos.second] == 'P')
{
return true;
}
Node newNode;
newNode.prevPos = cur;
newNode.curPos = newPos;
nodes.push(newNode);
}
}
return false;
}
vector<int> solution(vector<vector<string>> places) {
vector<int> answer;
for(const vector<string>& place : places)
{
vector<pair<int, int>> points;
bool bIsSafe = true;
for(int i = 0; i < place.size(); i++)
{
for(int j = 0; j < place[i].size(); j++)
{
if(place[i][j] == 'P')
{
if(CheckPInRange(place, make_pair(i, j)))
{
bIsSafe = false;
break;
}
}
}
if(!bIsSafe)
{
break;
}
}
answer.push_back(bIsSafe ? 1 : 0);
}
return answer;
}
음 코드를 다시 살펴보니 CheckPInRange에서 queue에 집어넣는 코드가 빠져있고, 거리를 체크하는 것도 빠져있네요.
수정 코드 - 실패 정답률 하락
#include <string>
#include <vector>
#include <queue>
using namespace std;
struct Node
{
pair<int, int> prevPos;
pair<int, int> curPos;
};
bool CheckPInRange(const vector<string>& map, pair<int, int> pos)
{
vector<pair<int,int>> dir = {{0,1}, {0, -1}, {-1, 0}, {1, 0}};
queue<Node> nodes;
Node node;
node.prevPos = pos;
node.curPos = pos;
nodes.push(node);
while(!nodes.empty())
{
Node curNode = nodes.front();
nodes.pop();
pair<int, int> prev = curNode.prevPos;
pair<int, int> cur = curNode.curPos;
for(int i = 0; i < 4; i++)
{
pair<int, int> newPos = cur;
newPos.first += cur.first + dir[i].first;
newPos.second += cur.second + dir[i].second;
int dist = abs(pos.first - newPos.first) +
abs(pos.second - newPos.second);
if(dist > 2)
{
continue;
}
if(newPos.first < 0 || newPos.first >= 5
|| newPos.second < 0 || newPos.second >= 5)
{
continue;
}
else if(map[newPos.first][newPos.second] == 'X')
{
continue;
}
else if(newPos == prev)
{
continue;
}
else if(map[newPos.first][newPos.second] == 'P')
{
return true;
}
Node newNode;
newNode.prevPos = cur;
newNode.curPos = newPos;
nodes.push(newNode);
}
}
return false;
}
vector<int> solution(vector<vector<string>> places) {
vector<int> answer;
for(const vector<string>& place : places)
{
vector<pair<int, int>> points;
bool bIsSafe = true;
for(int i = 0; i < place.size(); i++)
{
for(int j = 0; j < place[i].size(); j++)
{
if(place[i][j] == 'P')
{
if(CheckPInRange(place, make_pair(i, j)))
{
bIsSafe = false;
break;
}
}
}
if(!bIsSafe)
{
break;
}
}
answer.push_back(bIsSafe ? 1 : 0);
}
return answer;
}
정확성 30.2%를 받았습니다.
코드를 다시 살펴보니 또 잘못된 부분을 확인했습니다.
for(int i = 0; i < 4; i++)
{
pair<int, int> newPos = cur;
newPos.first += cur.first + dir[i].first;
newPos.second += cur.second + dir[i].second;
newPos.first = cur.first + dir[i].first ; 나
newPos.first += dir[i].first; 로 작성했어야 했네요.
수정하니 예시 테스트 케이스에서 실패하네요.
어디에서 또 잘못되어 있을까..
거리가 2여도 한바퀴 돌아서 제자리로 돌아올 수 있었네요.
일단 원위치로 돌아오는 것을 막도록 수정했습니다.
#include <string>
#include <vector>
#include <queue>
using namespace std;
struct Node
{
pair<int, int> prevPos;
pair<int, int> curPos;
};
bool CheckPInRange(const vector<string>& map, pair<int, int> pos)
{
vector<pair<int,int>> dir = {{0,1}, {0, -1}, {-1, 0}, {1, 0}};
queue<Node> nodes;
Node node;
node.prevPos = pos;
node.curPos = pos;
nodes.push(node);
while(!nodes.empty())
{
Node curNode = nodes.front();
nodes.pop();
pair<int, int> prev = curNode.prevPos;
pair<int, int> cur = curNode.curPos;
for(int i = 0; i < 4; i++)
{
pair<int, int> newPos = cur;
newPos.first += dir[i].first;
newPos.second += dir[i].second;
int dist = abs(pos.first - newPos.first) +
abs(pos.second - newPos.second);
if(dist > 2 || newPos == prev || newPos == pos)
{
continue;
}
if(newPos.first < 0 || newPos.first >= 5
|| newPos.second < 0 || newPos.second >= 5)
{
continue;
}
else if(map[newPos.first][newPos.second] == 'X')
{
continue;
}
else if(map[newPos.first][newPos.second] == 'P')
{
return true;
}
Node newNode;
newNode.prevPos = cur;
newNode.curPos = newPos;
nodes.push(newNode);
}
}
return false;
}
vector<int> solution(vector<vector<string>> places) {
vector<int> answer;
for(const vector<string>& place : places)
{
vector<pair<int, int>> points;
bool bIsSafe = true;
for(int i = 0; i < place.size(); i++)
{
for(int j = 0; j < place[i].size(); j++)
{
if(place[i][j] == 'P')
{
if(CheckPInRange(place, make_pair(i, j)))
{
bIsSafe = false;
break;
}
}
}
if(!bIsSafe)
{
break;
}
}
answer.push_back(bIsSafe ? 1 : 0);
}
return answer;
}
이동 횟수 제한도 추가했습니다. 거리 2니까 4 정도로 제한했습니다.
#include <string>
#include <vector>
#include <queue>
using namespace std;
struct Node
{
pair<int, int> prevPos;
pair<int, int> curPos;
int moveCnt = 0;
};
bool CheckPInRange(const vector<string>& map, pair<int, int> pos)
{
vector<pair<int,int>> dir = {{0,1}, {0, -1}, {-1, 0}, {1, 0}};
queue<Node> nodes;
Node node;
node.prevPos = pos;
node.curPos = pos;
node.moveCnt = 0;
nodes.push(node);
while(!nodes.empty())
{
Node curNode = nodes.front();
nodes.pop();
pair<int, int> prev = curNode.prevPos;
pair<int, int> cur = curNode.curPos;
for(int i = 0; i < 4; i++)
{
pair<int, int> newPos = cur;
newPos.first += dir[i].first;
newPos.second += dir[i].second;
int dist = abs(pos.first - newPos.first) +
abs(pos.second - newPos.second);
if(dist > 2 || newPos == prev || newPos == pos
|| curNode.moveCnt >=4)
{
continue;
}
if(newPos.first < 0 || newPos.first >= 5
|| newPos.second < 0 || newPos.second >= 5)
{
continue;
}
else if(map[newPos.first][newPos.second] == 'X')
{
continue;
}
else if(map[newPos.first][newPos.second] == 'P')
{
return true;
}
Node newNode;
newNode.prevPos = cur;
newNode.curPos = newPos;
newNode.moveCnt = curNode.moveCnt + 1;
nodes.push(newNode);
}
}
return false;
}
vector<int> solution(vector<vector<string>> places) {
vector<int> answer;
for(const vector<string>& place : places)
{
vector<pair<int, int>> points;
bool bIsSafe = true;
for(int i = 0; i < place.size(); i++)
{
for(int j = 0; j < place[i].size(); j++)
{
if(place[i][j] == 'P')
{
if(CheckPInRange(place, make_pair(i, j)))
{
bIsSafe = false;
break;
}
}
}
if(!bIsSafe)
{
break;
}
}
answer.push_back(bIsSafe ? 1 : 0);
}
return answer;
}
메인보드 prime b365m-a, GPU GTX-2060
메인보드 호환 여부, DRAM 지원, 발열 등등 알아봐야 할 것이 너무 많습니다.
몇 년전에는 9만원이던 것이 지금은 34만원이고 가격대가 장난 아니네요.
이게 내려가긴 할 지...
https://www.yopc.co.kr/shop/item.php?it_id=5565683998
발열이 적고 가성비가 좋다고 합니다. 이때 DRAM이 중요하다는 것을 알게 되었습니다.
SATA, M.2라는 SSD 종류가 존재한다는 것도 알게 되었네요.
1TB 살돈이면 돈 더 보태서 2TB를 사는 게 나은 상황이라 아예 중고를 싸게 살 것인지
추후 업그레이드를 생각해서 4.0이나 5.0으로 살 것인지 -> 현재 보드는 3.0 지원 더 높은 것 호환 여부 확인 필요, 호환되도 3.0 수준으로 하향될 것
https://prod.danawa.com/info/?pcode=17788451&cate=112760
4.0, 2TB 52만
https://www.daangn.com/kr/buy-sell/xpg-sx8200-pro-m-2-ssd-512gb-1tb-sd9g499mqhhm/
중고, 보증기간 끝남, 1TB 15만
괜찮은 중고 전문 판매 업체를 소개받아 그곳에서 동생과 찾아던 ssd를 절반보다 높은 수준의 가격으로 구매하게 되었습니다.
2TB도 좋지만 지금 메인보드 상태상 4.0은 제대로 받아들이지 못하고 최대한 언리얼에만 사용한다면 용량이 괜찮을 것이라는 이야기를 해주셨습니다.
https://mystisle.notion.site/35d25e4e7f808021a6aee9fb57b510dd?pvs=73
ABP_Mannequin_Base
프로퍼티 엑세스 노드로 값을 가져와서 사용하고, Blueprint Thread Safe Update Animation에서 값을 갱신합니다.
Blueprint Thread Safe Update Animation는 그래프 업데이트 직전, Work Thread에서 애니메이션 블루프린트가 업데이트될 때 실행된다고 합니다.
즉 값 갱신 -> 그래프 업데이트 보장
스레드 세이프 기능은 다른 스레드로 인한 데이터 덮어쓰기를 방지하기 위해 객체의 데이터 직접 엑세스하는 대신, Property Access 시스템을 사용하여 데이터에 접근합니다. 안전할 때에 값을 복제해두는 방식.
애니메이션 그래프를 살펴보니 애니메이션을 직접 참조하지 않고 몽타주와 링크드 애니메이션 레이어가 그래프의 특정 지점에서 포즈를 재생할 수 있는 진입점을 제고한다고 합니다.
ABPMannequin_Base의 주요 목점은 이러한 진입점을 함께 블렌딩하는 것이라고 하는데, 이 방식 덕분에 애니메이션이 필요할 때만 로드할 수 있게 된다고 합니다.
예를 들어, 무기에는 필요한 몽타주 및 링크드 애니메이션 레이어에 대한 참조가 저장되므로 무기가 로드될 때만 데이터가 로드됩니다.
더 자세히 예를 들면, B_WeaponInstance_Shotgun은 몽타주 및 링크드 애니메이션 레이어에 대한 참조를 보유하고 있습니다. 해당 데이터는 B_WeaponInstance_Shotgun이 로드될 때만 로드됩니다.
B무기 인스턴스_베이스는 무기용 애니메이션 레이어를 연결하는 역할을 합니다.
내부 함수를 확인하던 중 정리를 해보았습니다.
Velocity를 LocalVelocity2D로 변환할 때 Unroatate Vector를 사용하는 이유
GetVelocity()는 월드 공간(World Space) 벡터를 반환합니다. 예를 들어 캐릭터가 북동쪽으로 달리면 (1, 1, 0) 같은 값이 나옵니다. 문제는 "캐릭터가 앞으로 달리는가, 옆으로 달리는가" 는 캐릭터가 어느 방향을 바라보느냐에 따라 달라진다는 점입니다.
UnrotateVector(WorldVelocity2D, WorldRotation) 은 월드 속도를 캐릭터 회전의 역방향으로 돌려서 캐릭터 로컬 공간 벡터(LocalVelocity2D) 로 바꿉니다. 이 결과의 X성분 = 전후, Y성분 = 좌우가 됩니다.
이후 블렌드스페이스, 발 IK 등에서 이 성분을 직접 사용한다고 합니다.
CalculateDirection이 WorldVelocity2D와 WorldRotation 둘 다 필요한 이유
CalculateDirection()은 "이동 방향 벡터"와 "캐릭터 전방 벡터" 사이의 부호 있는 각도를 계산합니다:
둘 다 있어야 atan2(cross, dot) 형태로 −180°~+180° 반환이 가능합니다.
무슨 함수인지 의아했는데 각도의 형태로 이동방향을 나타내기 위해 사용한다고 합니다.
SelectCardinalDirectionFromAngle의 역할
연속 각도(−180~+180°)를 4방향 열거형(AnimEnum_CardinalDirection)으로 변환합니다.
단순 스냅이 아니라 세 가지 스마트 기능이 추가됩니다:
|기능|파라미터|효과|
|-|-|-|
|히스테리시스|CardinalDirectionDeadZone|경계선 근처에서 방향이 빠르게 왔다갔다 깜박이는 현상 방지|
|이전 방향 참조|CurrentDirection (이전 프레임 값)|히스테리시스 기준으로 사용|
|정지 시 방향 고정|UseCurrentDirection = WasMovingLastUpdate|캐릭터가 멈추면 마지막 이동 방향을 유지해서 재출발 시 스냅 방지|
GCNL_Death에 대해
GCNL 접두사 의미
GCNL = GameplayCueNotify_BurstLatent
| 접두사 | 클래스 | 특성 |
|---|---|---|
| GCN_ | UGameplayCueNotify_Burst | 단발성, 같은 프레임 완료 |
| GCNL_ | UGameplayCueNotify_BurstLatent | 단발성이지만 지연 가능 (Timeline, AsyncNode 사용 OK) |
| (별도) | UGameplayCueNotify_Looping | Active/WhileActive/Remove 이벤트 처리 |
봉재 튜터님과 ssd 상담 받을 때 보원님을 불러서 같이 이야기
라이라 애니메이션은 Advanced locomotion system v4이라는 플러그인에서 발전된 것?
Advanced locomotion system v4이 언리얼에 팔려가서 통합이 되었고 그것을 Lyra에서
애니메이션들을 인터페이스화 해서 서로 연관성을 줄이기 위해 AnimLayerInterface가 도입됨.
스테이트 내부에 사이클이 존재