VB6 もこんな仕様だっけ?
某学祭用に AuVN-lite を改造したついでに VB のリハビリにと、ゲームの定番リバーシを VB.NET で書いてみた。
で、8x8 の盤面に石を置けるかどうかチェックするとき、盤面を表す配列が Dim board(7, 7) As Integer
と宣言されていたなら、盤面の範囲チェックは
If x < 0 Or x > 7 Or y < 0 Or y > 7 Then Exit Sub
とか書けるが、これでは素直すぎて気に入らない(ぉ ので、x, y の値が 0...7 までしかとらないことを利用して、下位 3 ビットをマスクして上位が立っているかどうかでチェックをすることにした。これなら、値が 8 以上であれば明らかに成り立つし、値が負の数になっても 2 の補数表現であれば上位ビットは必ず立つので成り立つ。
変数が一つであれば当然 x And Not 7
と書くが、x, y の 2 変数をチェックするので
(x And Not 7) Or (y And Not 7)
と書くことになり、分配則を使って (x Or y) And Not 7
と簡単にできる。
最終的には
If (x Or y) And Not 7 <> 0 Then Exit Sub
とかいう文になる.しかしこのコード、このまま書いても正常に動作しない。常に Exit Sub
してしまう。
ステップモード(古)で x, y を定数に置き換えて評価すると正しく結果を返すものの、変数で与えると常に 0 が返る。
これは VB がこの式を Boolean コンテキストとして評価しているためで、VB では論理演算子とビット操作演算子が同じ予約語になっているため、ビット操作であることは明示しなければならない。
この式を Boolean コンテキストとして評価すると、VB の Boolean は非 0 が True となるため、
(x Or y) And Not True
と評価され、x, y の値にかかわらず結果は False となる。
解決するには、
If ((x Or y) And Not 7) <> 0 Then Exit Sub
のように、ビット演算コンテキストを () で括って論理演算に使う。