C#で将棋盤を描画してみようその2.1 ～駒の描画～

[その1](http://qiita.com/pizyumi/items/f4d56665e8473e1f4c0a)からの続き。

その1で枠線を描画することができたので、今日は駒を描画してみようと思います。

問題はどのようにして描画するかですが、予め駒の画像を用意しておき、それを描画することにしました。

文字を描画することも考えたのですが、文字の描画は色々と難しい点があります（たとえば、フォントをどうするか、縦書きが実現できるか、描画位置の計算をどうするか、etc.）。なので、予め画像を用意しておいてそれを描画するのが直截簡明だし、画像を差し替えればどのような駒でも描画できるし、良いかと思いました。

それでは早速実装していきたいところですが、その前に幾つか実装の際に欲しくなるものを導入しましょう。

# その1 運用記録

前回作成したのはただ線を描画するだけの簡単なプログラムでしたが、今回は画像を読み込まなければなりません。画像を読み込むということはプログラムの外部のものに依存するということですのでエラー処理を考慮することは必須です。特にファイルに格納されているデータの読み込みの場合はファイルが存在しない可能性が現実的にあり得ますのでエラー処理は必須です。そうなると、運用記録を発行できるような機能が欲しくなります（データを読み込まなければならないファイルが存在しない場合にはファイルが存在しないことを通知する運用記録を発行します。勿論運用記録の用途は他にも沢山あるでしょう）。

という訳で、運用記録を発行するための機構として別の記事で作ったものを導入することにします。

[ログ出力](http://qiita.com/pizyumi/items/d64017761b14a0236415)

# その2 随意型

多少複雑なことをしたい場合はやっぱり欲しくなりますね。特に今回は画像が存在しない場合（画像ファイルが存在しない場合）に対応しなければなりませんから、随意型はどうしても欲しいです。

という訳で、随意型として別の記事で作ったものを導入することにします。

[C#でOption<T>型](http://qiita.com/pizyumi/items/0151c70fa79bf07288a7)

# その3 将棋クラス

前回作成したのはただ線を描画するだけの簡単なプログラムでしたのでProgramクラスに全ての処理を押し込んでいるような作りでしたが、そろそろプログラムが大きくなってきそうなので、将棋に関する処理全般を放り込むためのクラスを作成しましょう。名称はSyougiクラスとします。

```csharp
    //将棋に関する処理
    public class Syougi
    {
    }
```

前回作成したプログラムで将棋に関係のある部分（CreateDefaultContent関数）をSyougiクラスに移動しなければなりませんが、それは後にしましょう。

# その4 局面

駒を描画するにはまず駒がどこに配置されているかという局面の情報がなければなりません。局面の情報を保持するためのクラスを作成します。

まず、駒のクラスを作成します。

```csharp
    //駒の所有者
    public enum Owner
    {
        //先手
        Sente,
        //後手
        Gote
    }

    //駒
    public abstract class Piece
    {
        //所有者
        public Owner Owner { get; set; }
    }

    //成ることのできる駒
    public abstract class PieceCanPromoted : Piece
    {
        //成っているか
        public bool IsPromoted { get; set; }
    }

    //歩兵
    public class Hu : PieceCanPromoted { }
    //銀将
    public class Gin : PieceCanPromoted { }
    //飛車
    public class Hi : PieceCanPromoted { }
    //角行
    public class Kaku : PieceCanPromoted { }
    //桂馬
    public class Kei : PieceCanPromoted { }
    //金将
    public class Kin : Piece { }
    //香車
    public class Kyou : PieceCanPromoted { }
    //王将
    public class Ou : Piece { }
```

次に、枡のクラスを作成します。枡の中には0個又は1個の駒があります。

```csharp
    //枡
    public class Section
    {
        //駒
        public Option<Piece> Piece { get; set; }
    }
```

最後に、局面のクラスを作成します。局面の中には2次元状の枡があります。他に持ち駒も必要ですが、今回は実装しません。次回以降実装します。

```csharp
    //局面
    public class Space
    {
        //枡
        public Section[,] Sections { get; set; }
    }
```

# その5 局面に関する処理

局面に関する処理をSyougiクラスに追加していきます。

駒が1つも配置されていない新しい局面を作成する関数を追加します。

```csharp
        //新しい局面を作成し、返す（駒が1つも配置されていない局面を作成し、返す）
        private static Space CreateSpace()
        {
            //駒が配置されていない枡を作成する
            Section[,] sections = new Section[NumOfRows, NumOfColumns];
            for (int i = 0; i < NumOfRows; i++)
                for (int j = 0; j < NumOfColumns; j++)
                {
                    sections[i, j] = new Section();
                    sections[i, j].Piece = Option.Return<Piece>();
                }

            //局面を作成する
            Space space = new Space();
            space.Sections = sections;

            //局面を返す
            return space;
        }
```

局面を引数として受け取って初形の局面に変更する関数を追加します。

```csharp
        static Syougi()
        {
            //0個の駒を作成する
            Func<Option<Piece>> createNone = () => Option.Return<Piece>();

            //歩兵を作成する
            Func<Owner, Func<Option<Piece>>> createHu = (owner) => () => Option.Return<Piece>(new Hu() { Owner = owner });
            //銀将を作成する
            Func<Owner, Func<Option<Piece>>> createGin = (owner) => () => Option.Return<Piece>(new Gin() { Owner = owner });
            //飛車を作成する
            Func<Owner, Func<Option<Piece>>> createHi = (owner) => () => Option.Return<Piece>(new Hi() { Owner = owner });
            //角行を作成する
            Func<Owner, Func<Option<Piece>>> createKaku = (owner) => () => Option.Return<Piece>(new Kaku() { Owner = owner });
            //桂馬を作成する
            Func<Owner, Func<Option<Piece>>> createKei = (owner) => () => Option.Return<Piece>(new Kei() { Owner = owner });
            //金将を作成する
            Func<Owner, Func<Option<Piece>>> createKin = (owner) => () => Option.Return<Piece>(new Kin() { Owner = owner });
            //香車を作成する
            Func<Owner, Func<Option<Piece>>> createKyou = (owner) => () => Option.Return<Piece>(new Kyou() { Owner = owner });
            //王将を作成する
            Func<Owner, Func<Option<Piece>>> createOu = (owner) => () => Option.Return<Piece>(new Ou() { Owner = owner });

            //初形の局面の駒を作成する関数を作成する
            CreateInitialPieces = new Func<Option<Piece>>[,]
            {
                { createKyou(Owner.Gote),  createKei(Owner.Gote), createGin(Owner.Gote), createKin(Owner.Gote), createOu(Owner.Gote), createKin(Owner.Gote), createGin(Owner.Gote), createKei(Owner.Gote), createKyou(Owner.Gote) },
                { createNone,  createHi(Owner.Gote), createNone, createNone, createNone, createNone, createNone, createKaku(Owner.Gote), createNone },
                { createHu(Owner.Gote), createHu(Owner.Gote), createHu(Owner.Gote), createHu(Owner.Gote), createHu(Owner.Gote), createHu(Owner.Gote), createHu(Owner.Gote), createHu(Owner.Gote), createHu(Owner.Gote) },
                { createNone,  createNone, createNone, createNone, createNone, createNone, createNone, createNone, createNone },
                { createNone,  createNone, createNone, createNone, createNone, createNone, createNone, createNone, createNone },
                { createNone,  createNone, createNone, createNone, createNone, createNone, createNone, createNone, createNone },
                { createHu(Owner.Sente), createHu(Owner.Sente), createHu(Owner.Sente), createHu(Owner.Sente), createHu(Owner.Sente), createHu(Owner.Sente), createHu(Owner.Sente), createHu(Owner.Sente), createHu(Owner.Sente) },
                { createNone,  createKaku(Owner.Sente), createNone, createNone, createNone, createNone, createNone, createHi(Owner.Sente), createNone },
                { createKyou(Owner.Sente),  createKei(Owner.Sente), createGin(Owner.Sente), createKin(Owner.Sente), createOu(Owner.Sente), createKin(Owner.Sente), createGin(Owner.Sente), createKei(Owner.Sente), createKyou(Owner.Sente) },
            };
        }

        //初形の局面の駒を作成する関数
        private static readonly Func<Option<Piece>>[,] CreateInitialPieces;

        //局面を受け取って初形の局面に変更する
        private static void InitializeSpace(Space space)
        {
            Section[,] sections = space.Sections;
            for (int i = 0; i < NumOfRows; i++)
                for (int j = 0; j < NumOfColumns; j++)
                    sections[i, j].Piece = CreateInitialPieces[i, j]();
        }
```