Notice
Recent Posts
Recent Comments
Link
«   2026/06   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
Tags
more
Archives
Today
Total
관리 메뉴

뭐라도 쓰겠지

25.03.06 / 비트 플래그를 이용한 퀘스트 클리어 여부 확인 본문

프로그래밍/C

25.03.06 / 비트 플래그를 이용한 퀘스트 클리어 여부 확인

김데피 2025. 3. 6. 18:37
#include <stdio.h>

// 퀘스트 나열
enum Quest {
	q1 = 1,
	q2 = 2,
	q3 = 4,
	q4 = 8,
	q5 = 16,
	q6 = 32,
	q7 = 64,
	q8 = 128
};

//현재 클리어 퀘스트
unsigned char player_quest;

// 퀘스트 클리어
void ClearQuest(int* _questNum, int _quest) {
	*_questNum |= _quest;
}

// XOR 연산자를 이용한 퀘스트 포기
void ForgiveQuest(int* _questNum, int _quest) {
	*_questNum ^= _quest;
}

// AND NOT 연산자를 이용한 퀘스트 포기
void ForgiveQuest(int* _questNum, int _quest) {
	*_questNum &= ~_quest;
}

// 클리어한 퀘스트 출력
void PrintQuest(int _quest) {
	if (_quest & q1) printf("1번 퀘스트 클리어\n");
	if (_quest & q2) printf("2번 퀘스트 클리어\n");
	if (_quest & q3) printf("3번 퀘스트 클리어\n");
	if (_quest & q4) printf("4번 퀘스트 클리어\n");
	if (_quest & q5) printf("5번 퀘스트 클리어\n");
	if (_quest & q6) printf("6번 퀘스트 클리어\n");
	if (_quest & q7) printf("7번 퀘스트 클리어\n");
	if (_quest & q8) printf("8번 퀘스트 클리어\n");
	printf("\n");
}

int main(void) {
	ClearQuest(&player_quest, (q1 | q2 | q3));
	PrintQuest(player_quest);

	ClearQuest(&player_quest, (q4 | q5 | q6));
	PrintQuest(player_quest);

	ClearQuest(&player_quest, (q7 | q8));
	PrintQuest(player_quest);

	ForgiveQuest(&player_quest, q1);
	PrintQuest(player_quest);

	ForgiveQuest(&player_quest, q1);
	PrintQuest(player_quest);

	return 0;
}

코드를 살펴보면 퀘스트 포기가 XOR 연산자를 사용하는게 있고 AND NOT 연산자를 사용하는게 있다. 두 개의 차이에 대해 알아보자.

// XOR 연산자를 이용한 퀘스트 포기
void ForgiveQuest(int* _questNum, int _quest) {
	*_questNum ^= _quest;
}

예를 들어 현재 q1, q3, q5를 완료한 상태라 가정하자. 그럼 player_quest에 저장된 값은 00010101(2)이다. 만약 여기서 퀘스트 q1, q3을 포기를 하는 경우

 00010101 // q1 q3 q5 클리어
^00000101 // q1 q3 포기
=00010000 // q5만 남음

XOR 연산을 통해 00010000(2)가 되어 q5만 성공에 남아있게 된다. 그런데 만약 성공하지 않은 퀘스트를 포기하려 하면 어떻게 될까?

 00010101 // q1 q3 q5 클리어
^00000010 // q2 포기
=00010111 // q1 q2 q3 q5 클리어?

이렇게 성공하지 않은 상태로 포기한 q2가 성공처리 되는 오류가 발생한다. 실제 인게임이라면 버그로 퀘스트가 깨져버린 상황이 된거다.

 

이번엔 AND와 NOT 연산을 통해 퀘스트를 포기해보자.

// AND NOT 연산자를 이용한 퀘스트 포기
void ForgiveQuest(int* _questNum, int _quest) {
	*_questNum &= ~_quest;
}

위의 예시와 똑같이 q1, q3, q5를 완료한 상태라 가정하자. 똑같이 player_quest에 저장된 값은 00010101(2)이다. 만약 여기서 퀘스트 q1, q3을 포기하는 경우

 00010101 // q1 q3 q5클리어
~00000101 // q1 q3 포기
&11111010 // 반전한 q1, q3값
 00010000 // 겹치는 q5만 1로 남음

여기까진 똑같은 결과가 나온다. 그렇다면 q2를 포기하는 경우엔 어떻게 될까?

 00010101 // q1 q3 q5 클리어
~00000010 // q2를 NOT 연산
&11111101 // 그 이후 player_quest와 ~q2를 AND 연산
=00010101 // q1 q3 q5 클리어로 오류 발생하지 않음!

이렇게 q2가 클리어되지 않고 정상적으로 처리된다. 

 

물론 게임 내에서 클리어하지 않은 퀘스트를 포기 처리하지 못하게 방지하면 되지만, 애초부터 이렇게 코드를 작성하면 오류가 발생할 가능성이 없어진다.