「C#」カテゴリーアーカイブ

【C#】【ピクロス】【ALTSEED】解析パターン12

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

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

https://github.com/takishita2nd/Picross

次はここを処理します。

数字が2つなのに対して、マスは2箇所、マスクされたマスを挟んで塗られているので、2つの数字はこのマスに繋がります。

なので、赤いところで囲まれた部分は塗ることができないのが分かります。

なので、ここをマスクします。

考え方は、マスクされていない部分のマスを抽出、リスト化し、塗られているマスを含むリストの数と数字の数が一致していた場合、塗られていないリストのマスをマスクする、という方法で行きます。

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

                // マスクされていない連続したマスを数える
                var data = getSquareDataListUnMaskedRow(row);
                if(data == null)
                {
                    row++;
                    rowlist.AnalyzeDatas.Reverse();
                    continue;
                }

                // 塗られているマスがあるところを確認する
                int i = 0;
                bool[] flg = new bool[data.Count];
                for(i = 0; i < data.Count; i++)
                {
                    flg[i] = false;
                }
                i = 0;
                int count = 0;
                foreach(var dataList in data)
                {
                    foreach(var p in dataList)
                    {
                        if (p.IsPainted())
                        {
                            flg[i] = true;
                            count++;
                            break;
                        }
                    }
                    i++;
                }

                // 数字の数とflgの数を比較
                if(rowlist.AnalyzeDatas.Count == count)
                {
                    // flgが立っていないマスをマスクする
                    i = 0;
                    foreach(var dataList in data)
                    {
                        if(flg[i] == false)
                        {
                            foreach(var p in dataList)
                            {
                                p.Mask();
                            }
                        }
                        i++;
                    }
                }

                rowlist.AnalyzeDatas.Reverse();
                row++;
            }
        }
        private List<List<BitmapData>> getSquareDataListUnMaskedRow(int row)
        {
            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)
            {
                return null;
            }

            return data;
        }

同じ処理をColに対しても行います。

実行結果はこちら。

だいぶ良い感じに埋まってきました。

【北海道大戦】マップデータを描画する

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

gitHubにソースファイルを公開しました。

https://github.com/takishita2nd/HokkaidoWar

前回作成したJsonファイルを読み込んで、画面に出力させたいと思います。

まずはJsonデータをオブジェクトで持つためのクラスを作成します。

    [JsonObject("MapDataModel")]
    public class MapData
    {
        [JsonProperty("list")]
        public List[] list { get; set; }
    }

    [JsonObject("List")]
    public class List
    {
        [JsonProperty("name")]
        public string name { get; set; }
        [JsonProperty("point")]
        public Point[] point { get; set; }
    }

    [JsonObject("Point")]
    public class Point
    {
        [JsonProperty("x")]
        public int x { get; set; }
        [JsonProperty("y")]
        public int y { get; set; }
    }

これは、Jsonをクリップボードにある状態で、「編集」→「形式を選択して貼り付け」→「Json」を選択すると簡単にJsonに合わせてクラスを作成してくれます。

では、実際にJsonを読み込んでオブジェクト化する処理。

    class FileAccess
    {
        private const string _filename = "hokkaido.json";
        public static MapData Load()
        {
            string str = string.Empty;
            using (var stream = new StreamReader(_filename, true))
            {
                str = stream.ReadToEnd();
            }
            return JsonConvert.DeserializeObject<MapData>(str);
        }
    }

これをAltseedで画面に表示させます。

    class HokkaidoWar
    {
        MapData mapData = null;
        public HokkaidoWar()
        {
            mapData = FileAccess.Load();
        }

        public void Run()
        {
            asd.Engine.Initialize("北海道大戦", 1800, 1000, new asd.EngineOption());

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

            var r = new Random();
            foreach (var map in mapData.list)
            {
                var color = new asd.Color((byte)r.Next(0, 255), (byte)r.Next(0, 255), (byte)r.Next(0, 255));
                foreach (var point in map.point)
                {
                    var geometryObj = new asd.GeometryObject2D();
                    geometryObj.Color = color;
                    asd.Engine.AddObject2D(geometryObj);
                    var rect = new asd.RectangleShape();
                    rect.DrawingArea = new asd.RectF(24 * point.x + 50, 24 * point.y + 50, 24, 24);
                    geometryObj.Shape = rect;
                }
            }

            while (asd.Engine.DoEvents())
            {
                asd.Engine.Update();
            }
            asd.Engine.Terminate();
        }
    }
        static void Main(string[] args)
        {
            HokkaidoWar hokkaidoWar = new HokkaidoWar();
            hokkaidoWar.Run();
        }

色はとりあえず乱数で振ることにしました。

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

【C#】【ピクロス】【ALTSEED】解析パターン11

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

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

https://github.com/takishita2nd/Picross

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

解析実行。

この状態で止まってしまいましたね。

また新しい解析パターンを追加する必要があるようです。

ここに注目してみました。

この列では4が一番大きい数字で、すでに4マス塗られていますので、この4はすでに確定します。

なので、この4は解析済みにし、両端をマスクする、というロジックが必要です。

これを実装します。

考え方は、

  1. 行、列から連続する塗られたマスを取得する
  2. その中から最大の物を取得する
  3. 数字の中で一番大きい物を取得する
  4. 取得した連続するマスの数が、一番多き数字と一致するかどうかを確認する
  5. 一致するならば、その数字を解析済みにし、塗られた連続するマスの両端をマスクする

コードはこうなりました。

        // 解析パターンその11
        // すでに塗っている場所を解析済みにする
        private void pattern11()
        {
            // Row
            pattern11Row();
            // Col
            pattern11Col();
        }

        private void pattern11Row()
        {
            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].IsPainted() == true)
                        {
                            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++;
                        rowlist.AnalyzeDatas.Reverse();
                        continue;
                    }
                }

                List<BitmapData> targetDataList = null;
                // 最大の物を取得する
                foreach (var datalist in data)
                {
                    if(targetDataList == null)
                    {
                        targetDataList = datalist;
                    }
                    else if(targetDataList.Count < datalist.Count)
                    {
                        targetDataList = datalist;
                    }
                }

                AnalyzeData targetRowList = null;
                foreach(var rowdata in rowlist.AnalyzeDatas)
                {
                    if(targetRowList == null)
                    {
                        targetRowList = rowdata;
                    }
                    else if(targetRowList.Value < rowdata.Value)
                    {
                        targetRowList = rowdata;
                    }

                }

                if(targetDataList.Count == targetRowList.Value)
                {
                    //解析済みにする
                    targetRowList.Analyzed();
                    if(targetDataList[0].Col > 0)
                    {
                        if (_bitmapData[targetDataList[0].Row, targetDataList[0].Col - 1].IsValid() == false)
                        {
                            _bitmapData[targetDataList[0].Row, targetDataList[0].Col - 1].Mask();
                        }
                    }
                    if (targetDataList[targetDataList.Count - 1].Col < colNumbers.Count - 1)
                    {
                        if (_bitmapData[targetDataList[targetDataList.Count - 1].Row, targetDataList[targetDataList.Count - 1].Col + 1].IsValid() == false)
                        {
                            _bitmapData[targetDataList[targetDataList.Count - 1].Row, targetDataList[targetDataList.Count - 1].Col + 1].Mask();
                        }
                    }
                }

                rowlist.AnalyzeDatas.Reverse();
                row++;
            }
        }

        private void pattern11Col()
        {
            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].IsPainted() == true)
                        {
                            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++;
                        collist.AnalyzeDatas.Reverse();
                        continue;
                    }
                }

                List<BitmapData> targetDataList = null;
                // 最大の物を取得する
                foreach (var datalist in data)
                {
                    if (targetDataList == null)
                    {
                        targetDataList = datalist;
                    }
                    else if (targetDataList.Count < datalist.Count)
                    {
                        targetDataList = datalist;
                    }
                }

                AnalyzeData targetColList = null;
                foreach (var coldata in collist.AnalyzeDatas)
                {
                    if (targetColList == null)
                    {
                        targetColList = coldata;
                    }
                    else if (targetColList.Value < coldata.Value)
                    {
                        targetColList = coldata;
                    }

                }

                if (targetDataList.Count == targetColList.Value)
                {
                    //解析済みにする
                    targetColList.Analyzed();
                    if (targetDataList[0].Row > 0)
                    {
                        if (_bitmapData[targetDataList[0].Row - 1, targetDataList[0].Col].IsValid() == false)
                        {
                            _bitmapData[targetDataList[0].Row - 1, targetDataList[0].Col].Mask();
                        }
                    }
                    if (targetDataList[targetDataList.Count - 1].Row < colNumbers.Count - 1)
                    {
                        if (_bitmapData[targetDataList[targetDataList.Count - 1].Row + 1, targetDataList[targetDataList.Count - 1].Col].IsValid() == false)
                        {
                            _bitmapData[targetDataList[targetDataList.Count - 1].Row + 1, targetDataList[targetDataList.Count - 1].Col].Mask();
                        }
                    }
                }

                collist.AnalyzeDatas.Reverse();
                col++;
            }
        }

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

まだ完全では無いですが、少し進みましたね。

【C#】【ピクロス】【ALTSEED】データ入力UIの改善

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

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

https://github.com/takishita2nd/Picross

いままではデータ入力値がパレットの陰に隠れて見えづらい、という問題をうすうすと感じていましたが、これを修正したいと思います。

具体的には、パレットの上に入力値を表示し、ENTERボタンを押下することで入力データを反映させます。

なので、パレットを拡張。

そして、パレット周りの処理をがっつり書き換えました。

    class Palette
    {
        public void OnClick(asd.Vector2DF pos)
        {
            if (paletteZeroSquareObject.IsClick(pos))
            {
                if(_valueText.Text != "" && _valueText.Text != "0")
                {
                    if (_valueText.Text.Length < 2)
                    {
                        _valueText.Text += "0";
                    }
                }
            }
            else if (paletteBSSquareObject.IsClick(pos))
            {
                if(_valueText.Text.Length > 0)
                {
                    _valueText.Text = _valueText.Text.Remove(_valueText.Text.Length - 1);
                }
            }
            else if (paletteCRSquareObject.IsClick(pos))
            {
                _valueText.Text = "";
            }
            else if (paletteENSquareObject.IsClick(pos))
            {
                value = _valueText.Text;
                _isClickEnter = true;
            }
            else
            {
                for (int row = 0; row < 3; row++)
                {
                    for (int col = 0; col < 3; col++)
                    {
                        if (paletteSquareObjects[row, col].IsClick(pos) == true)
                        {
                            if(_valueText.Text.Length < 2)
                            {
                                if(_valueText.Text == "0")
                                {
                                    _valueText.Text = paletteSquareObjects[row, col].GetValue();
                                }
                                else
                                {
                                    _valueText.Text += paletteSquareObjects[row, col].GetValue();
                                }
                            }
                        }
                    }
                }
            }
        }

        public bool IsClickEnter()
        {
            return _isClickEnter;
        }

        public string GetValue()
        {
            return value;
        }

パレットを使用する側もがっつり書き換えます。

                            if (palette.IsClick(pos))
                            {
                                string value = string.Empty;
                                palette.OnClick(pos);
                                if(palette.IsClickEnter())
                                {
                                    palette.Hide();
                                    if (selectedNumberSquare != null)
                                    {
                                        selectedNumberSquare.SetValue(palette.GetValue());
                                        if (selectedNumberSquare.GetStringValue() != string.Empty)
                                        {
                                            if (selectedRowIndex >= 0)
                                            {
                                                if (Math.Abs(selectedColIndex - 1) > rowNumberSquare[selectedRowIndex].Count)
                                                {
                                                    var square = new NumberSquare(selectedRowIndex, selectedColIndex - 1);
                                                    asd.Engine.AddObject2D(square.getBackTexture());
                                                    asd.Engine.AddObject2D(square.getTextObject());
                                                    rowNumberSquare[selectedRowIndex].Add(square);
                                                }
                                            }
                                            else if (selectedColIndex >= 0)
                                            {
                                                if (Math.Abs(selectedRowIndex - 1) > colNumberSquare[selectedColIndex].Count)
                                                {
                                                    var square = new NumberSquare(selectedRowIndex - 1, selectedColIndex);
                                                    asd.Engine.AddObject2D(square.getBackTexture());
                                                    asd.Engine.AddObject2D(square.getTextObject());
                                                    colNumberSquare[selectedColIndex].Add(square);
                                                }
                                            }
                                        }
                                        else
                                        {
                                            if (selectedRowIndex >= 0)
                                            {
                                                if (Math.Abs(selectedColIndex - 1) <= rowNumberSquare[selectedRowIndex].Count)
                                                {
                                                    asd.Engine.RemoveObject2D(rowNumberSquare[selectedRowIndex][Math.Abs(selectedColIndex + 1)].getBackTexture());
                                                    asd.Engine.RemoveObject2D(rowNumberSquare[selectedRowIndex][Math.Abs(selectedColIndex + 1)].getTextObject());
                                                    rowNumberSquare[selectedRowIndex].RemoveAt(Math.Abs(selectedColIndex + 1));
                                                    for (int col = selectedColIndex + 1; Math.Abs(col) < rowNumberSquare[selectedRowIndex].Count; col--)
                                                    {
                                                        rowNumberSquare[selectedRowIndex][Math.Abs(col)].SetPosition(selectedRowIndex, col - 1);
                                                    }
                                                }
                                            }
                                            else if (selectedColIndex >= 0)
                                            {
                                                if (Math.Abs(selectedRowIndex - 1) <= colNumberSquare[selectedColIndex].Count)
                                                {
                                                    asd.Engine.RemoveObject2D(colNumberSquare[selectedColIndex][Math.Abs(selectedRowIndex + 1)].getBackTexture());
                                                    asd.Engine.RemoveObject2D(colNumberSquare[selectedColIndex][Math.Abs(selectedRowIndex + 1)].getTextObject());
                                                    colNumberSquare[selectedColIndex].RemoveAt(Math.Abs(selectedRowIndex + 1));
                                                    for (int row = selectedRowIndex + 1; Math.Abs(row) < colNumberSquare[selectedColIndex].Count; row--)
                                                    {
                                                        colNumberSquare[selectedColIndex][Math.Abs(row)].SetPosition(row - 1, selectedColIndex);
                                                    }
                                                }
                                            }
                                            selectedNumberSquare.SetValue("0");
                                        }
                                        selectedNumberSquare = null;
                                    }
                                }
                            }
                            else
                            {
                                palette.Hide();
                            }

とりあえず、UI周りはこれで十分かと思います。

じゃあ、ロジックに戻りましょうか。

【C#】【ピクロス】【ALTSEED】簡単な問題は解けるようになりました(たぶん)

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

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

https://github.com/takishita2nd/Picross

あれから、いくつかの問題を解いてみましたが、まだまだ不具合が多く、調査・修正しながら解いていきました。

どこを直したかはgitHubのコードを参照して頂きたく。

だいたいここまで攻略できれば、解析処理も一段落できそう。

解析処理は一旦ここまでにして、UI側の修正に戻ろうと思います。

いろいろ弄っていると、UIの挙動にもおかしいところが見受けられたので、その修正を行いたいと思います。

【C#】【ピクロス】【ALTSEED】いろいろと修正。

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

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

https://github.com/takishita2nd/Picross

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

もちろん一発で解けるとは思っていませんでした。

しかし、ここまでハマるとは・・・

解析パターン5にバグがあって、

いろいろコードを書き換えながら試行錯誤していったんですが、

結局、コードと格闘すること5時間。

解けました。

大きな変更としては、解析済みの数字に対して、きちんと解析済みフラグを設定しましょう、ということで、

要するに、

縦の数字を埋めていったら、横の数字も出来上がっているにもかかわらず、解析済みフラグが立っていないケースがあって、それで動きがおかしくなっていたので、きちんと解析完了フラグを立てましょう、ということを入れました。

        private void checkAnalyze()
        {
            checkAnalyzeRowBefore();
            checkAnalyzeRowAfter();
            checkAnalyzeColBefore();
            checkAnalyzeColAfter();
        }

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

                rowList.AnalyzeDatas.Reverse();
                int rowIndex = 0;
                foreach(var rowData in rowList.AnalyzeDatas)
                {
                    if (rowData.IsAnalyzed())
                    {
                        rowIndex++;
                    }
                    else
                    {
                        break;
                    }
                }
                if (rowIndex == rowList.AnalyzeDatas.Count)
                {
                    rowList.AnalyzeDatas.Reverse();
                    row++;
                    continue;
                }

                int painted = 0;
                int count = 0;
                for (int col = 0; col < colNumbers.Count; col++)
                {
                    if (_bitmapData[row, col].IsPainted())
                    {
                        painted++;
                    }
                    else if (_bitmapData[row, col].IsMasked())
                    {
                        if(count == rowIndex)
                        {
                            if (rowList.AnalyzeDatas[rowIndex].Value == painted)
                            {
                                rowList.AnalyzeDatas[rowIndex].Analyzed();
                                rowList.CheckAnalyze();
                            }
                        }
                        else
                        {
                            count++;
                        }
                    }
                    else
                    {
                        rowList.AnalyzeDatas.Reverse();
                        row++;
                        break;
                    }
                }
            }
        }

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

                int rowIndex = 0;
                foreach (var rowData in rowList.AnalyzeDatas)
                {
                    if (rowData.IsAnalyzed())
                    {
                        rowIndex++;
                    }
                    else
                    {
                        break;
                    }
                }
                if(rowIndex == rowList.AnalyzeDatas.Count)
                {
                    row++;
                    continue;
                }

                int painted = 0;
                int count = 0;
                for (int col = colNumbers.Count - 1; col >= 0; col--)
                {
                    if (_bitmapData[row, col].IsPainted())
                    {
                        painted++;
                    }
                    else if (_bitmapData[row, col].IsMasked())
                    {
                        if (count == rowIndex)
                        {
                            if (rowList.AnalyzeDatas[rowIndex].Value == painted)
                            {
                                rowList.AnalyzeDatas[rowIndex].Analyzed();
                                rowList.CheckAnalyze();
                            }
                        }
                        else
                        {
                            count++;
                        }
                    }
                    else
                    {
                        row++;
                        break;
                    }
                }
            }
        }

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

                colList.AnalyzeDatas.Reverse();
                int colIndex = 0;
                foreach (var colData in colList.AnalyzeDatas)
                {
                    if (colData.IsAnalyzed())
                    {
                        colIndex++;
                    }
                    else
                    {
                        break;
                    }
                }
                if (colIndex == colList.AnalyzeDatas.Count)
                {
                    colList.AnalyzeDatas.Reverse();
                    col++;
                    continue;
                }
                int painted = 0;
                int count = 0;
                for (int row = 0; row < rowNumbers.Count; row++)
                {
                    if (_bitmapData[row, col].IsPainted())
                    {
                        painted++;
                    }
                    else if (_bitmapData[row, col].IsMasked())
                    {
                        if (count == colIndex)
                        {
                            if (colList.AnalyzeDatas[colIndex].Value == painted)
                            {
                                colList.AnalyzeDatas[colIndex].Analyzed();
                                colList.CheckAnalyze();
                            }
                        }
                        else
                        {
                            count++;
                        }
                    }
                    else
                    {
                        colList.AnalyzeDatas.Reverse();
                        col++;
                        break;
                    }
                }
            }
        }

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

                int colIndex = 0;
                foreach (var colData in colList.AnalyzeDatas)
                {
                    if (colData.IsAnalyzed())
                    {
                        colIndex++;
                    }
                    else
                    {
                        break;
                    }
                }
                if (colIndex == colList.AnalyzeDatas.Count)
                {
                    col++;
                    continue;
                }
                int painted = 0;
                int count = 0;
                for (int row = rowNumbers.Count - 1; row >= 0; row--)
                {
                    if (_bitmapData[row, col].IsPainted())
                    {
                        painted++;
                    }
                    else if (_bitmapData[row, col].IsMasked())
                    {
                        if (count == colIndex)
                        {
                            if (colList.AnalyzeDatas[colIndex].Value == painted)
                            {
                                colList.AnalyzeDatas[colIndex].Analyzed();
                                colList.CheckAnalyze();
                            }
                        }
                        else
                        {
                            count++;
                        }
                    }
                    else
                    {
                        col++;
                        break;
                    }
                }
            }
        }

細かい所は、直接gitHubのコードを見て欲しく。

何より大変だったのは、既存部分を変更することにより、過去の問題が解けなくなる可能性もあり、その確認のため、過去問を引っ張り出してきたこと。

セーブ&ロード機能実装してて正解だったわ。

無かったら確実に発狂してる。

とはいえ、この作業に大半の時間を使ってしまったので、他の作業ができなかったので、今日は他の作業に取りかかろう。

【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のソースコードを見て欲しい。

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

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

これから考えます。