はじめに
今回は列挙型にビット演算を用いて同時にフラグをたてれるようにする記事になります!
突然ですが、こちらのコードを見てみてください。
public enum Magic { Hyado, Gira, Hoimi, Mera }
いわゆる列挙型といういうやつですね。ドラクエの魔法を列挙型で表現してみました。
ただこの魔法を複数習得したいときってないでしょうか?いまの状態だと4つのうち一つしか習得できません。
そんなときはビット演算を用いることで簡単に表現することができます。
ということで早速みていきましょう!
ビットフラグとは
まずはビットフラグという考え方についてみてみましょう。この画像をみてみてください。
これはMagicはint型の10
という数字ですが、2進数で表すと1010
になります。
その1010
に先頭からbool型のメラ・ホイミ・ギラ・ヒャドを対応させているイメージです。
数字が1
ならTrue
,0
ならFalse
という訳ですね。
列挙型を定義する
先程のビットフラグを列挙型にも用いてみましょう。以下のようなコードを書いてみます。
public enum Magics { Hyado = 1 << 0, //2進数だと0001 (10進数だと1) Gira = 1 << 1, //2進数だと0010 (10進数だと2) Hoimi = 1 << 2, //2進数だと0100 (10進数だと4) Mera = 1 << 3 //2進数だと1000 (10進数だと8) }
これで先程のビットフラグの例と対応した列挙型が作成できました。
<<
はビットシフトというもので、1 << 2
という操作をすると0001
(10進数で1)が0100
(10進数で4)という感じで左に2個ずらすことができます。
ちなみにこのように書いてもOKです。
public enum Magics { Hyado = 1 //2進数だと0001 Gira = 2, //2進数だと0010 Hoimi = 4, //2進数だと0100 Mera = 8 //2進数だと1000 }
最後にFlags属性をつけてあげることで完成です。ちなみにこれはあってもなくてもToString
をしたときの表示が変わるくらいで、あまり意味があることではありません。
ただ、一応見て分かりやすいようにお作法だと思っていいでしょう。
[Flags] public enum Magics { Hyado = 1 << 0, //2進数だと0001 (10進数だと1) Gira = 1 << 1, //2進数だと0010 (10進数だと2) Hoimi = 1 << 2, //2進数だと0100 (10進数だと4) Mera = 1 << 3 //2進数だと1000 (10進数だと8) }
またFlag属性を使うときはusing System
を書くことを忘れずにしましょう。
フラグを立てる
フラグを立てるときはOR演算(A | B)を用います。
Magics magics = Magics.Gira | Magics.Mera; //Gira, Mera
これは2進数のこのような性質を用いることで実現しています。
A | B | A|B |
---|---|---|
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 1 |
特定のフラグの操作をしたいとき
加えて特定のフラグの操作をしたいときはこのように書きます。
Magics magics = Magics.Gira | Magics.Mera; //Gira, Mera magics |= Magics.Hoimi; //Gira, Hoimi, Mera magics &= ~Magics.Hoimi; //Gira, Mera
フラグをFalseにするのは少しだけややこしく、AND演算(A & B)とNOT演算(~A)を用います。
A | B | A & B |
---|---|---|
0 | 0 | 0 |
0 | 1 | 0 |
1 | 0 | 0 |
1 | 1 | 1 |
A | ~A |
---|---|
0 | 1 |
1 | 0 |
フラグの判定をする
フラグの判定はAND演算(A & B)を用いて行います。
Magics magics = Magics.Gira | Magics.Mera; //Gira, Mera if((magics & Magics.Mera) == Magics.Mera) { //True } if((magics & Magics.Hyado) == Magics.Hyado) { //Flase }
さいごに
列挙型とビット演算について書かせていただきました。
またメモリ的にも良いという印象を受けますが、C#だとそうでもないっぽい?ようでまだよく分かっていません。
もし分かる方がいらしたら是非コメント等で教えていただけると嬉しいです。