「技術」カテゴリーアーカイブ

【Laravel】【ダイエット支援】ダッシュボード画面を作成する

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

https://github.com/takishita2nd/diet-mng

とりあえずダッシュボードの画面を作成してみました。

最近のVSCodeは非常に便利でして、

この画面でnpm run watchコマンドを動かしてくれるんです。

わざわざコマンドを入力する必要がないので、便利です。

この画面はVue.jsで書かれています。

久しぶりのhtml,cssだったので、ちょっと時間がかかりましたが、イメージとしては良いのではないでしょうか。

【C#】【ピクロス】【ALTSEED】解析パターンその8

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

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

https://github.com/takishita2nd/Picross

今回注目したのはここです。

ここはどのように塗っていくかというと、

空いているマスが4マスに対して、数字は3なので、

真ん中の2マスは確実に塗れることが分かります。

なので、これを実装します。

処理を単純化させるため、解析対象となる数字が行、列で1つの場合のみを、このロジックの対象とします。

また、このロジックを適用するマスを抽出するのですが、

マスクとマスクの間が全て塗られていた場合は処理済みと判断してスキップさせます。

その結果、対象のマスが1つの場合のみ、このロジックの対象とします。

この様な説明で分かってもらえるかどうか分からないけど、そういうことをやっています。

        // 解析パターンその8
        // 数字が大きい場合、真ん中の方を塗る
        private void pattern8()
        {
            // Row
            pattern8Row();
            // Col
            pattern8Col();
        }

        private void pattern8Row()
        {
            int row = 0;
            foreach (var rowlist in rowNumbers)
            {
                if (rowlist.IsAnalyzed())
                {
                    row++;
                    continue;
                }

                // 有効な数字を取り出す
                List<int> values = new List<int>();
                foreach(var data in rowlist.AnalyzeDatas)
                {
                    if (data.IsAnalyzed())
                    {
                        continue;
                    }
                    values.Add(data.Value);
                }
                if(values.Count != 1)
                {
                    row++;
                    continue;
                }

                // 対象となるマスを抽出する
                List<List<BitmapData>> bitmapLists = new List<List<BitmapData>>();
                List<BitmapData> bitmaplist = new List<BitmapData>();
                for (int col = 0; col < colNumbers.Count; col++)
                {
                    // マスクとマスクの間が全て塗られていたら、そこは対象としない
                    if (_bitmapData[row, col].IsMasked())
                    {
                        if(bitmaplist.Count != 0)
                        {
                            bool done = true;
                            foreach(var bitmap in bitmaplist)
                            {
                                if(bitmap.IsPainted() == false)
                                {
                                    done = false;
                                }
                            }
                            if(done == false)
                            {
                                bitmapLists.Add(bitmaplist);
                            }
                            bitmaplist = new List<BitmapData>();
                        }
                        continue;
                    }
                    bitmaplist.Add(_bitmapData[row, col]);
                }
                if (bitmaplist.Count != 0)
                {
                    bitmapLists.Add(bitmaplist);
                }
                if(bitmapLists.Count != 1)
                {
                    row++;
                    continue;
                }

                int value = values[0];
                List<BitmapData> bitmaps = bitmapLists[0];
                if(value < bitmaps.Count && value * 2 > bitmaps.Count)
                {
                    int paintNum = value * 2 - bitmaps.Count;
                    int countMax = 0;
                    if(paintNum % 2 == 1)
                    {
                        countMax = paintNum / 2 + 1;
                    }
                    else
                    {
                        countMax = paintNum / 2;
                    }
                    for (int count = -paintNum / 2; count < countMax; count++)
                    {
                        bitmaps[bitmaps.Count / 2 + count].Paint();
                    }
                }
                row++;
            }
        }

        private void pattern8Col()
        {
            int col = 0;
            foreach (var collist in colNumbers)
            {
                if (collist.IsAnalyzed())
                {
                    col++;
                    continue;
                }

                // 有効な数字を取り出す
                List<int> values = new List<int>();
                foreach (var data in collist.AnalyzeDatas)
                {
                    if (data.IsAnalyzed())
                    {
                        continue;
                    }
                    values.Add(data.Value);
                }
                if (values.Count != 1)
                {
                    col++;
                    continue;
                }

                // 対象となるマスを抽出する
                List<List<BitmapData>> bitmapLists = new List<List<BitmapData>>();
                List<BitmapData> bitmaplist = new List<BitmapData>();
                for (int row = 0; row < rowNumbers.Count; row++)
                {
                    // マスクとマスクの間が全て塗られていたら、そこは対象としない
                    if (_bitmapData[row, col].IsMasked())
                    {
                        if (bitmaplist.Count != 0)
                        {
                            bool done = true;
                            foreach (var bitmap in bitmaplist)
                            {
                                if (bitmap.IsPainted() == false)
                                {
                                    done = false;
                                }
                            }
                            if (done == false)
                            {
                                bitmapLists.Add(bitmaplist);
                            }
                            bitmaplist = new List<BitmapData>();
                        }
                        continue;
                    }
                    bitmaplist.Add(_bitmapData[row, col]);
                }
                if (bitmaplist.Count != 0)
                {
                    bitmapLists.Add(bitmaplist);
                }
                if (bitmapLists.Count != 1)
                {
                    col++;
                    continue;
                }

                int value = values[0];
                List<BitmapData> bitmaps = bitmapLists[0];
                if (value < bitmaps.Count && value * 2 > bitmaps.Count)
                {
                    int paintNum = value * 2 - bitmaps.Count;
                    int countMax = 0;
                    if (paintNum % 2 == 1)
                    {
                        countMax = paintNum / 2 + 1;
                    }
                    else
                    {
                        countMax = paintNum / 2;
                    }
                    for (int count = -paintNum / 2; count < countMax; count++)
                    {
                        bitmaps[bitmaps.Count / 2 + count].Paint();
                    }
                }

                col++;
            }
        }
        public BitmapData[,] Run()
        {
            pattern1();
            while (checkPainedCount())
            {
                pattern2();
                pattern3();
                pattern4();
                pattern5();
                pattern6();
                pattern7();
                pattern8();
                doMask();
            }

            return _bitmapData;
        }

実行結果はこうなりました。

全て埋まりましたね。

解けたようです。

やったぁ。

【ダイエット支援】画面構成を考える。

とりあえず、環境を初期設定しました。

Auth機能を設定。

詳細はあとで作成する。

ログインするとこんな感じ。

とりあえず、体重などを記録して表示させたいと思っているので、画面はこんな感じかな。

ダッシュボードにはこんな感じで画面を作る。

クイック入力をクリックすると、ダイアログを表示する。

パパっと入力できるように。

詳細をクリックするとこんな感じの画面に遷移する。

こんな感じでリスト表示。

ここでデータ入力、編集、削除ができる。

操作はダイアログかなぁ。

ページャーもいるよね。

あとはグラフ表示を行うのにどのライブラリを使うかだな。

今後の予定としては、

  • 画面のMOCKを作成
  • WebAPIを作成
  • グラフのライブラリを探す

こんな感じかなぁ。

ぼちぼちとりかかりますか。

【C#】【ピクロス】【ALTSEED】解析パターン5と6の修正

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

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

https://github.com/takishita2nd/Picross

あれからがっつり修正しました。

具体的には、解析パターン5と6。

一度にたくさん処理していたのを、

一番最初のもの、一番最後のものの2パターンに分け、1回の処理では1つだけしか処理しない、という風にしました。

最初のループでは処理できない箇所でも次以降のループで処理できるでしょ、という考え。

詳しくはgitHubのソースコードを見て欲しい。

最終的には、こんな感じになりました。

解析完了までもう少しだが、まだ解析手法はあるはず。

これから考えます。

【C#】【ピクロス】【ALTSEED】解析パターンその7

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

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

https://github.com/takishita2nd/Picross

今回はここを狙います。

ここは、数値が一つなのに対して、塗るで確定しているマスが二つありますので、この間が塗れることが分かります。

これを実装します。

        // 解析パターンその7
        // 数字が1個で2マス塗られている場合はその間を塗る
        private void pattern7()
        {
            // Row
            pattern7Row();
            // Col
            pattern7Col();
        }

        private void pattern7Row()
        {
            int row = 0;
            foreach (var rowlist in rowNumbers)
            {
                if (rowlist.IsAnalyzed())
                {
                    row++;
                    continue;
                }

                if(rowlist.AnalyzeDatas.Count == 1)
                {
                    int value = rowlist.AnalyzeDatas[0].Value;
                    int startCol = 0;
                    int endCol = 0;
                    for (int col = 0; col < colNumbers.Count; col++)
                    {
                        if(_bitmapData[row, col].IsPainted() && startCol == 0)
                        {
                            startCol = col;
                        }
                        else if(_bitmapData[row, col].IsMasked() && startCol != 0)
                        {
                            break;
                        }
                        else if(_bitmapData[row, col].IsPainted() && startCol != 0)
                        {
                            endCol = col;
                        }
                    }

                    if(startCol== 0 || endCol == 0)
                    {
                        row++;
                        continue;
                    }

                    for(int col = startCol; col < endCol; col++)
                    {
                        _bitmapData[row, col].Paint();
                    }
                }
                row++;
            }
        }

        private void pattern7Col()
        {
            int col = 0;
            foreach (var collist in colNumbers)
            {
                if (collist.IsAnalyzed())
                {
                    col++;
                    continue;
                }

                if (collist.AnalyzeDatas.Count == 1)
                {
                    int value = collist.AnalyzeDatas[0].Value;
                    int startRow = 0;
                    int endRow = 0;
                    for (int row = 0; row < rowNumbers.Count; row++)
                    {
                        if (_bitmapData[row, col].IsPainted() && startRow == 0)
                        {
                            startRow = row;
                        }
                        else if (_bitmapData[row, col].IsMasked() && startRow != 0)
                        {
                            break;
                        }
                        else if (_bitmapData[row, col].IsPainted() && startRow != 0)
                        {
                            endRow = row;
                        }
                    }

                    if (startRow == 0 || endRow == 0)
                    {
                        col++;
                        continue;
                    }

                    for (int row = startRow; row < endRow; row++)
                    {
                        _bitmapData[row, col].Paint();
                    }
                }
                col++;
            }
        }

やっていることは簡単で、最初に塗られているマスと後に塗られているマスを探し、その間を塗る、というロジックです。

まずは1周実行してみます。

想定通りに塗られていますね。

では2周目

3周目

おや?

ここをマスクされると、縦11の数字の処理に矛盾が発生しますので、この動きはおかしいですね。

いろいろ調査してみましたが、解析パターン5でマスクを行っている用です。

なので、今の解析パターン5に問題があるようです。

なので、次回なおしましょうか。(今なおしたらハマりそう)

【C#】【ピクロス】【Altseed】新しい問題に取り組む

次はこの問題を解いてみようと思います。

これまで作成したアルゴリズムを適用してみました。

まぁ、そうだろうねぇ。

でもこれならまだ頭の中に解法はある。

次回からそれを実装していきましょう。

あ、ロード処理を少し修正しました。

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

https://github.com/takishita2nd/Picross

【ラズパイ】LCDディスプレイを購入してみた。

新しい遊び道具を購入しました。

LCDディスプレイです。

実際に使用するときはバックライトが白く光り、ドット単位で黒くする事ができる、らしいです。

これをラズパイで使って遊ぼうか、と。

なので、ラズパイのHATを取り外す。

そして、これとLCDディスプレイをつなぐためのケーブルを用意する。

あかんやん、オスーオスやん。

なので、これを使用する。

よく見るブレッドボードにヘッダーを取り付けました。

これを使うと、どのGPIOのピンがどこと対応しているかがすぐに分かります。

そして、本体とつなぐにはこれ。

接続。

そして、LCDディスプレイもオスが刺さるようにメスのヘッダを取り付ける。

あれ?これって、はんだづけが必要???

仕方が無い。ポチるか。

【C#】【ピクロス】【ALTSEED】解析パターンその6

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

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

https://github.com/takishita2nd/Picross

前回の続き。

前回は前から塗れるところをチェックしていきましたが、今回は後ろから塗れるところをチェックしていきます。

この時きちんと考えなくちゃいけないのは、データの順序。

今回、ここがぐっちゃになって一番ハマった。

前回のソースにも関連するのですが、

            foreach (var rowlist in rowNumbers)
            {
                if (rowlist.IsAnalyzed())
                {
                    row++;
                    continue;
                }

このrowlistをReverse()すると、元々の解析データ(rowNumbers)が壊れてしまうので、

            foreach (var rowlist in rowNumbers)
            {
                if (rowlist.IsAnalyzed())
                {
                    row++;
                    continue;
                }
                var tempRowList = rowlist.Clone();
                tempRowList.AnalyzeDatas.Reverse();

こんな感じでクローンを作成してReverse()しなくちゃいけない。

なので、クローンメソッドを追加。

    class AnalyzeData
    {
        public AnalyzeData Clone()
        {
            var clone = new AnalyzeData(Value);
            if (_analyzed)
            {
                clone.Analyzed();
            }
            return clone;
        }
    }
    class AnalyzeListData
    {
        public AnalyzeListData Clone()
        {
            var clone = new AnalyzeListData();
            clone.AnalyzeDatas = new List<AnalyzeData>();
            foreach (var data in AnalyzeDatas)
            {
                clone.AnalyzeDatas.Add(data.Clone());
            }
            if (_analyzed)
            {
                clone.Analyzed();
            }
            return clone;
        }
    }

そしてパターン6の実装。

データの順番に気をつけて。

        // 解析パターンその6
        // 端っこ(後ろ)が塗られていたら塗る。
        private void pattern6()
        {
            // Row
            pattern6Row();
            // Col
            pattern6Col();
        }

        private void pattern6Row()
        {
            int row = 0;
            foreach (var rowlist in rowNumbers)
            {
                if (rowlist.IsAnalyzed())
                {
                    row++;
                    continue;
                }
                var tempRowList = rowlist.Clone();
                tempRowList.AnalyzeDatas.Reverse();

                // 塗った場所が端っこならそこを塗る
                // マスクされていない部分をリスト化して取得する
                List<List<BitmapData>> data = new List<List<BitmapData>>();
                {
                    List<BitmapData> dataList = new List<BitmapData>();
                    for (int col = 0; col < colNumbers.Count; col++)
                    {
                        if (_bitmapData[row, col].IsMasked() == false)
                        {
                            dataList.Add(_bitmapData[row, col]);
                        }
                        else
                        {
                            if (dataList.Count != 0)
                            {
                                data.Add(dataList);
                                dataList = new List<BitmapData>();
                            }
                        }
                    }
                    if (dataList.Count != 0)
                    {
                        data.Add(dataList);
                    }

                    if (data.Count == 0)
                    {
                        row++;
                        continue;
                    }
                }

                int rowNumberIndex = 0;
                foreach (var dataList in data)
                {
                    // 端っこが塗られているか?
                    dataList.Reverse();
                    if (dataList[0].IsPainted())
                    {
                        // すでに処理済みか?
                        if (tempRowList.AnalyzeDatas[rowNumberIndex].IsAnalyzed())
                        {
                            rowNumberIndex++;
                            if (rowNumberIndex >= tempRowList.AnalyzeDatas.Count)
                            {
                                break;
                            }
                            continue;
                        }

                        // 数字に従ってマスを塗る
                        int count = 0;
                        foreach (var s in dataList)
                        {
                            if (count < tempRowList.AnalyzeDatas[rowNumberIndex].Value)
                            {
                                s.Paint();
                                count++;
                            }
                            else
                            {
                                if (s.IsMasked() == false)
                                {
                                    s.Mask();
                                }
                                tempRowList.AnalyzeDatas[rowNumberIndex].Analyzed();
                                tempRowList.CheckAnalyze();
                                break;
                            }
                        }
                    }
                    rowNumberIndex++;
                    if (rowNumberIndex >= tempRowList.AnalyzeDatas.Count)
                    {
                        break;
                    }
                }
                row++;
            }
        }

        private void pattern6Col()
        {
            int col = 0;
            foreach (var collist in colNumbers)
            {
                if (collist.IsAnalyzed())
                {
                    col++;
                    continue;
                }

                // 塗った場所が端っこならそこを塗る
                // マスクされていない部分をリスト化して取得する
                List<List<BitmapData>> data = new List<List<BitmapData>>();
                {
                    List<BitmapData> dataList = new List<BitmapData>();
                    for (int row = 0; row < rowNumbers.Count; row++)
                    {
                        if (_bitmapData[row, col].IsMasked() == false)
                        {
                            dataList.Add(_bitmapData[row, col]);
                        }
                        else
                        {
                            if (dataList.Count != 0)
                            {
                                data.Add(dataList);
                                dataList = new List<BitmapData>();
                            }
                        }
                    }
                    if (dataList.Count != 0)
                    {
                        data.Add(dataList);
                    }

                    if (data.Count == 0)
                    {
                        col++;
                        continue;
                    }
                }

                int colNumberIndex = 0;
                data.Reverse();
                foreach (var dataList in data)
                {
                    // 端っこが塗られているか?
                    dataList.Reverse();
                    if (dataList[0].IsPainted())
                    {
                        // すでに処理済みか?
                        if (collist.AnalyzeDatas[colNumberIndex].IsAnalyzed())
                        {
                            colNumberIndex++;
                            if (colNumberIndex >= collist.AnalyzeDatas.Count)
                            {
                                break;
                            }
                            continue;
                        }

                        // 数字に従ってマスを塗る
                        int count = 0;
                        foreach (var s in dataList)
                        {
                            if (count < collist.AnalyzeDatas[colNumberIndex].Value)
                            {
                                s.Paint();
                                count++;
                            }
                            else
                            {
                                if (s.IsMasked() == false)
                                {
                                    s.Mask();
                                }
                                collist.AnalyzeDatas[colNumberIndex].Analyzed();
                                collist.CheckAnalyze();
                                break;
                            }
                        }
                    }
                    colNumberIndex++;
                    if(colNumberIndex >= collist.AnalyzeDatas.Count)
                    {
                        break;
                    }
                }
                col++;
            }
        }

とりあえず、1回このロジックを当てはめてみる。

狙い通りに動いているみたいです。

なので、最後まで処理させてみる。

お、解けた。

多分、まだ完璧では無いですが、これで一歩前進です。

【C#】【ピクロス】【ALTSEED】解析パターンその5

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

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

https://github.com/takishita2nd/Picross

さて、今回はここを攻めていきます。

ここはマスクされたマスのすぐ隣に塗られたマスがあるので、当てはめる数字が分かればここも確実に塗ることができます。

ただ、前から塗る場合と後ろから塗る場合で、一緒に考えるとハマってしまうので、今回は前から塗るケースを考えました。

つまり、今回の対象はここになります。

解き方はこんな風に考えました。

空いているマスを抽出し、その端っこ(今回は先頭)が塗られているならば、数字に従って塗る。

そして、その次のマスは必ずマスクされますので、マスクする。

これでいきます。

        // 解析パターンその5
        // 端っこ(先頭)が塗られていたら塗る。
        private void pattern5()
        {
            // Row
            pattern5Row();
            // Col
            pattern5Col();
        }

        private void pattern5Row()
        {
            int row = 0;
            foreach (var rowlist in rowNumbers)
            {
                if (rowlist.IsAnalyzed())
                {
                    row++;
                    continue;
                }
                rowlist.AnalyzeDatas.Reverse();

                // 塗った場所が端っこならそこを塗る
                // マスクされていない部分をリスト化して取得する
                List<List<BitmapData>> data = new List<List<BitmapData>>();
                {
                    List<BitmapData> dataList = new List<BitmapData>();
                    for (int col = 0; col < colNumbers.Count; col++)
                    {
                        if (_bitmapData[row, col].IsMasked() == false)
                        {
                            dataList.Add(_bitmapData[row, col]);
                        }
                        else
                        {
                            if (dataList.Count != 0)
                            {
                                data.Add(dataList);
                                dataList = new List<BitmapData>();
                            }
                        }
                    }
                    if (dataList.Count != 0)
                    {
                        data.Add(dataList);
                    }

                    if (data.Count == 0)
                    {
                        row++;
                        continue;
                    }
                }

                int rowNumberIndex = 0;
                foreach (var dataList in data)
                {
                    // 端っこが塗られているか?
                    if (dataList[0].IsPainted())
                    {
                        // すでに処理済みか?
                        if (rowlist.AnalyzeDatas[rowNumberIndex].IsAnalyzed())
                        {
                            rowNumberIndex++;
                            continue;
                        }

                        // 数字に従ってマスを塗る
                        int count = 0;
                        foreach (var s in dataList)
                        {
                            if (count < rowlist.AnalyzeDatas[rowNumberIndex].Value)
                            {
                                s.Paint();
                                count++;
                            }
                            else
                            {
                                if (s.IsMasked() == false)
                                {
                                    s.Mask();
                                }
                                rowlist.AnalyzeDatas[rowNumberIndex].Analyzed();
                                rowlist.CheckAnalyze();
                                break;
                            }
                        }
                    }
                }
                row++;
            }
        }

        private void pattern5Col()
        {
            int col = 0;
            foreach (var collist in colNumbers)
            {
                if (collist.IsAnalyzed())
                {
                    col++;
                    continue;
                }
                collist.AnalyzeDatas.Reverse();

                // 塗った場所が端っこならそこを塗る
                // マスクされていない部分をリスト化して取得する
                List<List<BitmapData>> data = new List<List<BitmapData>>();
                {
                    List<BitmapData> dataList = new List<BitmapData>();
                    for (int row = 0; row < rowNumbers.Count; row++)
                    {
                        if (_bitmapData[row, col].IsMasked() == false)
                        {
                            dataList.Add(_bitmapData[row, col]);
                        }
                        else
                        {
                            if (dataList.Count != 0)
                            {
                                data.Add(dataList);
                                dataList = new List<BitmapData>();
                            }
                        }
                    }
                    if (dataList.Count != 0)
                    {
                        data.Add(dataList);
                    }

                    if (data.Count == 0)
                    {
                        col++;
                        continue;
                    }
                }

                int colNumberIndex = 0;
                foreach (var dataList in data)
                {
                    // 端っこが塗られているか?
                    if (dataList[0].IsPainted())
                    {
                        // すでに処理済みか?
                        if (collist.AnalyzeDatas[colNumberIndex].IsAnalyzed())
                        {
                            colNumberIndex++;
                            continue;
                        }

                        // 数字に従ってマスを塗る
                        int count = 0;
                        foreach (var s in dataList)
                        {
                            if (count < collist.AnalyzeDatas[colNumberIndex].Value)
                            {
                                s.Paint();
                                count++;
                            }
                            else
                            {
                                if (s.IsMasked() == false)
                                {
                                    s.Mask();
                                }
                                collist.AnalyzeDatas[colNumberIndex].Analyzed();
                                collist.CheckAnalyze();
                                break;
                            }
                        }
                    }
                }
                col++;
            }
        }

考え方は簡単に思えますが、実際に実装して見ると結構複雑になったりします。

このコーディングが正しく動かすまでに何度もデバッグを繰り返しました。

プログラミングとはそういうもんです。

基本的にトライエラーで正しく動くまで修正するのです。

実行結果はこうなりました。

小さな一歩ですが、確実に行きましょう。

【C#】【ピクロス】【ALTSEED】解析パターンその4

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

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

https://github.com/takishita2nd/Picross

この問題を解いてみました。

とりあえず、前回までのロジックを実装した解析プログラムを適用してみます。

当然、解けませんでした。

では、ここに注目してみましょう。

左の数字を見ると、真ん中に4マス空いていますので、そこが塗れると思います。

逆に考えれば、その左右にある1マスの所には塗れないことが明らかになっています。

ピクロスの解析の基本は、塗れないところはマスクしていく、と言うことなので、今回の解析パターンでは、こういったスペースをマスクするロジックを作成していきます。

それができれば、残ったスペースには解析パターン2が適用されて塗ってくれるはずです。

そこで、こういうクラスを用意しました。

        class Pattern4Data
        {
            public int Index;
            public int Value;
            public Pattern4Data(int index, int value)
            {
                Index = index;
                Value = value;
            }
        }

空きがある位置と、空いているマスの数を数えて保持します。

これをListで持ちます。

List<Pattern4Data> countList = new List<Pattern4Data>();

こうやって、空白のある部分を全て抽出します。

その中から、与えられた数字のマスが確実に入らないところ、とりあえずは、一番小さな値よりも小さいマスを検出して、その空白を全てマスクして塗れない様にします。

と言うわけで、こういうコードを書きました。

        // 解析パターンその4
        // 空いているマスが少なくて塗れないマスをマスクする
        private void pattern4()
        {
            // Row
            pattern4Row();
            // Col
            pattern4Col();
        }

        private void pattern4Row()
        {
            int row = 0;
            foreach (var rowlist in rowNumbers)
            {
                if (rowlist.IsAnalyzed())
                {
                    row++;
                    continue;
                }

                // マスクされていない連続したマスを数える
                int col = 0;
                int rememberCol = colNumbers.Count;
                int count = 0;
                List<Pattern4Data> countList = new List<Pattern4Data>();
                while (col < colNumbers.Count)
                {
                    if (_bitmapData[row, col].IsMasked() == false)
                    {
                        count++;
                        if(rememberCol == colNumbers.Count)
                        {
                            rememberCol = col;
                        }
                    }
                    else
                    {
                        if (count != 0)
                        {
                            countList.Add(new Pattern4Data(rememberCol, count));
                            count = 0;
                            rememberCol = colNumbers.Count;
                        }
                    }
                    col++;
                    if (col == colNumbers.Count)
                    {
                        if (count != 0)
                        {
                            countList.Add(new Pattern4Data(rememberCol, count));
                        }
                    }
                }

                // 数字の中で一番小さい値を取得する
                int val = colNumbers.Count;
                foreach(var s in rowlist.AnalyzeDatas)
                {
                    if(val > s.Value)
                    {
                        val = s.Value;
                    }
                }

                // マスクされていない連続したマスの数が数字より小さい場合はマスクする
                foreach(var data in countList)
                {
                    if(val > data.Value)
                    {
                        for(int i = 0; i< data.Value; i++)
                        {
                            if(_bitmapData[row, data.Index + i].IsValid() == false)
                            {
                                _bitmapData[row, data.Index + i].Mask();
                            }
                        }
                    }
                }
                row++;
            }
        }

        private void pattern4Col()
        {
            int col = 0;
            foreach (var collist in colNumbers)
            {
                if (collist.IsAnalyzed())
                {
                    col++;
                    continue;
                }

                // マスクされていない連続したマスを数える
                int row = 0;
                int rememberRow = rowNumbers.Count;
                int count = 0;
                List<Pattern4Data> countList = new List<Pattern4Data>();
                while (row < rowNumbers.Count)
                {
                    if (_bitmapData[row, col].IsMasked() == false)
                    {
                        count++;
                        if(rememberRow == rowNumbers.Count)
                        {
                            rememberRow = row;
                        }
                    }
                    else
                    {
                        if (count != 0)
                        {
                            countList.Add(new Pattern4Data(rememberRow, count));
                            count = 0;
                            rememberRow = rowNumbers.Count;
                        }
                    }
                    row++;
                    if (row == rowNumbers.Count)
                    {
                        if (count != 0)
                        {
                            countList.Add(new Pattern4Data(rememberRow, count));
                        }
                    }
                }

                // 数字の中で一番小さい値を取得する
                int val = rowNumbers.Count;
                foreach(var s in collist.AnalyzeDatas)
                {
                    if(val > s.Value)
                    {
                        val = s.Value;
                    }
                }

                // マスクされていない連続したマスの数が数字より小さい場合はマスクする
                foreach(var data in countList)
                {
                    if(val > data.Value)
                    {
                        for(int i = 0; i< data.Value; i++)
                        {
                            if(_bitmapData[data.Index + i, col].IsValid() == false)
                            {
                                _bitmapData[data.Index + i, col].Mask();
                            }
                        }
                    }
                }
                col++;
            }
        }
        public BitmapData[,] Run()
        {
            pattern1();
            while (checkPainedCount())
            {
                pattern2();
                pattern3();
                pattern4();
            }
            return _bitmapData;
        }

実行結果はこうなりました。

想定通りの動作をしていますね。