ピクロス解析ツールを作成する!

数独解析ツールはほぼ出来上がってしまったので、

今度はピクロス解析ツールを作成してみようと思います。

自信は無いです。

でもできるところまでやってみます。

数独の時はロジック→UIの順に作成しましたが、今回はUI→ロジックの順に作成していこうと思います。

まず、どんなUIにしようかまとめてみます。

ピクロスは絵のサイズが同じとは限らないので、サイズをフレキシブルに変更できるようにしなければなりません。

あと、数字入力は数独の時に適用したパレット方式が意外と使い勝手が良かったので、今回もその方式を取り入れようと思います。

問題データをセーブ/ロードできるようにした方が良いかなぁ(デバッグが楽)

まぁ、とりあえずやってみます。

【ラズパイ】ラズパイのセットアップ

さぁ、ラズパイをセットアップするぞ。

まずはマイクロSDカードにラズパイOSをインストールします。

マイクロSDカードをPCに接続して、以下のサイトからインストールツールをダウンロードします。

https://www.raspberrypi.org/downloads/

実行するとこんな画面が表示されるので、一番左のリストボックスから使用するOSを選びます。

今回はデフォのRASBIANで。

真ん中のリストボックスでは、インストール先のメディアを選択します。

これは当然SDカードを選択。

この二つを選択すると、一番右のWRITEボタンが有効になります。

WRITEボタンを押すとSDカードにOSが書き込まれます。

終わりました。

マイクロSDカードをラズパイに装着し、電源以外のケーブルなどを接続。

最後に電源ケーブルを接続します。

そうすれば勝手にラズパイが立ち上がります。

立ち上がりました。

初回セットアップに言語設定、Wi-Fi設定、アップデートを行って設定完了。

これで自動的に日本語も使用できます。

あと、設定を変えることろは、VNCを有効にする。

Raspberry Piの設定からVNCの項を有効にすると、他PCからVNCで接続できます。

基本的にはVNC接続で使用していきたいと思います。

さて、次回はアタッチメントをつなげてみましょうか。

数独解析ツールをリリースしました。

まぁいろいろありましたが、数独解析ツールが完成しましたので、ご報告いたします。

ダウンロードはこちら(gitHub)

https://github.com/takishita2nd/sudokuGUI/releases/tag/1.02

zipファイルを解凍してsudokuGUI.exeを実行してください。

操作はマウスでクリックするだけなのでわかりやすくなっていると思います。

何かありましたらコメントください。

あと、ネタもください。

【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オブジェクトを渡すことで対応させました。

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

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

【ラズパイ】Raspberry PI4が届いた!

買いました。

Raspberry Pi 4 Model B 2GB RAM。

これの一個前がRaspberry Pi 2 Model Bだったから、それより大幅なパワーアップです。

メモリもプロセッサーも強化されていますが、わかりやすいところで言うと、

HDMIポート1個から、Micro HDMIのポート2つになりました。

4K出力もできるみたいよぉ。

Micro HDMI対応のケーブルなんてほとんど出回っていないので、本体と一緒に注文しました。

Micro HDMI – HDMIのケーブルです。

これが無いと、ディスプレイに画面を表示できません。

そして、もう一つ、左側にあるのが電源です。

端子はUSB-Cなのですが、これを動かすのに3Aの出力が必要なので、一般に出回っているUSB-Cケーブルでは動きません。

これも本体と同時に対応電源を注文しました。

あとは、ストレージとなるMicro SDカード。

これだけでこのラズパイは動かせるのですが、ついでなので、もうちょっと遊べるパーツを買いました。

このボードに温度計、湿度計などなど、あと右下にジョイスティック、8×8のLEDディスプレイが付いているパーツです。

ラズパイ4でも動くはず。

さあ、セットアップするぞ。

この一式はこちらのサイトで購入しました。

https://raspberry-pi.ksyic.com

【テイクアウト】大衆酒場 八重洲居酒場商店 札幌北一条チカホ店

串カツが食べたかった。

白石区役所で障害者手帳を更新した後、電話でテイクアウトの注文を入れて、受け取ってきました。

タレは別容器で付属されていました。

そのタレをかけて食べます。

サッポロクラシックも飲んで。

溜まった動画を見ながら。

午後6時に酔い潰れて寝ました。

12時間ぐらい寝たね。

また今日から頑張る。

障害者手帳が更新できました。

多分、申請してから10日ぐらいかな?

先々週の金曜日に窓口で申請して、

次の週の金曜日には電話で申請が通ったって連絡があり、

次の日には封書で通知が届いて、

昨日(月曜日)更新できました。

更新に必要なのは、障害者手帳と、手帳に貼り付ける写真と、印鑑、あと、福祉乗車証(カード)があればそれも必要になります。

なぜなら、この後すぐに福祉乗車証(カード)の更新を行うため。

まぁ、障害者手帳を更新したら、窓口の人が教えてくれるよ。

まぁ、これで、GW中に失効して電車に乗れない、というのは回避できました。

よかったよかった。

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

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

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

外出自粛中でも病院には行かなくちゃいけない訳で。

昨日(4/25)は心療内科の通院日。

外出自粛中でも病院に行って薬を処方して貰わなくちゃ、鬱病患者は死んでしまうわけで(大袈裟)。

まず、病院に入る前に検温と問診があり、万が一の場合には、処方箋だけ貰って帰ることもできるみたいです。

そして、お医者さんと「どうぶつの森」の会話をして(買えないんだってね~っていう内容)。

薬を処方して貰いました。

街に出たついでに何か買って帰ろうと思っていたけど、

街の中のお店、ほとんど休業中でシャッターが閉まっているので、結局何も買えず。

結局、まっすぐ帰って、近所のスーパーで食料買いました。

・・・たまには良い物食いたいね。

港町酒場もんきち商店 白石店で海産物の店頭販売やってました(4/24)

整体に行ってきた帰りに店頭販売やってました。

この日はたらことむきえびを購入しました。

この二つで1000かからなかったので、スーパーで買うよりお得だったかもしれません。

エビはエビチリにしました。

・・・作りすぎたか?

たらこもご飯のお供に美味しく食べています。

今もやっているか分かりませんが、近くに来たときはお店を覗いてみてはいかがでしょうか?

ランチ営業もやっているみたいです。

自分、ぼっちですが何か?