이전에 푼 적 있는 문제입니다.
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
struct Data
{
vector<int> data;
int offset;
bool operator<(const Data &d)
{
if(this->data[offset]<d.data[offset])
return true;
else if(this->data[offset]==d.data[offset])
{
if(this->data[0]>d.data[0])
return true;
else
return false;
}
return false;
}
};
bool comp(Data &a, Data &b)
{
if(a<b)
return false;
return true;
}
int solution(vector<vector<int>> data, int col, int row_begin, int row_end) {
int answer = 0;
vector<Data> datas;
for(int i=0;i<data.size();i++)
{
Data d;
d.data=data[i];
d.offset=col-1;
datas.push_back(d);
}
sort(datas.begin(),datas.end());
for(int i=row_begin-1;i<=row_end-1;i++)
{
Data d=datas[i];
int num=0;
for(int j=0;j<d.data.size();j++)
{
num+= d.data[j]%(i+1);
}
answer^=num;
}
return answer;
}
최대한 코드를 보지 않기 위해 조심해야겠네요.
DataTable이 들어오고 data 내부의 모든 속성은 int형입니다.
키 값의 중복이 없다는 것이 보장됩니다.
정렬함수는 입력받은 col을 인덱스 삼아 col번째 컴럼 값을 기준으로 오름차순 정렬
col번째 컬럼의 값이 같다 => 키 값으로 내림차순 정렬
정렬된 데이터에서 S_i를 i 번째 행의 튜플에 대해 각 컬럼의 값을 i 로 나눈 나머지들의 합으로 정의합니다
=> 정렬된 순서가 i이고 data의 모든 컬럼 값을 i로 나눈 나머지의 합을 S로 정의한다.
row_begin ~ row_end의 모든 S를 bitwise XOR한 값을 해시로 삼아서 반환하면 끝.
bitset 사용하는게 좋으려나? 값의 범위가 1000000까지라 좀 핵갈리네요.
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
int staticCol;
bool compare(vector<int>& first, vector<int>& second)
{
return first[staticCol] == second[staticCol] ? first[0] > second[staticCol]
: first[staticCol] < second[staticCol];
}
int solution(vector<vector<int>> data, int col, int row_begin, int row_end) {
int answer = 0;
staticCol = col;
sort(data.begin(), data.end(), compare);
return answer;
}
sort 까지는 완료? 전역변수를 만드는 것이 잘한 짓은 아닌 것 같은데 지금은 더 나은 방법이 생각 안나니 일단 패스.
생각해보니 bitset을 사용하면 xor 사용하는 순간 0이던 부분들이 1이 될 가능성이 엄청 높네요. 굳이 사용할 필요 없이 ^ 연산자를 쓰면 되는 거였어요.
1차 시도 코드
#include <string>
#include <vector>
#include <algorithm>
#include <bitset>
using namespace std;
int staticCol;
bool compare(vector<int>& first, vector<int>& second)
{
return first[staticCol] == second[staticCol] ? first[0] > second[staticCol]
: first[staticCol] < second[staticCol];
}
int solution(vector<vector<int>> data, int col, int row_begin, int row_end) {
int answer = -1;
staticCol = col;
sort(data.begin(), data.end(), compare);
for(int i = row_begin; i <= row_end; i++)
{
int S = 0;
for(int num : data[i])
{
S += (num % data[i][col]);
}
if(answer == -1)
{
answer = S;
}
else
{
answer ^= S;
}
}
return answer;
}
입구컷입니다.
입력값 : [[2, 2, 6], [1, 5, 10], [4, 2, 9], [3, 8, 3]], 2, 2, 3
기대값 : 4
결과값 : 0
2차 입구컷 코드입니다.
#include <string>
#include <vector>
#include <algorithm>
#include <bitset>
using namespace std;
int staticCol;
bool compare(vector<int>& first, vector<int>& second)
{
return first[staticCol] == second[staticCol] ? first[0] > second[staticCol]
: first[staticCol] < second[staticCol];
}
int solution(vector<vector<int>> data, int col, int row_begin, int row_end) {
int answer = -1;
staticCol = col - 1;
sort(data.begin(), data.end(), compare);
for(int i = row_begin; i <= row_end; i++)
{
int S = 0;
for(int num : data[i])
{
S += (num % data[i][col - 1]);
}
answer = answer == -1 ? S : answer ^ S;
}
return answer;
}
col이 0부터가 아니라 1부텅였네요. 그래서 -1씩 해주었습니다.
실행결과 : 7
오늘 자 마지막 시도 코드
#include <string>
#include <vector>
#include <algorithm>
#include <bitset>
using namespace std;
int staticCol;
bool compare(vector<int>& first, vector<int>& second)
{
return first[staticCol] == second[staticCol] ? first[0] > second[0]
: first[staticCol] < second[staticCol];
}
int solution(vector<vector<int>> data, int col, int row_begin, int row_end) {
int answer = -1;
staticCol = col - 1;
sort(data.begin(), data.end(), compare);
for(int i = row_begin; i <= row_end; i++)
{
int S = 0;
for(int num : data[i])
{
S += (num % (i + 1));
}
answer = answer == -1 ? S : answer ^ S;
}
return answer;
}
실행 결과 : 2로 입구컷입니다.
Today I Learned |
Unreal Engine 5|GAS|DataTable|StateTree|C++
ASC->HandleGameplayEvent(Tag, &EventData)는 해당 Tag를 Listen하는 GA를
K2_ActivateAbilityFromEvent로 트리거한다.
TryActivateAbilityByClass와 달리 EventData를 함께 전달하므로
GA Blueprint에서 이벤트 데이터를 직접 활용할 수 있다.
// ❌ Instigator 미설정
FGameplayEventData EventData;
EventData.EventTag = RetrieveGameplayTags::GameplayEvent_Enemy_Attack;
EventData.Target = Target;
// EventData.Instigator → 기본값 nullptr
// ✅ 수정
EventData.Instigator = GetOwner();
GA Blueprint에서 Instigator를 Cast할 때 nullptr이면:
K2_ActivateAbilityFromEvent
→ Cast(EventData.Instigator → Pawn) ← nullptr → CastFailed
→ CastFailed 핀 미연결 → 실행 중단
→ AIMoveTo, PlayMontageAndWait 미실행
에러 로그 없이 GA가 조용히 중단된다. 디버깅이 매우 어렵다.
Instigator / Target / EventTag 3개를 체크리스트로 확인BP Class Defaults
└─ MonsterDataRowName = "Zombie_Basic" ← 여기가 None이면 전체 실패
└─ MonsterDataTable->FindRow(MonsterDataRowName)
└─ Row->PatternSlots (패턴 Row 이름 목록)
└─ EnemyCombatComponent->Initialize(PatternTable, PatternSlots)
BP_Test_EnemyCharacter의 Class Defaults에서 MonsterDataRowName = None.
void ARetrieveEnemyCharacter::InitializeComponents()
{
if (!MonsterDataTable || MonsterDataRowName.IsNone())
{
UE_LOG(LogTemp, Warning, TEXT("설정 없음"));
return; // ← 조기 return
}
// EnemyCombatComponent, DropComponent 초기화 전혀 안 됨
}
결과: PatternSlots 비어 있음 → FindBestPattern 항상 nullptr → 모든 공격 불가.
증상이 "공격이 안 된다"로만 나타나서 원인을 찾는 데 시간이 걸렸다.
| 항목 | 확인 위치 |
|---|---|
| MonsterDataRowName | BP Class Defaults |
| MonsterDataTable | BP Class Defaults |
| PatternSlots 채워짐 여부 | InitializeComponents 로그 |
| PatternTable 유효 여부 | EnemyCombatComponent::Initialize 진입 확인 |
RequestPatternByPriority는 DT에서 패턴을 탐색하고
쿨다운을 관리하는 패턴(특수) 공격 로직이다.
일반 공격도 이 경로로 처리하려다 책임이 뒤섞였다.
EnemyCombatComponent
├── RequestBasicAttack(Target) ← 기본 공격: 탐색 없음, 즉시 발동
├── RequestPatternByPriority(Target) ← 패턴 공격: DT 탐색, 쿨다운 관리
└── ActivateHitbox() / DeactivateHitbox() ← 공용 (ANS에서 호출)
bool UEnemyCombatComponent::RequestBasicAttack(AActor* Target)
{
if (!Target || !PatternTable || BasicAttackRowName.IsNone()) return false;
const FMonsterPatternRow* Row =
PatternTable->FindRow<FMonsterPatternRow>(BasicAttackRowName, TEXT(""));
if (!Row || Row->HitboxBoneName.IsNone()) return false;
ActivePatternRowName = BasicAttackRowName; // ActivateHitbox()가 이 값을 사용
FGameplayEventData EventData;
EventData.EventTag = RetrieveGameplayTags::GameplayEvent_Enemy_Attack;
EventData.Target = Target;
EventData.Instigator = GetOwner();
return ASC->HandleGameplayEvent(..., &EventData) > 0;
}
ActivePatternRowName은 공격 요청 시점에 설정되어,
ANS(AnimNotifyState)가 ActivateHitbox()를 호출할 때 올바른 Row를 찾는 연결고리다.
RequestBasicAttack() / RequestPatternByPriority()
→ ActivePatternRowName 설정
↓
ANS_AttackWindow::NotifyBegin
→ EnemyCombatComponent->ActivateHitbox()
→ PatternTable->FindRow(ActivePatternRowName)
→ 히트박스 위치·크기 적용
이 값이 None이거나 잘못 설정되면 히트박스 전체가 작동하지 않는다.
| 항목 | 기본 공격 (RequestBasicAttack) | 패턴 공격 (RequestPatternByPriority) |
|---|---|---|
| DT 탐색 | 고정 Row (BasicAttackRowName) | 거리·우선순위·쿨다운 기반 탐색 |
| 쿨다운 관리 | 없음 (GA 측에서 처리) | CooldownExpiry 맵으로 관리 |
| 발동 조건 | 없음 | ActivationRange, IsCooldownReady |
| ActivePatternRowName 설정 | BasicAttackRowName 고정 | FindBestPattern 내부에서 설정 |
HandleGameplayEvent의EventData.Instigator를 설정하지 않으면
GA Blueprint에서 Cast가 실패해 에러 없이 조용히 중단된다.- DataTable 기반 초기화는 BP Class Defaults → DataTable Row → 컴포넌트 3단계이므로
어느 한 단계라도 None이면 전체가 실패한다.- 기본 공격과 패턴 공격은 책임이 다르다:
기본 공격은 즉시 발동, 패턴 공격은 탐색과 쿨다운 관리를 포함한다.ActivePatternRowName은 공격 요청 → ANS → 히트박스를 이어주는 핵심 연결고리다.
이 값이 잘못되면 히트박스 전체가 작동하지 않는다.- AI가 생성한 리팩토링 코드에는 중복 순회나 잘못된 필드 할당 같은 미묘한 버그가
섞일 수 있다. 반드시 변경 diff를 직접 검토할 것.
Retrieve — 7th Team2 Final Project | 2026-05-22