ビット演算を使ってフラグを管理する

ビット演算

1つの変数で複数のフラグを管理するにはビット演算を使った方法が有用です。例えばゲームの進捗管理もできたりします。

サンプルはGo言語を使っています。

1.ビットフラグを用意する

まずビットフラグを用意します。

例えば、ゲームでよく見る以下のような流れがあるとします。まず、それぞれのビットフラグを用意します。

  1. ユーザー名入力
  2. 規約同意
  3. チュートリアルガチャ
  4. チュートリアルバトル
const INPUT_USER_NAME = 1 << 0
const AGREE_TERMS = 1 << 1
const TUTORIAL_GACHA = 1 << 2
const TUTORIAL_BATTLE = 1 << 3

<< は左シフトと言って、2進数で左へずらすことを表しています。右の数値は何回ずらすかを指定しています。

1 << 2の場合は左へ2回ずらすを意味します。
1を2進数で表すと0001になります。これを左へ2回ずらすと0100になります。

2.フラグを保持するための変数を用意し、達成するものを詰めていく

上記のフラグを管理するため変数tutorial_flagを用意します。

達成したものを変数に詰めていくイメージで管理します。

例えば、ユーザー名入力と規約同意が達成したとします。

var tutorial_flag int

// 達成したものを変数に詰め込む
func SetFlag(flag int) {
	// ビット論理和代入演算子を使って引数のフラグを変数に詰めていく
	tutorial_flag |= flag
}

func main() {
	SetFlag(INPUT_USER_NAME)// ユーザー名入力
	SetFlag(AGREE_TERMS)// 規約同意

	fmt.Printf("%04b\n", tutorial_flag)

	// ビット論理積 (&)を使って達成したか否かを確認する
	if tutorial_flag&INPUT_USER_NAME != 0 {
		fmt.Println("ユーザー名入力が達成しました")
	} else {
		fmt.Println("ユーザー名入力が達成していません")
	}

	if tutorial_flag&AGREE_TERMS != 0 {
		fmt.Println("規約同意が達成しました")
	} else {
		fmt.Println("規約同意が達成していません")
	}

	if tutorial_flag&TUTORIAL_GACHA != 0 {
		fmt.Println("チュートリアルガチャが達成しました")
	} else {
		fmt.Println("チュートリアルガチャが達成していません")
	}

	if tutorial_flag&TUTORIAL_BATTLE != 0 {
		fmt.Println("チュートリアルバトルが達成しました")
	} else {
		fmt.Println("チュートリアルバトルが達成していません")
	}
}

出力結果

0011
ユーザー名入力が達成しました
規約同意が達成しました
チュートリアルガチャが達成していません
チュートリアルバトルが達成していません

3.フラグを落としたい場合

// 引数のフラグを落とす
func UnSetFlag(flag int) {
	// 引数のフラグを反転してビット論理積代入(&=)で落とす
	tutorial_flag &= ^flag

	// phpの場合
	// $tutorial_flag &= ~flag;
}

func main() {
	SetFlag(INPUT_USER_NAME) // ユーザー名入力
	SetFlag(AGREE_TERMS)     // 規約同意

	fmt.Printf("%04b\n", tutorial_flag)

	UnSetFlag(INPUT_USER_NAME) // ユーザー名入力のフラグを落としてみる

	fmt.Printf("%04b\n", tutorial_flag)

	// ビット論理積 (&)を使って達成したか否かを確認する
	if tutorial_flag&INPUT_USER_NAME != 0 {
		fmt.Println("ユーザー名入力が達成しました")
	} else {
		fmt.Println("ユーザー名入力が達成していません")
	}

	if tutorial_flag&AGREE_TERMS != 0 {
		fmt.Println("規約同意が達成しました")
	} else {
		fmt.Println("規約同意が達成していません")
	}

	if tutorial_flag&TUTORIAL_GACHA != 0 {
		fmt.Println("チュートリアルガチャが達成しました")
	} else {
		fmt.Println("チュートリアルガチャが達成していません")
	}

	if tutorial_flag&TUTORIAL_BATTLE != 0 {
		fmt.Println("チュートリアルバトルが達成しました")
	} else {
		fmt.Println("チュートリアルバトルが達成していません")
	}
}

出力結果

0011
0010
ユーザー名入力が達成していません
規約同意が達成しました
チュートリアルガチャが達成していません
チュートリアルバトルが達成していません

まとめ

  • 進捗を管理するための変数を用意する
  • 各項目のビットフラグを用意する
  • 達成した項目をビット論理和代入(|=)で変数に詰めていく
  • 達成の判定はビット論理積(&)を使って判断できる。結果が0の場合は達成していない、0じゃなければ達成したことになる
  • フラグを落としたい場合は該当の項目を反転してビット論理積代入(&=)を使うことでフラグを落とせる

コメント

タイトルとURLをコピーしました