【C#】【オセロ】解説記事 part 1

はじめに

この記事は以下の記事のサポート記事です。手順を細かく解説しています。
touch-sp.hatenablog.com

解説

まず最初に盤面の表し方を解説します。
ビット演算の解説も含まれます。

盤面の表し方

オセロはマス目が64個あるので黒、白の石を別々にUInt64で表現することが可能です。
UInt64は基本的にただの正の整数ですが、2進法で表現すると「0」か「1」で構成された64桁の文字列になります。

なぜ黒と白の石を別々にする必要があるのか?それは「0」か「1」で構成された2進法で表現することによって後に出てくるビット演算が使用できるようになるからです。ここではそういうものと考えておいて下さい。

石を表現する時は石がある場所を「1」、石がない場所を「0」とします。
盤面は以下のようにナンバリングしました。
f:id:touch-sp:20210921112755p:plain:w300

試しに初期状態を考えてみましょう。
f:id:touch-sp:20210921113240p:plain:w300

ここで黒石だけを見ます。
f:id:touch-sp:20210921115554p:plain:w300
28番目と35番目に石が置かれています。
つまり28番目と35番目が「1」、それ以外は「0」の64桁の文字列をつくればよいことになります。
(ここでいう番目は一番右を0番目として数えています。)

C#ではこのようにして簡単に作れます。

UInt64 init = 1;
UInt64 black = 0;

black |= init << 28;
black |= init << 35;

文字列と表現しましたが実際には2進法で表すと28番目と35番目が「1」、それ以外は「0」のただの整数です。
文字列を扱っているかのように整数を扱っているだけです。

試しに以下の一行を実行すると整数が出力されます。

Console.WriteLine(black.ToString());

34628173824

この数字は2の28乗と2の35乗の和になっています。

ここではじめてビット演算が出てきました。難しく思われる人もいるかと思いますがビット演算は覚えることがたったの六つです。
「<<」「>>」「|」「&」「^」「~」
こちらのサイトがよくまとまっていると思いますので参考にしてここで習得してしまいましょう。
C#のビット演算の方法を解説|ビットフラグのメリットや例も紹介
10分もあればある程度理解できると思います。

先に作ったblackに格納された整数はあとで使いますので記録しておきます。
ここからは好みの問題になりますが64桁を8桁ずつ区切ってそれぞれ16進法で表したものを記録することにします。
以下の1行で出力されます。

Console.WriteLine(black.ToString("X16"));

0000000810000000


黒が終わったので白についても同様に出力します。

UInt64 init = 1;
UInt64 white = 0;

white |= init << 27;
white |= init << 36;

Console.WriteLine(white.ToString("X16"));

0000001008000000


最後に盤面を表示してみましょう。ただ初期盤面を出力するだけです。
初期配置については先に求めておいたのでそれをそのまま使います。

UInt64 init = 1;
UInt64 black = Convert.ToUInt64("0000000810000000", 16);
UInt64 white = Convert.ToUInt64("0000001008000000", 16);
UInt64 target;

foreach (int i in Enumerable.Range(0, 8))
{
    foreach (int j in Enumerable.Range(0, 8))
    {
        target = init << (8 * i + j); 
        if ((black & target) != 0)
        {
            Console.Write(" O  ");
        }
        else
        {
            Console.Write(((white & target) != 0) ? " x  " : " .  ");
        }
    }
    Console.WriteLine();
}


このように出力されればOKです。

 .   .   .   .   .   .   .   .
 .   .   .   .   .   .   .   .
 .   .   .   .   .   .   .   .
 .   .   .   x   O   .   .   .
 .   .   .   O   x   .   .   .
 .   .   .   .   .   .   .   .
 .   .   .   .   .   .   .   .
 .   .   .   .   .   .   .   .

ここでもビット演算が出てきました。ビット演算に慣れていない人はここで理解を深めておきましょう。

一部のみ解説します。
例えば28番目に黒石が置かれているかどうかを判定する方法です。

初期画面の黒石を表す整数を図示するとこのようになります。
f:id:touch-sp:20210921123851p:plain:w300

28番目を調べたければ28番目のみが「1」、それ以外が「0」の整数を作ります。
C#ではこのようにして簡単に作れます。わかりやすいようにtargetという変数に格納しています。

UInt64 init = 1;
UInt64 target = init << 28;

それを図示するとこのようになります。
f:id:touch-sp:20210921124323p:plain:w300

これら二つを論理AND演算子「&」で計算します。

black & target

この結果が0(つまり64桁すべて0)であれば黒石はないことになります。
結果が0以外であれば黒石があることになります。
ここで黒石があった場合の結果は1でないことに注意して下さい。28番目に「1」が存在する整数です。そのため黒石があるかどうかの判定は以下のようになります。

if ((black & target) != 0)


くれぐれもこのように書かないように気を付けて下さい。

if ((black & target) == 1)

さいごに

つづきを書きました。
【C#】【オセロ】解説記事 part 2 - パソコン関連もろもろ

間違いや改善点があればコメント頂けましたら幸いです。