「#ピクロス」タグアーカイブ

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

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

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

https://github.com/takishita2nd/Picross

次は、ここに注目します。

数字が、2,6と並んでいます。

ということは、下の6の数字では、上3マス(数字の2マスとマスク分1マス)は絶対に塗ることはできません。

なので、6という数字については、上の3マスを除いた7マスの間で中心を塗る、解析パターン8と同じロジックが適用できます。

        // 解析パターンその10
        // 中央の塗った場所から、塗れない場所をマスクする(数字が2個の場合)
        private void pattern10()
        {
            // Row
            pattern10Row();
            // Col
            pattern10Col();
        }

        private void pattern10Row()
        {
            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 != 2)
                {
                    row++;
                    continue;
                }

                // 対象となるマスを抽出する
                List<List<BitmapData>> bitmapLists = extractTargetBitmapListsCol(row);
                if (bitmapLists.Count != 1)
                {
                    row++;
                    continue;
                }

                // 塗られている場所を特定
                int leftCol = colNumbers.Count;
                int rightCol = 0;
                bool painted = false;
                foreach (var bitmap in bitmapLists[0])
                {
                    if(bitmap.IsPainted())
                    {
                        leftCol = bitmap.Col;
                        painted = true;
                    }
                    else
                    {
                        if (painted)
                        {
                            rightCol = bitmap.Col;
                            break;
                        }
                    }
                }

                var bitmaplist = bitmapLists[0];
                if(bitmaplist.Count <= 1)
                {
                    row++;
                    continue;
                }

                // 塗る対象は右側か、左側か?
                int bigValue = 0;
                int smallValue = 0;
                if (values[0] > values[1])
                {
                    bigValue = values[0];
                    smallValue = values[1];
                    bitmaplist.RemoveRange(0, smallValue + 1);
                }
                else
                {
                    bigValue = values[1];
                    smallValue = values[0];
                    bitmaplist.RemoveRange(bitmaplist.Count - (smallValue + 1), smallValue + 1);
                }

                paintCenter(bigValue, ref bitmaplist);

                row++;
            }
        }

        private void pattern10Col()
        {
            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 != 2)
                {
                    col++;
                    continue;
                }

                // 対象となるマスを抽出する
                List<List<BitmapData>> bitmapLists = extractTargetBitmapListsRow(col);
                if (bitmapLists.Count != 1)
                {
                    col++;
                    continue;
                }

                // 塗られている場所を特定
                int topRow = rowNumbers.Count;
                int downRow = 0;
                bool painted = false;
                foreach (var bitmap in bitmapLists[0])
                {
                    if (bitmap.IsPainted())
                    {
                        topRow = bitmap.Row;
                        painted = true;
                    }
                    else
                    {
                        if (painted)
                        {
                            downRow = bitmap.Row;
                            break;
                        }
                    }
                }

                var bitmaplist = bitmapLists[0];
                if (bitmaplist.Count <= 1)
                {
                    col++;
                    continue;
                }

                // 塗る対象は右側か、左側か?
                int bigValue = 0;
                int smallValue = 0;
                if (values[0] > values[1])
                {
                    bigValue = values[0];
                    smallValue = values[1];
                    bitmaplist.RemoveRange(0, smallValue + 1);
                }
                else
                {
                    bigValue = values[1];
                    smallValue = values[0];
                    bitmaplist.RemoveRange(bitmaplist.Count - (smallValue + 1), smallValue + 1);
                }

                paintCenter(bigValue, ref bitmaplist);

                col++;
            }
        }

今回は数字が2個の場合で、数字が大きい方のみを対象としました。

パターン8、9、10で共通化できる処理があったので、サブルーチンで共通化しています。

        private List<List<BitmapData>> extractTargetBitmapListsCol(int row)
        {
            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);
            }

            return bitmapLists;
        }

        private List<List<BitmapData>> extractTargetBitmapListsRow(int col)
        {
            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);
            }

            return bitmapLists;
        }

        private void paintCenter(int value, ref List<BitmapData> bitmaps)
        {
            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();
                }
            }
        }

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

これはウサギかな?

解けたようです。

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

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

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

https://github.com/takishita2nd/Picross

次はこの問題を解いてみます。

解析を実行するとこうなりました。

今回はここに注目します。

10×10の問題ですが、例えば行の数字が7の場合、すでに真ん中の5マスが塗られているので、一番左の1マスは塗ることができないのが分かります。

同じ理由で、行の数字が6ならば、左2マスが塗ることができません。

なので、ここをマスクしちゃいましょう。

今回は条件を簡潔にしたいので、数字が1個の場合で、塗られている部分も1かたまりになっている場合のみとします。

        // 解析パターンその9
        // 中央の塗った場所から、塗れない場所をマスクする
        private void pattern9()
        {
            // Row
            pattern9Row();
            // Col
            pattern9Col();
        }

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

                // 有効な数字で一番大きいものを取り出す
                if(rowlist.AnalyzeDatas.Count != 1)
                {
                    row++;
                    continue;
                }
                int value = rowlist.AnalyzeDatas[0].Value;

                // 対象となるマスを抽出する
                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 leftCol = colNumbers.Count;
                int rightCol = 0;
                bool painted = false;
                foreach (var bitmap in bitmapLists[0])
                {
                    if(bitmap.IsPainted())
                    {
                        leftCol = bitmap.Col;
                        painted = true;
                    }
                    else
                    {
                        if (painted)
                        {
                            rightCol = bitmap.Col;
                            break;
                        }
                    }
                }
                // 左側をマスク
                for(int col = 0; col < rightCol - value; col++)
                {
                    if(_bitmapData[row,col].IsValid() == false)
                    {
                        _bitmapData[row, col].Mask();
                    }
                }

                // 右側をマスク
                for (int col = leftCol + value; col < colNumbers.Count; col++)
                {
                    if (_bitmapData[row, col].IsValid() == false)
                    {
                        _bitmapData[row, col].Mask();
                    }
                }

                row++;
            }
        }

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

                // 有効な数字で一番大きいものを取り出す
                if (collist.AnalyzeDatas.Count != 1)
                {
                    col++;
                    continue;
                }
                int value = collist.AnalyzeDatas[0].Value;

                // 対象となるマスを抽出する
                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 topRow = rowNumbers.Count;
                int downRow = 0;
                bool painted = false;
                foreach (var bitmap in bitmapLists[0])
                {
                    if (bitmap.IsPainted())
                    {
                        topRow = bitmap.Row;
                        painted = true;
                    }
                    else
                    {
                        if (painted)
                        {
                            downRow = bitmap.Row;
                            break;
                        }
                    }
                }
                // 左側をマスク
                for (int row = 0; row < downRow - value; row++)
                {
                    if (_bitmapData[row, col].IsValid() == false)
                    {
                        _bitmapData[row, col].Mask();
                    }
                }

                // 右側をマスク
                for (int row = topRow + value; row < rowNumbers.Count; row++)
                {
                    if (_bitmapData[row, col].IsValid() == false)
                    {
                        _bitmapData[row, col].Mask();
                    }
                }

                col++;
            }
        }

塗られている塊の部分を探し、その左端の行、列と右端の行、列を取得し、その値を数字からどこまでマスクされるかを探しています。

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

あまり大きな変化はありませんでしたが、こういうときこそ、塗ることができないマスは確実に潰していく事が、ピクロスの解析に重要です。

ちなみに、こんな問題、解けました。

【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;
        }

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

全て埋まりましたね。

解けたようです。

やったぁ。

【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

【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】解析パターンその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;
        }

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

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

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

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

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

https://github.com/takishita2nd/Picross

次は、ここを攻めていきます。

この赤い部分、すでに塗られているマスから、開いているマスは全て塗ることができないことが分かると思います。

これを処理していきましょう。

パターン2では塗られていないマスを数えましたが、パターン3では塗られているマスを数えます。

コードはパターン2と似ていますが、条件が変わっています。

        // 解析パターンその3
        // すでに塗りつぶされたマスからマスクをする
        private void pattern3()
        {
            // Row
            pattern3Row();
            // Col
            pattern3Col();
        }

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

                // 塗ったマスを数える
                int col = 0;
                int count = 0;
                List<int> countList = new List<int>();
                while (col < colNumbers.Count)
                {
                    if (_bitmapData[row, col].IsPainted())
                    {
                        count++;
                    }
                    else
                    {
                        if (count != 0)
                        {
                            countList.Add(count);
                            count = 0;
                        }
                    }
                    col++;
                    if (col == colNumbers.Count)
                    {
                        if (count != 0)
                        {
                            countList.Add(count);
                        }
                    }
                }
                // 数えた数字が全て一致すれば確定とする
                bool result = true;
                if (rowlist.AnalyzeDatas.Count != countList.Count)
                {
                    row++;
                    continue;
                }
                for (int i = 0; i < countList.Count; i++)
                {
                    if (rowlist.AnalyzeDatas[i].Value != countList[i])
                    {
                        result = false;
                    }
                }
                if (result)
                {
                    // 開いているところをマスクする
                    col = 0;
                    while (col < colNumbers.Count)
                    {
                        if (_bitmapData[row, col].IsValid() == false)
                        {
                            _bitmapData[row, col].Mask();
                        }
                        col++;
                    }
                    rowlist.Analyzed();
                }
                row++;
            }
        }

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

                // 塗ったマスを数える
                int row = 0;
                int count = 0;
                List<int> countList = new List<int>();
                while (row < rowNumbers.Count)
                {
                    if (_bitmapData[row, col].IsPainted())
                    {
                        count++;
                    }
                    else
                    {
                        if (count != 0)
                        {
                            countList.Add(count);
                            count = 0;
                        }
                    }
                    row++;
                    if (row == rowNumbers.Count)
                    {
                        if(count != 0)
                        {
                            countList.Add(count);
                        }
                    }
                }
                // 数えた数字が全て一致すれば確定とする
                bool result = true;
                if (collist.AnalyzeDatas.Count != countList.Count)
                {
                    col++;
                    continue;
                }
                countList.Reverse();
                for (int i = 0; i < countList.Count; i++)
                {
                    if (collist.AnalyzeDatas[i].Value != countList[i])
                    {
                        result = false;
                    }
                }
                if (result)
                {
                    // 開いているところをマスクする
                    row = 0;
                    while (row < rowNumbers.Count)
                    {
                        if (_bitmapData[row, col].IsValid() == false)
                        {
                            _bitmapData[row, col].Mask();
                        }
                        row++;
                    }
                    collist.Analyzed();
                }
                col++;
            }
        }

実行結果はこちら。

ここまで来たら、パターン2とパターン3の繰り返しで全て塗れるのでは無いでしょうか?

では、パターン2とパターン3をループ処理させるのに、終了条件を判定する処理を作成します。

        private bool checkPainedCount()
        {
            int newPaintedCount = 0;
            for (int row = 0; row < rowNumbers.Count; row++)
            {
                for(int col = 0; col < colNumbers.Count; col++)
                {
                    if(_bitmapData[row, col].IsValid())
                    {
                        newPaintedCount++;
                    }
                }
            }
            if(oldPaintedCount == newPaintedCount)
            {
                return false;
            }
            oldPaintedCount = newPaintedCount;
            return true;
        }

考え方は、全てのマスが確定したかを判定し、その数を数えます。

ループ前とループ後のカウント数を比較し、変化があればカウント数を更新、変化が無ければループを終了します。

        public BitmapData[,] Run()
        {
            pattern1();
            while (checkPainedCount())
            {
                pattern2();
                pattern3();
            }
            return _bitmapData;
        }

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

これは・・・黒電話かな?

解けたようです。

まだ完全ではないですが、簡単な問題ならこれで解けそうです。

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

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

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

https://github.com/takishita2nd/Picross

つぎはどう攻めていくかというと、ここに注目しましょう。

ここも塗れるのが確定していますよね。

ここを塗るための条件を確認しましょう。

マスクされていないマスを数え、連続したマスの数と、範囲の数が全て一致した場合、確定とする。

つまり、

マスクされていないマスが2個、1個、2個と並んでいて、これらが全て左の数字と一致するため、この開いているマスは全て塗ることができます。

これをコーディングします。

    // 解析パターンその2
    private void pattern2()
    {
        // Row
        pattern2Row();
        // Col
        pattern2Col();
    }
        private void pattern2Row()
        {
            int row = 0;
            foreach (var rowlist in rowNumbers)
            {
                if (rowlist.IsAnalyzed())
                {
                    row++;
                    continue;
                }

                // マスクされていない連続したマスを数える
                int col = 0;
                int count = 0;
                List<int> countList = new List<int>();
                while (col < colNumbers.Count)
                {
                    if (_bitmapData[row, col].IsMasked() == false)
                    {
                        count++;
                    }
                    else
                    {
                        if (count != 0)
                        {
                            countList.Add(count);
                            count = 0;
                        }
                    }
                    col++;
                    if(col == colNumbers.Count)
                    {
                        countList.Add(count);
                    }
                }
                // 数えた数字が全て一致すれば確定とする
                bool result = true;
                if (rowlist.AnalyzeDatas.Count != countList.Count)
                {
                    row++;
                    continue;
                }
                for (int i = 0; i < countList.Count; i++)
                {
                    if (rowlist.AnalyzeDatas[i].Value != countList[i])
                    {
                        result = false;
                    }
                }
                if (result)
                {
                    // 開いているところを塗る
                    col = 0;
                    while (col < colNumbers.Count)
                    {
                        if(_bitmapData[row, col].IsValid() == false)
                        {
                            _bitmapData[row, col].Paint();
                        }
                        col++;
                    }
                    rowlist.Analyzed();
                }
                row++;
            }
        }

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

                // マスクされていない連続したマスを数える
                int row = 0;
                int count = 0;
                List<int> countList = new List<int>();
                while (row < rowNumbers.Count)
                {
                    if (_bitmapData[row, col].IsMasked() == false)
                    {
                        count++;
                    }
                    else
                    {
                        if (count != 0)
                        {
                            countList.Add(count);
                            count = 0;
                        }
                    }
                    row++;
                    if (row == rowNumbers.Count)
                    {
                        countList.Add(count);
                    }
                }
                // 数えた数字が全て一致すれば確定とする
                bool result = true;
                if (collist.AnalyzeDatas.Count != countList.Count)
                {
                    col++;
                    continue;
                }
                countList.Reverse();
                for (int i = 0; i < countList.Count; i++)
                {
                    if (collist.AnalyzeDatas[i].Value != countList[i])
                    {
                        result = false;
                    }
                }
                if (result)
                {
                    // 開いているところを塗る
                    row = 0;
                    while (row < rowNumbers.Count)
                    {
                        if (_bitmapData[row, col].IsValid() == false)
                        {
                            _bitmapData[row, col].Paint();
                        }
                        row++;
                    }
                    collist.Analyzed();
                }
                col++;
            }
        }

数える→数を確認する→塗るの順で処理しています。

少しデータの持ち方も変えています。

    private List<AnalyzeListData> rowNumbers;
    private List<AnalyzeListData> colNumbers;
    class AnalyzeListData
    {
        private bool _analyzed;
        public List<AnalyzeData> AnalyzeDatas;

        public AnalyzeListData()
        {
            _analyzed = false;
            AnalyzeDatas = new List<AnalyzeData>();
        }

        public bool IsAnalyzed()
        {
            return _analyzed;
        }

        public void Analyzed()
        {
            _analyzed = true;
        }
    class AnalyzeData
    {
        private bool _analyzed;
        public int Value { get; }

        public AnalyzeData(int value)
        {
            Value = value;
            _analyzed = false;
        }

        public bool IsAnalyzed()
        {
            return _analyzed;
        }

        public void Analyzed()
        {
            _analyzed = true;
        }

    }

どのデータを塗ったかどうかを確認できるようにしています。

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

うん、順調ですね。