「#C#」タグアーカイブ

【北海道大戦】人口データを作成・読み込ませる

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

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

https://github.com/takishita2nd/HokkaidoWar

北海道大戦では、人口がそのまま戦力値として使用したいと思っています。

なので、人口データを入力します。

こちらに掲載されている人口データを参照しました。

https://uub.jp/cty/hokkaido.html

EXCELマクロを修正して、出力Jsonに人口データを含めます。

あとは、プログラム本体側を修正し、人口データを読み込ませるようにします。

たいした修正では無いので、詳細はgitHubを参照してください。

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

たぶん、一番人口が少ない音威子府。

そして、一番多いのは、言わずもがな札幌市。

ちなみに、一番人口の少ない市は歌志内市。

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

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

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

https://github.com/takishita2nd/Picross

次はここを処理します。

ここは数字が[3,1]とありますが、すでに3マス塗られているので、その上にある空白はマスクされるのが確定されています。

考え方は、

・数字の先頭が解析済みである。

・マスの中で塗られている該当箇所を特定する。

・その前の空白マスをマスクする。

このロジックで行けるはずです。

        // 解析パターンその13
        // 確実に塗れない空白部分をマスクする
        private void pattern13()
        {
            // Row
            pattern13RowFront();
            pattern13RowBack();
            // Col
            pattern13ColFront();
            pattern13ColBack();
        }

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

                // 先頭の数字が解析済みであるか?
                if (rowlist.AnalyzeDatas[0].IsAnalyzed() == false)
                {
                    row++;
                    rowlist.AnalyzeDatas.Reverse();
                    continue;
                }

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

                // 解析済みのマスを確認する
                foreach(var data in dataList)
                {
                    bool check = false;
                    int count = 0;
                    foreach(var p in data)
                    {
                        if (p.IsPainted())
                        {
                            count++;
                        }
                        else
                        {
                            break;
                        }
                    }
                    if(count == rowlist.AnalyzeDatas[0].Value)
                    {
                        foreach(var data2 in dataList)
                        {
                            if (data2.Equals(data) == false)
                            {
                                foreach(var p in data2)
                                {
                                    p.Mask();
                                }
                            }
                            else
                            {
                                break;
                            }
                        }
                        check = true;
                    }
                    if (check)
                    {
                        break;
                    }
                }

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

このパターンは前から確認するパターンと後ろから確認するパターン、それを行と列に対して行うようにしています。

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

だいぶ埋まってきましたね。

【北海道大戦】マップに市町村名を表示する

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

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

https://github.com/takishita2nd/HokkaidoWar

前回はただマップを表示するだけでしたが、

今回はマウスカーソルを移動させると、そのカーソル位置の市町村名を表示させるところまでやります。

そのためには、前回取り込んだJsonデータを扱いやすいように内部データに取り込む必要があります。

市町村は複数のマップで構成されているので、まずは、マップクラスを作成します。

    class Map
    {
        private int _x;
        private int _y;
        private asd.GeometryObject2D _geometryObj;

        private readonly int width = 24;
        private readonly int height = 24;
        private readonly int offsetx = 50;
        private readonly int offsety = 50;

        public Map(int x, int y, asd.Color color)
        {
            _x = x;
            _y = y;
            _geometryObj = new asd.GeometryObject2D();
            _geometryObj.Color = color;
            asd.Engine.AddObject2D(_geometryObj);
            var rect = new asd.RectangleShape();
            rect.DrawingArea = new asd.RectF(width * _x + offsetx, height * _y + offsety, width, height);
            _geometryObj.Shape = rect;
        }

        public void SetColor(asd.Color color)
        {
            _geometryObj.Color = color;
        }

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

これを使用する都市クラスを作成します。

    class City
    {
        private string _name = string.Empty;
        private List<Map> _maps = null;
        private asd.Color _color;

        public City(string name, Point[] points)
        {
            _name = name;
            _maps = new List<Map>();
            var r = Singleton.GetRandom();
            _color = new asd.Color((byte)r.Next(0, 255), (byte)r.Next(0, 255), (byte)r.Next(0, 255));

            foreach (var p in points)
            {
                Map m = new Map(p.x, p.y, _color);
                _maps.Add(m);
            }
        }

        public void OnMouse(asd.Vector2DF pos)
        {
            foreach(var m in _maps)
            {
                if(m.IsOnMouse(pos))
                {
                    var info = Singleton.GetInfomationWindow();
                    info.ShowText(pos, _name);
                }
            }
        }

        public bool IsOnMouse(asd.Vector2DF pos)
        {
            bool ret = false;
            foreach (var m in _maps)
            {
                if (m.IsOnMouse(pos))
                {
                    ret = true;
                }
            }
            return ret;
        }
    }

と、ここでひょっこり出てきた都市名を表示する窓クラスも作成します。

    class InfomationWindow
    {
        private asd.TextObject2D _valueText;

        public InfomationWindow()
        {
            _valueText = new asd.TextObject2D();
            _valueText.Font = Singleton.GetFont();
            asd.Engine.AddObject2D(_valueText);
        }

        public void ShowText(asd.Vector2DF pos, string text)
        {
            _valueText.Text = text;
            _valueText.Position = new asd.Vector2DF(pos.X, pos.Y);
        }
    }

これをどこでも取り出せるようにシングルトンにします。

    class Singleton
    {
        private static InfomationWindow _info = null;
        private static Random random = null;
        private static asd.Font _font = null;

        public static Random GetRandom()
        {
            if(random == null)
            {
                random = new Random();
            }
            return random;
        }

        public static asd.Font GetFont()
        {
            if(_font == null)
            {
                _font = asd.Engine.Graphics.CreateFont("FontText.aff");
            }
            return _font;
        }

        public static InfomationWindow GetInfomationWindow()
        {
            if (_info == null)
            {
                _info = new InfomationWindow();
            }
            return _info;
        }
    }

最終的にこれらを組み合わせると、

        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;

            cities = new List<City>();
            var r = new Random();
            foreach (var map in mapData.list)
            {
                City city = new City(map.name, map.point);
                cities.Add(city);
            }

            while (asd.Engine.DoEvents())
            {
                asd.Vector2DF pos = asd.Engine.Mouse.Position;
                if (isOnMaouseMap(pos))
                {
                    foreach (var city in cities)
                    {
                        city.OnMouse(pos);
                    }
                }
                else
                {
                    var info = Singleton.GetInfomationWindow();
                    info.ShowText(pos, string.Empty);
                }

                asd.Engine.Update();
            }
            asd.Engine.Terminate();
        }

        private bool isOnMaouseMap(asd.Vector2DF pos)
        {
            bool ret = false;
            foreach (var city in cities)
            {
                if (city.IsOnMouse(pos))
                {
                    ret = true;
                }
            }
            return ret;
        }

実行結果はこちら。

【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に対しても行います。

実行結果はこちら。

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

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

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

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

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

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