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

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

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

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

https://github.com/takishita2nd/Picross

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

実行結果はこちら

惜しい。

多分、次やらなくちゃ行けないのはここだろうな。

ここは2,2,5とすでに塗られているので、空いている空白はマスクで確定されます。

ちょっと解析パターン11と似ていますが、こんなコードを組んでみました。

        // 解析パターンその15
        // 数字と空いているマスを照合して塗る
        private void pattern15()
        {
            // Row
            pattern15Row();
            // Col
            pattern15Col();
        }

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

                // 有効な数字を取り出す
                List<AnalyzeData> aData = new List<AnalyzeData>();
                foreach(var data in rowlist.AnalyzeDatas)
                {
                    if (data.IsAnalyzed())
                    {
                        continue;
                    }
                    aData.Add(data);
                }

                // 対象となるマスを抽出する
                List<List<BitmapData>> bitmapLists = extractTargetBitmapListsCol(row);
                bitmapLists.Reverse();

                // 数字とマスを照合する
                if (bitmapLists.Count != aData.Count)
                {
                    row++;
                    continue;
                }

                for(int i = 0; i < aData.Count; i++)
                {
                    int count = 0;
                    // 塗られているマスを数える
                    foreach (var b in bitmapLists[i])
                    {
                        if (b.IsPainted())
                        {
                            count++;
                        }
                    }
                    // 塗られているマスと数字が一定している場合は空きマスをマスクする
                    if(aData[i].Value == count)
                    {
                        foreach(var b in bitmapLists[i])
                        {
                            if(b.IsValid() == false)
                            {
                                b.Mask();
                            }
                        }
                    }
                }
                row++;
            }
        }

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

                // 有効な数字を取り出す
                List<AnalyzeData> aData = new List<AnalyzeData>();
                foreach (var data in collist.AnalyzeDatas)
                {
                    if (data.IsAnalyzed())
                    {
                        continue;
                    }
                    aData.Add(data);
                }

                // 対象となるマスを抽出する
                List<List<BitmapData>> bitmapLists = extractTargetBitmapListsRow(col);
                bitmapLists.Reverse();

                // 数字とマスを照合する
                if (bitmapLists.Count != aData.Count)
                {
                    col++;
                    continue;
                }

                for (int i = 0; i < aData.Count; i++)
                {
                    int count = 0;
                    // 塗られているマスを数える
                    foreach (var b in bitmapLists[i])
                    {
                        if (b.IsPainted())
                        {
                            count++;
                        }
                    }
                    // 塗られているマスと数字が一定している場合は空きマスをマスクする
                    if (aData[i].Value == count)
                    {
                        foreach (var b in bitmapLists[i])
                        {
                            if (b.IsValid() == false)
                            {
                                b.Mask();
                            }
                        }
                    }
                }
                col++;
            }
        }

んー思った以上に進んでいないぞ。

少々時間がかかりそうです。

もう少し調べてみます。

【北海道大戦】各市町村の行動をランダムで回す

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

https://github.com/takishita2nd/HokkaidoWar

早速バトル処理を作成していきます。

しかし、ただループさせるだけだと途中経過が全く見えないので、

マウスをクリックすると次の行動を実行する、という形にしたいと思います。

そして、ターンの最初には、市町村の行動順をランダムに並べ替えます。

まずは、市町村を並び替える処理を作成。

    class Battle
    {
        private List<City> cityRandomReplace(List<City> beforeCities)
        {
            var r = Singleton.GetRandom();
            List<City> afterCities = new List<City>();
            int max = beforeCities.Count;
            for (int i = 0; i < max; i++)
            {
                int index = r.Next(0, beforeCities.Count - 1);
                afterCities.Add(beforeCities[index]);
                beforeCities.RemoveAt(index);
            }

            return afterCities;
        }

乱数でindexの値を振り、そのindexの都市を新しいListに追加して、古いリストから削除する、という処理を繰り返す事で並べ替えできます。

これを使用してマウスクリック処理を作成しいます。

    class HokkaidoWar
    {
        public void Run()
        {
            _battle = new Battle(cities);

            while (asd.Engine.DoEvents())
            {
                if (asd.Engine.Mouse.LeftButton.ButtonState == asd.ButtonState.Push)
                {
                    _battle.NextTurn();
                }
                asd.Engine.Update();
            }
            asd.Engine.Terminate();
    class Battle
    {
        private List<City> _cities = null;
        private int turn;
        private int cityCnt;
        public Battle(List<City> cities)
        {
            turn = 1;
            cityCnt = 0;
            _cities = new List<City>();
            foreach(var c in cities)
            {
                _cities.Add(c);
            }
            _cities = cityRandomReplace(_cities);
        }

        public void NextTurn()
        {
            cityCnt++;
            if(cityCnt >= _cities.Count)
            {
                _cities = cityRandomReplace(_cities);
                cityCnt = 0;
                turn++;
            }

            var info = Singleton.GetGameProcessInfomation();
            info.ShowText(_cities[cityCnt].GetPosition(), string.Format("{0} turn {1} / {2} {3}", turn, cityCnt, _cities.Count, _cities[cityCnt].Name));
        }

マウスをクリックする度に、NextTurn()が実行され、順番が回ってきた市町村の名前を表示します。

そして、一巡したらターンを更新し、市町村を並べ替えて処理を続けます。

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

【C#】【ピクロス】【ALTSEED】自動テスト機能を実装する。

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

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

https://github.com/takishita2nd/Picross

さて、いよいよ、自動テストを作っていきますか。

前回で問題データと解答データを用意したので、

問題データの読み込み→解析→回答データと照合→結果出力

こんな感じの流れでできると思います。

という訳で実装。

    class AutoTest
    {
        private const string QuestionFolder = "q";
        private const string AnswerFolder = "a";
        private const string ResultFolder = "r";
        private const string QuestionFile = "save";
        private const string AnswerFile = "output";
        private const string ResultFile = "result";

        public AutoTest()
        {

        }

        public void Run()
        {
            var files = Directory.EnumerateFiles(QuestionFolder, "*");
            foreach(var file in files)
            {
                string answerFile = file.Replace(QuestionFolder, AnswerFolder).Replace(QuestionFile, AnswerFile);
                string resultFile = file.Replace(QuestionFolder, ResultFolder).Replace(QuestionFile, ResultFile);
                if (File.Exists(resultFile))
                {
                    File.Delete(resultFile);
                }

                if (File.Exists(answerFile))
                {
                    List<List<NumberSquare>> rowNumberSquare = new List<List<NumberSquare>>();
                    List<List<NumberSquare>> colNumberSquare = new List<List<NumberSquare>>();
                    FileAccess.Load(file, ref rowNumberSquare, ref colNumberSquare);
                    PicrossAnalyze picross = new PicrossAnalyze(rowNumberSquare, colNumberSquare);
                    var ret = picross.Run();
                    string answer = string.Empty;
                    for(int r = 0; r < rowNumberSquare.Count; r++)
                    {
                        for(int c = 0; c < colNumberSquare.Count; c++)
                        {
                            if (ret[r, c].IsPainted())
                            {
                                answer += "1";
                            }
                            else
                            {
                                answer += "0";
                            }
                        }
                        answer += "\r\n";
                    }
                    string compare = FileAccess.AnswerLoad(answerFile);
                    string result;
                    if(compare.CompareTo(answer) == 0)
                    {
                        result = "OK";
                    }
                    else
                    {
                        result = answer;
                    }
                    using (var stream = new StreamWriter(resultFile, true))
                    {
                        stream.Write(result);
                    }
                }
            }
        }
    }
    class PicrossUI
    {
        public void Run()
        {

            // テストボタン
            var testButton = new Button(10, 170, "テスト");
            testButton.Show();
            asd.Engine.AddObject2D(testButton.getBackTexture());
            asd.Engine.AddObject2D(testButton.getTextObject());
            buttons.Add(testButton);
            testButton.SetAction(() =>
            {
                var test = new AutoTest();
                test.Run();
            });

Directory.EnumerateFiles()で問題ファイルの一覧を取得し、それをforeachで回します。

問題ファイルからデータを取り出し、ピクロス解析処理にかけます。

その結果を前回のような0と1の文字列に変換し、CompareTo()で回答結果との照合を行います。

結果、問題無ければOK、問題があれば解析結果をresultファイルに出力します。

これでテストも楽になる!

【C#】【ピクロス】【ALTSEED】解析結果をファイルに出力する

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

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

https://github.com/takishita2nd/Picross

今回からは、デバッグ作業をよりやりやすくするために、過去問を一括して解いて正しく解析できているかを確認する仕組みを作っていきます。

そのためには、解析結果をファイルに出力して、照合対象となるデータを作成する必要があります。

なので、以下の様なコードを作成しました。

    class FileAccess
    {
        private const string _outputfile = "output.dat";
        public static void Output(BitmapData[,] bitmapDatas, int row, int col)
        {
            if (File.Exists(_outputfile) == true)
            {
                File.Delete(_outputfile);
            }

            using (var stream = new StreamWriter(_outputfile, true))
            {
                for(int r = 0; r < row; r++)
                {
                    for(int c = 0; c < col; c++)
                    {
                        if(bitmapDatas[r, c].IsPainted())
                        {
                            stream.Write(1);
                        }
                        else
                        {
                            stream.Write(0);
                        }
                    }
                    stream.Write("\r\n");
                }
            }
        }

解析済みのデータbitmapDatasを受け取り、それをファイルに出力します。

色塗りの部分は1、マスク部分は0となるイメージです。

このデータが、

こんな感じになります。

問題データを

こんな感じで用意して、

解析結果データを、

こんな感じで作成しました。

数字で問題と解答が結びついているイメージです。

さて、これで必要な準備が出来ました。

毎回、ピクロスネタをやるとコーディングに膨大な時間を使ってしまうので、今回はサックリやって、続きは次回やります。

【北海道大戦】マップと都市をリンクする

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

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

https://github.com/takishita2nd/HokkaidoWar

前回はマップ同士のリンクを作成しました。

ここ、もうちょっと改良します。

すぐ終わります。

マップのプロパティにUp、Down、Left、Rightを追加してそこから隣接するマップを取得させましょう。

    class Map
    {
        public Map Up { 
            get {
                var field = Singleton.GetFieldMap();
                return field.GetMap(_x, _y - 1);
            }
        }

        public Map Down
        {
            get
            {
                var field = Singleton.GetFieldMap();
                return field.GetMap(_x, _y + 1);
            }
        }

        public Map Left
        {
            get
            {
                var field = Singleton.GetFieldMap();
                return field.GetMap(_x - 1, _y);
            }
        }

        public Map Right
        {
            get
            {
                var field = Singleton.GetFieldMap();
                return field.GetMap(_x + 1, _y);
            }
        }
    class FieldMap
    {
        public Map GetMap(int x, int y)
        {
            if(x < 0 || x >= MaxX || y < 0 || y >= MaxY)
            {
                return null;
            }
            else
            {
                return _map[x, y];
            }
        }

これでだいぶ扱いやすくなったはず。

動作結果は前回と同じ。

で、ここからが今回の本題。

マップと都市のリンクを作成します。

マップから所属する都市を取得できるようにします。

まぁ、やっていることは簡単ですが。

    class Map
    {
        public void SetCity(City city)
        {
            _city = city;
        }

        public City GetCity()
        {
            return _city;
        }
    class City
    {
        public City(string name, Point[] points, int population)
        {
            _name = name;
            _population = population;
            _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));

            var fieldMap = Singleton.GetFieldMap();

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

マップに都市を設定する所を追加、マップの生成と一緒に自分自身のオブジェクトを設定する、というようにしました。

で、これを検証するために、選択した都市と隣接する都市の色を変えようと思います。

        private List<City> GetLinkedCities()
        {
            List<City> cities = new List<City>();
            foreach (var m in _maps)
            {
                if (m.Up != null)
                {
                    var c = m.Up.GetCity();
                    if (cities.Contains(c) == false && c != this)
                    {
                        cities.Add(c);
                    }
                }
                if (m.Down != null)
                {
                    var c = m.Down.GetCity();
                    if (cities.Contains(c) == false && c != this)
                    {
                        cities.Add(c);
                    }
                }
                if (m.Left != null)
                {
                    var c = m.Left.GetCity();
                    if (cities.Contains(c) == false && c != this)
                    {
                        cities.Add(c);
                    }
                }
                if (m.Right != null)
                {
                    var c = m.Right.GetCity();
                    if (cities.Contains(c) == false && c != this)
                    {
                        cities.Add(c);
                    }
                }
            }
            return cities;
        }
        public void OnMouse(asd.Vector2DF pos)
        {
            foreach (var m in _maps)
            {
                if(m.IsOnMouse(pos))
                {
                    var info = Singleton.GetInfomationWindow();
                    info.ShowText(pos, _name + "\r\n" + _population.ToString());
                    // test
                    var cities = GetLinkedCities();
                    foreach (var c in cities)
                    {
                        c.linkedCity();
                    }
                }
            }
        }
        //test
        private void linkedCity()
        {
            foreach(var m in _maps)
            {
                m.linkedMap();
            }
        }
    class HokkaidoWar
    {
        public void Run()
        {
            while (asd.Engine.DoEvents())
            {
                FieldMap fieldMap = Singleton.GetFieldMap();
                fieldMap.unlinkMap();

List.Contains(Obj)を使用すると、Listの中にObjと同じ物があるかを確認できます。

自分の都市の隣接する都市なので、自分自身は含めていません。

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

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

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

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

https://github.com/takishita2nd/HokkaidoWar

さて、現状マップデータの管理は、都市オブジェクトの中に所属するマップが格納されていると言う状態で、マップ同士の横のつながりがありません。

このままでは「隣接するマップ」を取り出すことが出来ないので、整理して管理したいと思います。

マップデータは横44マス、縦35マスで構成されているので、二次元配列にするのが最適でしょう。

なので、このデータを管理するクラスを作成し、シングルトンで使用します。

    class FieldMap
    {
        public int MaxX { get { return 44; } }
        public int MaxY { get { return 35; } }

        private Map[,] _map;
        public FieldMap()
        {
            _map = new Map[44, 35];
        }

        public Map GetMap(int x, int y)
        {
            return _map[x, y];
        }

        public void SetMap(Map map)
        {
            _map[map.X, map.Y] = map;
        }

    class Singleton
    {
        private static FieldMap _map = null;
        public static FieldMap GetFieldMap()
        {
            if (_map == null)
            {
                _map = new FieldMap();
            }
            return _map;
        }

で、都市オブジェクトからマップオブジェクトを作成する際に、このクラスにマップオブジェクトも保持させます。

        public City(string name, Point[] points, int population)
        {
            _name = name;
            _population = population;
            _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));

            var fieldMap = Singleton.GetFieldMap();

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

たぶん、これだけでOKのはずなので、うまく管理出来ているか、テストコードで確認したいと思います。

マウスカーソルのあるマップの隣にあるマップの色を変化させます。

    class City
    {
        public void OnMouse(asd.Vector2DF pos)
        {
            var fieldMap = Singleton.GetFieldMap();
            foreach (var m in _maps)
            {
                if(m.IsOnMouse(pos))
                {
                    var info = Singleton.GetInfomationWindow();
                    info.ShowText(pos, _name + "\r\n" + _population.ToString());
                    // test
                    fieldMap.onMouse(m);
                }
            }
        }
    class FieldMap
    {
        // Test
        public void onMouse(Map map)
        {
            for(int x = 0; x < MaxX; x++)
            {
                for(int y = 0; y < MaxY; y++)
                {
                    if(_map[x,y] != null)
                    {
                        _map[x, y].unlinkedMap();
                    }
                }
            }
            if(map.X > 0)
            {
                if (_map[map.X + 1, map.Y] != null)
                {
                    _map[map.X + 1, map.Y].linkedMap();
                }
            }
            if (map.X < MaxX)
            {
                if (_map[map.X - 1, map.Y] != null)
                {
                    _map[map.X - 1, map.Y].linkedMap();
                }
            }
            if (map.Y > 0)
            {
                if (_map[map.X, map.Y - 1] != null)
                {
                    _map[map.X, map.Y - 1].linkedMap();
                }
            }
            if (map.Y < MaxY)
            {
                if (_map[map.X, map.Y + 1] != null)
                {
                    _map[map.X, map.Y + 1].linkedMap();
                }
            }
        }
    class Map
    {
        // Test
        public void linkedMap()
        {
            var changeColor = new asd.Color(200, 200, 200);
           _geometryObj.Color = changeColor;
        }

        public void unlinkedMap()
        {
            _geometryObj.Color = _color;
        }

うまくいけていると思います。

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

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

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

https://github.com/takishita2nd/Picross

次はここを処理します。

ここは縦の数字がすでに3が塗られているので、上の空いているマスに1マス、下の空いているマスに2マスを塗ることができます。

なので、赤く囲んだ部分は塗れると言うことですね。

これを実装します。

考え方としては、まだ確定していないマスと数字を抽出し、順序関係が一致かつ、数字とマスが一致した場合、そこを塗る、という感じでいきますか。

        // 解析パターンその14
        // 数字と空いているマスを照合して塗る
        private void pattern14()
        {
            // Row
            pattern14Row();
            // Col
            pattern14Col();
        }

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

                // 有効な数字を取り出す
                List<AnalyzeData> aData = new List<AnalyzeData>();
                foreach(var data in rowlist.AnalyzeDatas)
                {
                    if (data.IsAnalyzed())
                    {
                        continue;
                    }
                    aData.Add(data);
                }

                // 対象となるマスを抽出する
                List<List<BitmapData>> bitmapLists = extractTargetBitmapListsCol(row);
                bitmapLists.Reverse();

                // 数字とマスを照合する
                if (bitmapLists.Count != aData.Count)
                {
                    row++;
                    continue;
                }

                AnalyzeData maxData = null;
                int remi = 0;
                for(int i = 0; i < aData.Count; i++)
                {
                    if (maxData == null)
                    {
                        maxData = aData[i];
                    }
                    else
                    {
                        if(maxData.Value < aData[i].Value)
                        {
                            remi = i;
                        }
                    }
                }
                if(maxData != null)
                {
                    if (bitmapLists[remi].Count == maxData.Value)
                    {
                        foreach (var b in bitmapLists[remi])
                        {
                            b.Paint();
                        }
                        maxData.Analyzed();
                    }
                }
                row++;
            }
        }

extractTargetBitmapListsCol()の処理も少し修正しています。

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

ここまで複雑なロジックを組み合わせていくと、過去の問題が解けなくなっているとか十分あり得るので、その確認が大変です。

なんかもっといい確認方法を考えないといけないかもしれない。

何か方法を考えます。

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

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

最新ソースはこちら(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;
        }

実行結果はこちら。