「#Altseed」タグアーカイブ

【C#】【ピクロス】【ALTSEED】サイズ変更ダイアログを大幅に修正

前回までの状況はこちら。

最新ソースはこちら。

https://github.com/takishita2nd/Picross

ダイアログ処理を大幅に修正しました。

具体的には、ボタン押下処理をラムダ式で与える、という形にしました。

    class Button : ObjectBase
    {
        private Action _action = null;

        public void SetAction(Action action)
        {
            _action = action;
        }

        public virtual void OnClick()
        {
            if(_action != null)
            {
                _action.Invoke();
            }
        }
        sizeButton.SetAction(() => {
            dialog.Show();
        });

ダイアログも同じように、

    class Dialog
    {
        private Action _action = null;

        public Dialog()
        {
            _isShow = false;
            _button = new Button(436, 450, "確定");
            _button.SetFontOffset(46, 4);
            _button.SetAction(() =>
            {
                if(_action != null)
                {
                    _action.Invoke();
                }
            });

            _texture = new asd.TextureObject2D();
            _texture.Position = new asd.Vector2DF(_x, _y);
        }

        public void SetAction(Action action)
        {
            _action = action;
        }

        public void OnClick(asd.Vector2DF pos)
        {
            if (_button.isClick(pos))
            {
                _button.OnClick();
            }
        }
            Dialog dialog = new Dialog();
            dialog.SetEngine();
            dialog.SetAction(() =>
            {
                dialog.Hide();
            });

特にUI周りは、オブジェクトが持つデータの引き渡しをどうするか、で頭を悩ませてしまいます。

こういうときは、慣れないと見た目複雑に見えてしまいますが、慣れればラムダ式にしてしまった方が、返ってコードがスッキリするんです。

実際、こうすることで、クラスの数を削減できました。

ボタン押下時の処理もラムダ式にすることで、実際の処理は作成元で定義すれば良いので、Buttonクラス一個で済んでしまいます。

UI周り自作するって予想以上に難しいね。

この調子でどんどん作ってきましょう。

【C#】【ピクロス】【ALTSEED】サイズ変更ダイアログを表示する

前回までの状況はこちら。

最新ソースはこちら。

https://github.com/takishita2nd/Picross

ダイアログを表示するところまで行きたいのですが、

まず、ダイアログを表示するボタンを作成しなくちゃいけないので、

    class Button : ObjectBase
    {
        private string _text;
        private const int fontOffsetX = 9;
        private const int fontOffsetY = 4;
        protected bool enable = true;

        public Button(int x, int y, string text)
        {
            width = 256;
            height = 64;
            _x = x;
            _y = y;
            _text = text;

            _backTexture = new asd.TextureObject2D();
            _backTexture.Position = new asd.Vector2DF(_x, _y);

            _valueText = new asd.TextObject2D();
            _valueText.Text = _text;
            _valueText.Font = Resource.getFont();
            _valueText.Position = new asd.Vector2DF(_x + fontOffsetX, _y + fontOffsetY);
        }

        public void updateTexture(asd.Vector2DF pos)
        {
            if (pos.X > _x && pos.X < _x + width
                && pos.Y > _y && pos.Y < _y + height)
            {
                _backTexture.Texture = Resource.getButtonTexture();
            }
            else
            {
                _backTexture.Texture = null;
            }
        }

        public void setEnable(bool enable)
        {
            this.enable = enable;
        }

        public virtual void onClick()
        {
            throw new NotImplementedException();
        }
    }

Buttonクラスを作成。ほぼほぼ数独解析ツールのコードをコピーしました。

座標とかサイズは微調整していますが。

これを継承してサイズ変更ボタンを作成。

class SizeButton : Button
{
    public SizeButton() : base(10, 10, "サイズ変更")
    {

    }

    public override void onClick()
    {
        Dialog dialog = Controll.GetDialog();
        dialog.Show();
    }
}
class Controll
{
    private static Dialog _dialog = null;

    public static Dialog GetDialog()
    {
        if(_dialog == null)
        {
            _dialog = new Dialog();
            _dialog.SetEngine();
        }
        return _dialog;
    }
}

各種コントロールもシングルトン形式にすれば、アクセスが簡単になるかと思って。

class Dialog
{
    private asd.TextureObject2D _texture;

    public Dialog()
    {
        _texture = new asd.TextureObject2D();
        _texture.Position = new asd.Vector2DF(300, 300);
    }

    public void SetEngine()
    {
        asd.Engine.AddObject2D(_texture);
    }

    public void Show()
    {
        _texture.Texture = Resource.getDialogTexture();
    }

    public void Hide()
    {
        _texture.Texture = null;
    }
class PicrossUI
{
    public void Run()
    {
        asd.Engine.Initialize("ピクロス解析ツール", 1000, 800, new asd.EngineOption());

        List<Button> buttons = new List<Button>();
        var sizeButton = new SizeButton();
        asd.Engine.AddObject2D(sizeButton.getBackTexture());
        asd.Engine.AddObject2D(sizeButton.getTextObject());
        buttons.Add(sizeButton);

        while (asd.Engine.DoEvents())
        {
            asd.Vector2DF pos = asd.Engine.Mouse.Position;
            foreach (Button button in buttons)
            {
                button.updateTexture(pos);
            }

            if (asd.Engine.Mouse.LeftButton.ButtonState == asd.ButtonState.Push)
            {
                foreach (Button button in buttons)
                {
                    if (button.isClick(pos))
                    {
                        button.onClick();
                    }
                }
            }
            asd.Engine.Update();
        }
        asd.Engine.Terminate();
    }
}

ダイアログ表示とか、ボタン押下時の処理とか、本来ウインドウシステムがやっていることを、全て自前でやらなくちゃ行けないので、ちょっと面倒な事になっています。

頭がごっちゃになりそう。

デリゲートとか上手に使うと上手くいきそうな気もするんですが。

もうちょっと考えてみます。

【C#】【ピクロス】【ALTSEED】絵を描画するエリアを作成する

前回までの状況はこちら。

最新ソースはこちら。

https://github.com/takishita2nd/Picross

今回は、前回のソースコードを元に、クラス構成を変えて作り直していきます。

まずはリソースを管理するクラス。

class Resource
{
    private static asd.Texture2D _picrossTexture = null;
    public static asd.Texture2D GetPicrossTexture()
    {
        if (_picrossTexture == null)
        {
            _picrossTexture = asd.Engine.Graphics.CreateTexture2D("square.png");
        }
        return _picrossTexture;
    }
}

数独の時と同じです。

画像などの外部リソースは、読み込んだ一個のオブジェクトをみんなで使い回すような仕組みにしています。

こうすることで、外部リソース読み込み速度が向上し、使用メモリも少なくなります。

シングルトンに近いイメージですね。

絵を構成するオブジェクトのベース部分を作成します。

class ObjectBase
{
    protected int _x;
    protected int _y;
    protected asd.TextureObject2D _backTexture;
    protected asd.TextObject2D _valueText;
    protected int width;
    protected int height;

    public asd.TextureObject2D getBackTexture()
    {
        return _backTexture;
    }

    public asd.TextObject2D getTextObject()
    {
        return _valueText;
    }

    public bool isClick(asd.Vector2DF pos)
    {
        if (pos.X > _x && pos.X < _x + width
            && pos.Y > _y && pos.Y < _y + height)
        {
            return true;
        }
        else
        {
            return false;
        }
    }

これは、数独のObjectBaseクラスと全く同じです。

これをベースにして、絵を書く部分と、数字を入力する部分とで、クラスを派生させて行きます。

絵を書く部分は以下の様に派生させました。

class DrawSquare : ObjectBase
{
    protected int _row;
    protected int _col;
    protected const int setPositionX = 200;
    protected const int setPositionY = 200;

    public DrawSquare(int row, int col)
    {
        width = 32;
        height = 32;
        _row = row;
        _col = col;
        _x = col * width + setPositionX;
        _y = row * height + setPositionY;

        _backTexture = new asd.TextureObject2D();
        _backTexture.Texture = Resource.GetPicrossTexture();
        _backTexture.Position = new asd.Vector2DF(_x, _y);
    }
}

これを使用して実装します。

class PicrossUI
{
    private List<List<DrawSquare>> drawSquares = new List<List<DrawSquare>>();

    public PicrossUI()
    {

    }

    public void Run()
    {
        asd.Engine.Initialize("ピクロス解析ツール", 1000, 800, new asd.EngineOption());

        // 下地
        var background = new asd.GeometryObject2D();
        asd.Engine.AddObject2D(background);
        var bgRect = new asd.RectangleShape();
        bgRect.DrawingArea = new asd.RectF(0, 0, 1000, 800);
        background.Shape = bgRect;

        for(int row = 0; row <10; row++)
        {
            List<DrawSquare> rowList = new List<DrawSquare>();
            for(int col = 0; col <10; col++)
            {
                var square = new DrawSquare(row, col);
                asd.Engine.AddObject2D(square.getBackTexture());
                rowList.Add(square);
            }
            drawSquares.Add(rowList);
        }

        while (asd.Engine.DoEvents())
        {
            asd.Engine.Update();
        }
        asd.Engine.Terminate();
    }
}

今回色を書く部分のマスの数は可変になるので、二次元配列ではなく、Listを使います。

実行結果はこんな感じになりました。

当然、見た目は何も弄っていないので、前回と同じですね。

次回はサイズを変更するダイアログを作成していきます。

【C#】【ピクロス】【Altseed】とりあえず画面を作ってみる。

最新ソースはこちら。

https://github.com/takishita2nd/Picross

とりあえず画面を作ってみます。

クラス構成とか考えずに、

この画像を作成し、これを10×10に並べてみました。

    class Program
    {
        [STAThread]
        static void Main(string[] args)
        {
            PicrossUI picross = new PicrossUI();
            picross.Run();
        }
    }
    class PicrossUI
    {
        private const int setPositionX = 200;
        private const int setPositionY = 200;

        public PicrossUI()
        {

        }

        public void Run()
        {
            asd.Engine.Initialize("ピクロス解析ツール", 1000, 800, new asd.EngineOption());

            // 下地
            var background = new asd.GeometryObject2D();
            asd.Engine.AddObject2D(background);
            var bgRect = new asd.RectangleShape();
            bgRect.DrawingArea = new asd.RectF(0, 0, 1000, 800);
            background.Shape = bgRect;

            for(int row = 0; row <10; row++)
            {
                for(int col = 0; col <10; col++)
                {
                    var square = new asd.TextureObject2D();
                    square.Texture = asd.Engine.Graphics.CreateTexture2D("square.png");
                    square.Position = new asd.Vector2DF(row * 32 + setPositionX, col * 32 + setPositionY);
                    asd.Engine.AddObject2D(square);
                }
            }

            while (asd.Engine.DoEvents())
            {
                asd.Engine.Update();
            }
            asd.Engine.Terminate();
        }
    }

数独の時は9×9のマスの画像をあらかじめ作成し、表示させていましたが、

これは数独が9×9で固定だからできるためです。

今回はマスの数が可変になるため、1個のマスを並べて使用したいと思います。

中の線が太く見えますが、マスを小さくすればそんなに気にならないかと思います。

ただ、マスのサイズを小さくしすぎると、このマスの中に後々数字を入れることになるので、あまり小さくできません。

今回は32×32ピクセルで作成しましたが、これが妥当なところでしょう。

考慮すべき所は、数字が入るところと色を塗るところが分かるように中の色を変えた方が良いかもしれません。

そこら辺を考慮した上で、クラス構成を考えてみたいと思います。

まずは、マスのサイズを可変に変更できるように作成していきましょう。

【C#】【ALTSEED】【数独】解析ができなかった場合の対処

前回までの状況はこちら。

最新ソースはこちら(gitHub)

https://github.com/takishita2nd/sudokuGUI

やることの三つ目を解決します。

今のままでは、入力データが不完全な状態で解析ボタンを押してしまうと、アプリが固まってしまいます。

原因は、仮置きロジックの再起処理が無限に実行されてしまっているようです。

なので、仮置きロジックが一定回数呼ばれたら失敗として処理終了させてしまいましょう。

    class Sudoku
    {
        private Square[,] _square;
        private int kariokiCount = 0;

        private Square doKarioki(Square[,] squares)
        {
            Square ret = null;
            List<Square> kariokiList = searchKariokiSquare(squares);
            kariokiCount++;
            if(kariokiCount >= 100)
            {
                return null;
            }

続いて、エラーを表示させる処理を追加します。

エラーは新しいオブジェクトを画面に追加して表示させます。

なので、フォントデータも作り直しです。

    class Message : ObjectBase
    {
        private string _text;
        private const int fontOffsetX = 0;
        private const int fontOffsetY = 0;

        public Message(int x, int y, string text)
        {
            width = 256;
            height = 64;
            _x = x;
            _y = y;
            _text = text;

            _backTexture = new asd.TextureObject2D();
            _backTexture.Position = new asd.Vector2DF(_x, _y);

            _valueText = new asd.TextObject2D();
            _valueText.Text = _text;
            _valueText.Font = Resource.getTextFont();
            _valueText.Position = new asd.Vector2DF(_x + fontOffsetX, _y + fontOffsetY);
        }

        public void show()
        {
            _valueText.Text = _text;
        }

        public void hide()
        {
            _valueText.Text = "";
        }
    }

テクスチャーは使わないので、書かなくても良かったんですけどね。


            // メッセージ
            Message message = new Message(10, 640, "解析に失敗しました");
            asd.Engine.AddObject2D(message.getTextObject());
            message.hide();

こんな感じでAltseedエンジンにテキストを追加します。

最後に、このメッセージの表示をON/OFFする処理を追加します。

    class Button : ObjectBase
    {
        public virtual void onClick(SquareObject[,] squareObjects, Message message)
    class AnalyzeButton : Button
    {
        public override void onClick(SquareObject[,] squareObjects, Message message)
        {
            if(enable == false)
            {
                return;
            }

            Square[,] squares = new Square[9, 9];
            for (int row = 0; row < 9; row++)
            {
                for (int col = 0; col < 9; col++)
                {
                    squares[row, col] = new Square(squareObjects[row, col].getValue(), row, col);
                }
            }
            Sudoku sudoku = new Sudoku(squares);
            var ret = sudoku.run();
            if(ret == null)
            {
                message.show();
                return;
            }

            for (int row = 0; row < 9; row++)
            {
                for (int col = 0; col < 9; col++)
                {
                    squareObjects[row, col].setValue(ret[row, col].GetValue());
                }
            }
        }
    }
    class ClearButton : Button
    {
        public override void onClick(SquareObject[,] squareObjects, Message message)
        {
            message.hide();
            for (int row = 0; row < 9; row++)
            {
                for (int col = 0; col < 9; col++)
                {
                    squareObjects[row, col].setValue(0);
                }
            }
        }
    }
                        bool isButtonClisk = false;
                        foreach (Button button in buttons)
                        {
                            if (button.isClick(pos))
                            {
                                button.onClick(squareObjects, message);
                                isButtonClisk = true;
                            }
                        }

実装に悩みましたが、onClickにmessageオブジェクトを渡すことで対応させました。

もっとスマートな方法があると思うんですが、次回の開発までの課題にします。

たぶん、ほぼほぼこれで完成だと思います。

【C#】【ALTSEED】【数独】解析前の入力データに誤りがあった場合の対処

前回までの状況はこちら。

最新ソースはこちら(gitHub)

https://github.com/takishita2nd/sudokuGUI

やることの二つ目を解決します。

入力データに誤りがある場合は、誤りであると分かった時点でユーザーに知らせることが必要になります。

数独の場合、

オレンジの数字と同じ数字が黄色の範囲に合った場合、すでに数独のルールから逸脱しているため、それが判明した時点で誤りと判断します。

どうやってユーザーに知らせるのかというと、数字フォントの色を赤に変えることで知らせようと思います。

それと同時に解析ボタンも押せないようにガードをかけようと思います。

まずは、フォントの色を変える処理を実装。

リソースの追加。

    static class Resource
    {
        private static asd.Font _fontRed = null;

        public static asd.Font getFontRed()
        {
            if (_fontRed == null)
            {
                _fontRed = asd.Engine.Graphics.CreateFont("numberRed.aff");
            }
            return _fontRed;
        }

フォントの色を変える処理。

    class SquareObject : ObjectBase
    {
        public enum FontColor
        {
            Black,
            Red
        }

        public bool isSetValue()
        {
            if(_value == 0)
            {
                return false;
            }
            else
            {
                return true;
            }
        }

        public void setFontColor(FontColor color)
        {
            switch (color)
            {
                case FontColor.Black:
                    _valueText.Font = Resource.getFont();
                    break;
                case FontColor.Red:
                    _valueText.Font = Resource.getFontRed();
                    break;
                default:
                    break;
            }
        }

ボタンを有効・無効を切り替える処理。

    class Button : ObjectBase
    {
        protected bool enable = true;

        public void setEnable(bool enable)
        {
            this.enable = enable;
        }
    class AnalyzeButton : Button
    {

        public override void onClick(SquareObject[,] squareObjects)
        {
            if(enable == false)
            {
                return;
            }

これを実装。

    class SudokuUI
    {
        private bool checkInputParameter(SquareObject[,] squareObjects)
        {
            bool conflict = false;
            for(int row = 0; row < 9; row++)
            {
                for(int col = 0; col < 9; col++)
                {
                    if(squareObjects[row,col].isSetValue() == true)
                    {
                        int value = squareObjects[row,col].getValue();
                        bool ret = checkRowNumber(squareObjects, row, col, value);
                        ret |= checkColNumber(squareObjects, row, col, value);
                        ret |= check9AreaNumber(squareObjects, row, col, value);
                        if(ret == true)
                        {
                            squareObjects[row, col].setFontColor(SquareObject.FontColor.Red);
                            conflict = true;
                        }
                    }
                }
            }
            return conflict;
        }

        private bool checkRowNumber(SquareObject[,] squareObjects, int row, int col, int value)
        {
            for(int c = 0; c < 9; c++)
            {
                if(c != col &&
                    squareObjects[row, c].getValue() == value)
                {
                    squareObjects[row, c].setFontColor(SquareObject.FontColor.Red);
                    return true;
                }
            }
            return false;
        }

        private bool checkColNumber(SquareObject[,] squareObjects, int row, int col, int value)
        {
            for (int r = 0; r < 9; r++)
            {
                if (r != row &&
                    squareObjects[r, col].getValue() == value)
                {
                    squareObjects[r, col].setFontColor(SquareObject.FontColor.Red);
                    return true;
                }
            }
            return false;
        }

        private bool check9AreaNumber(SquareObject[,] squareObjects, int row, int col, int value)
        {
            int rowStart;
            int colStart;
            getRowCol9Area(row, col, out rowStart, out colStart);

            for (int r = rowStart; r < rowStart + 3; r++)
            {
                for (int c = colStart; c < colStart + 3; c++)
                {
                    if (r != row && c != col &&
                        squareObjects[r, c].getValue() == value)
                    {
                        squareObjects[r, c].setFontColor(SquareObject.FontColor.Red);
                        return true;
                    }
                }
            }
            return false;
        }

        private void getRowCol9Area(int row, int col, out int rowStart, out int colStart)
        {
            if (row >= 0 && row <= 2)
            {
                rowStart = 0;
            }
            else if (row >= 3 && row <= 5)
            {
                rowStart = 3;
            }
            else
            {
                rowStart = 6;
            }

            if (col >= 0 && col <= 2)
            {
                colStart = 0;
            }
            else if (col >= 3 && col <= 5)
            {
                colStart = 3;
            }
            else
            {
                colStart = 6;
            }
        }
                if (asd.Engine.Mouse.LeftButton.ButtonState == asd.ButtonState.Push)
                {
                    if (mouseHold)
                    {
                        if (!palette.isClick(pos))
                        {
                            palette.hide();
                            mouseHold = false;
                        }
                        else
                        {
                            int value = palette.getClickValue(pos);
                            if(clickedSquareObject != null)
                            {
                                clickedSquareObject.setValue(value);
                                palette.hide();
                                mouseHold = false;
                            }
                            bool conflict = checkInputParameter(squareObjects);
                            if(conflict == true)
                            {
                                start.setEnable(false);
                            }
                            else
                            {
                                for (int row = 0; row < 9; row++)
                                {
                                    for (int col = 0; col < 9; col++)
                                    {
                                        squareObjects[row, col].setFontColor(SquareObject.FontColor.Black);
                                    }
                                }
                                start.setEnable(true);
                            }
                        }
                    }
                    else

ちょっと動作が怪しい気がするけど、、、後で見直す。

checkInputParameter()で数値の重複が無いかを確認し、あれば選択中のマスと同じ値のマスを赤くします。もし重複が無ければ全て黒に戻します。

そして、重複があればボタンを無効化、無ければボタンを有効化します。

動作結果はこうなりました。

【C#】【ALTSEED】【数独】9×9マスの外をクリックしてもパレットが表示されてしまう動作の修正

前回までの状況はこちら。

最新ソースはこちら(gitHub)

https://github.com/takishita2nd/sudokuGUI

やることの一つ目を解決します。

9×9の範囲が分かれば、対処は簡単です。

9×9は画像なので、幅、高さはプロパティを見ればわかります。

        private const int width = 576;
        private const int height = 576;

これが分かれば、isClick()を作成。

        private bool isClick(asd.Vector2DF pos)
        {
            if (pos.X > offsetX && pos.X < offsetX + width &&
                pos.Y > offsetY && pos.Y < offsetY + height)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

これを使用します。

                        if (isButtonClisk == false)
                        {
                            if (isClick(pos) == true)
                            {
                                mouseHold = true;
                                palette.show(pos);
                                for (int row = 0; row < 9; row++)
                                {
                                    for (int col = 0; col < 9; col++)
                                    {
                                        if (squareObjects[row, col].isClick(pos) == true)
                                        {
                                            clickedSquareObject = squareObjects[row, col];
                                        }
                                    }
                                }
                            }
                        }

こんな感じでどうでしょうか。

【C#】【ALTSEED】【数独】これからやること。

前回までの状況はこちら。

とりあえず、解析処理を行い、結果を表示するところまで完成しましたが、これだけではまだツールとしては完成ではありません。

まだまだ手を加えなければならないところがあります。

それは以下の3つです。

  • 9×9マスの外をクリックしてもパレットが表示されてしまう動作の修正
  • (入力データのミスで)解析ができなかった場合の対処
  • そもそも解析前の入力データに誤りがあった場合の対処

こんなところですかね。

具体的にどう対応するかはおいおい考えるとして、

まずは簡単に対処できそうな所から対処していこうと思います。

【C#】【ALTSEED】【数独】解析処理を実行

前回までの状況はこちら。

最新ソースはこちら(gitHub)

https://github.com/takishita2nd/sudokuGUI

解析処理を実行する処理を作成します。

作り方は前回のクリアボタンと同じです。

Buttonクラスを継承して、AnalyzeButtonクラスを作成します。

    class AnalyzeButton : Button
    {
        public AnalyzeButton() : base(600, 570, "解析開始")
        {

        }

        public override void onClick(SquareObject[,] squareObjects)
        {
            Square[,] squares = new Square[9, 9];
            for (int row = 0; row < 9; row++)
            {
                for (int col = 0; col < 9; col++)
                {
                    squares[row, col] = new Square(squareObjects[row, col].getValue(), row, col);
                }
            }
            Sudoku sudoku = new Sudoku(squares, null);
            sudoku.run();
            for (int row = 0; row < 9; row++)
            {
                for (int col = 0; col < 9; col++)
                {
                    squareObjects[row, col].setValue(squareObjects[row, col].getValue());
                }
            }
        }
    }

これを実装します。

            // ボタン
            List<Button> buttons = new List<Button>();
            Button clear = new ClearButton();
            asd.Engine.AddObject2D(clear.getBackTexture());
            asd.Engine.AddObject2D(clear.getTextObject());
            buttons.Add(clear);

            Button start = new AnalyzeButton();
            asd.Engine.AddObject2D(start.getBackTexture());
            asd.Engine.AddObject2D(start.getTextObject());
            buttons.Add(start);

            // パレット
            palette = new Palette();
            palette.setEngine();




            // Altseedが進行可能かチェックする。
            while (asd.Engine.DoEvents())
            {
                asd.Vector2DF pos = asd.Engine.Mouse.Position;
                if (!mouseHold)
                {
                    for (int row = 0; row < 9; row++)
                    {
                        for (int col = 0; col < 9; col++)
                        {
                            squareObjects[row, col].updateTexture(pos);
                        }
                    }
                    foreach(Button button in buttons)
                    {
                        button.updateTexture(pos);
                    }
                }
                else
                {
                    palette.updateTexture(pos);
                }

                if (asd.Engine.Mouse.LeftButton.ButtonState == asd.ButtonState.Push)
                {
                    if (mouseHold)
                    {
                        if (!palette.isClick(pos))
                        {
                            palette.hide();
                            mouseHold = false;
                        }
                        else
                        {
                            int value = palette.getClickValue(pos);
                            if(clickedSquareObject != null)
                            {
                                clickedSquareObject.setValue(value);
                                palette.hide();
                                mouseHold = false;
                            }
                        }
                    }
                    else
                    {
                        bool isButtonClisk = false;
                        foreach (Button button in buttons)
                        {
                            if (button.isClick(pos))
                            {
                                button.onClick(squareObjects);
                                isButtonClisk = true;
                            }
                        }

                        if (isButtonClisk == false)
                        {
                            mouseHold = true;
                            palette.show(pos);
                            for (int row = 0; row < 9; row++)
                            {
                                for (int col = 0; col < 9; col++)
                                {
                                    if (squareObjects[row, col].isClick(pos) == true)
                                    {
                                        clickedSquareObject = squareObjects[row, col];
                                    }
                                }
                            }
                        }
                    }
                }

                // Altseedを更新する。
                asd.Engine.Update();
            }

各種ボタン系はButtonリストでまとめておき、updateTexture()、isClick()、onClick()処理をforeachでまとめて処理できるように修正しています。

これで解析までできるはず。

ん?

あああ!

今の解析処理、解析結果をテキストに吐き出す処理のままだった!

これは解析処理にも修正をいれなくては。。。

ここまで来たので、修正しました。

あああ、この瞬間がたまらない!

これこそがプログラマーの喜び!

【C#】【ALTSEED】【数独】ボタン作成

前回までの状況はこちら。

最新ソースはこちら(gitHub)

https://github.com/takishita2nd/sudokuGUI

処理を行うボタンを設置します。

作成するボタンは「解析開始」ボタンと、入力した数字を全部消去する「クリア」ボタンです。

まず、ボタンを配置するところから作ります。

ボタンを配置するためにボタン用のクラスを作成します。

しかし、すでに作成しているSquareObjectクラスと重複している部分があるので、新たにObjectBaseクラスを作成して、共通部分はこちらに書きます。

    class ObjectBase
    {
        protected int _x;
        protected int _y;
        protected asd.TextureObject2D _backTexture;
        protected asd.TextObject2D _valueText;
        protected int width;
        protected int height;

        public asd.TextureObject2D getBackTexture()
        {
            return _backTexture;
        }

        public asd.TextObject2D getTextObject()
        {
            return _valueText;
        }

        public bool isClick(asd.Vector2DF pos)
        {
            if (pos.X > _x && pos.X < _x + width
                && pos.Y > _y && pos.Y < _y + height)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
    }

そして、SquareObjectクラスと新たに作成するボタンクラスはこのObjectBaseクラスを継承します。

SquareObjectの記載は省略します。gitHubのソースを参照してください。

    class Button : ObjectBase
    {
        private string _text;
        private const int fontOffsetX = 39;
        private const int fontOffsetY = 9;

        public Button(int x, int y, string text)
        {
            width = 256;
            height = 64;
            _x = x;
            _y = y;
            _text = text;

            _backTexture = new asd.TextureObject2D();
            _backTexture.Position = new asd.Vector2DF(_x, _y);

            _valueText = new asd.TextObject2D();
            _valueText.Text = _text;
            _valueText.Font = Resource.getTextFont();
            _valueText.Position = new asd.Vector2DF(_x + fontOffsetX, _y + fontOffsetY);
        }

        public void updateTexture(asd.Vector2DF pos)
        {
            if (pos.X > _x && pos.X < _x + width
                && pos.Y > _y && pos.Y < _y + height)
            {
                _backTexture.Texture = Resource.getButtonTexture();
            }
            else
            {
                _backTexture.Texture = null;
            }
        }

        public virtual void onClick(SquareObject[,] squareObjects)
        {
            throw new NotImplementedException();
        }
    }

onClick()にクリック時の処理を記載します。

実際はこのクラスを継承して使用するので、ここでは未実装Exceptionを投げて例外を発生させます。

このクラスを継承して、まずはクリア処理を作成します。

    class ClearButton : Button
    {
        public ClearButton() : base(600, 500, "クリア")
        {

        }

        public override void onClick(SquareObject[,] squareObjects)
        {
            for (int row = 0; row < 9; row++)
            {
                for (int col = 0; col < 9; col++)
                {
                    squareObjects[row, col].setValue(0);
                }
            }
        }
    }

これを使用して、処理を作成します。

            // ボタン
            Button clear = new ClearButton();
            asd.Engine.AddObject2D(clear.getBackTexture());
            asd.Engine.AddObject2D(clear.getTextObject());

            Button start = new Button(600, 570, "解析開始");
            asd.Engine.AddObject2D(start.getBackTexture());
            asd.Engine.AddObject2D(start.getTextObject());

            // Altseedが進行可能かチェックする。
            while (asd.Engine.DoEvents())
            {
                asd.Vector2DF pos = asd.Engine.Mouse.Position;
                if (!mouseHold)
                {
                    for (int row = 0; row < 9; row++)
                    {
                        for (int col = 0; col < 9; col++)
                        {
                            squareObjects[row, col].updateTexture(pos);
                        }
                    }
                    clear.updateTexture(pos);
                    start.updateTexture(pos);
                }
                else
                {
                    palette.updateTexture(pos);
                }

                if (asd.Engine.Mouse.LeftButton.ButtonState == asd.ButtonState.Push)
                {
                    if (mouseHold)
                    {
                        if (!palette.isClick(pos))
                        {
                            palette.hide();
                            mouseHold = false;
                        }
                        else
                        {
                            int value = palette.getClickValue(pos);
                            if(clickedSquareObject != null)
                            {
                                clickedSquareObject.setValue(value);
                                palette.hide();
                                mouseHold = false;
                            }
                        }
                    }
                    else
                    {
                        if (clear.isClick(pos))
                        {
                            clear.onClick(squareObjects);
                        }
                        else
                        {
                            mouseHold = true;
                            palette.show(pos);
                            for (int row = 0; row < 9; row++)
                            {
                                for (int col = 0; col < 9; col++)
                                {
                                    if (squareObjects[row, col].isClick(pos) == true)
                                    {
                                        clickedSquareObject = squareObjects[row, col];
                                    }
                                }
                            }
                        }
                    }
                }

                // Altseedを更新する。
                asd.Engine.Update();
            }

実行結果はこんな感じ。

次回は解析処理を実装していきます。