2016-08-03 4 views
0

正直言って、私はおそらくそこに悪いタイトルがあるので、説明することができます。 (タイトルの提案は大歓迎!)C# - カスタムクラスのリスト内の座標に基づいてダイヤモンド形状の半径を選択してください

まず最初に、私は「リスト」を適切にTileListという名前で持っています。 Tileはいくつかの変数を含むクラスですが、重要なものはpublic int xCoorとpublic int yCoorです。

TileListは自動的に外部関数によって埋められます。この場合、Tileクラスの100個のインスタンスで満たされています。それぞれxCoorとyCoorのxCoorsと0〜9のyCoors、0〜9のyCoors、基本的に10x10グリッドをシミュレートします。

外部関数で埋められているため、必ずしも10x10であるとは限りません.5x15または20x20などとすることもできます。

私は1つは、これまで完璧に動作することをFindTile-という名前の特定のタイルを、グラブ機能を持っている...

しかし、今、私は出発点に基づいて、グリッドからダイヤモンド形状を選択1を必要とし、半径。そして、私自身の試み、FindDiamond関数..は非常に乱雑であり、永久にロードされます。実際にはうまくいきません。

これは私が何をしたいのか、基本的である:Grid example

コードがダウンして以下の通りです:率直

public class Tile 
{ 
    public int xCoor; 
    public int yCoor; 

    //more variables 
} 

public class TileFinder 
{ 
    public List<Tile> TileList = new List<Tile>(); 

    //Give back tiles when generated 
    public void SaveGeneratedTiles(List<Tile> Save) 
    { 
     TileList = Save; 
    } 

    public Tile FindTile(int tileX, int tileY) 
    { 
     for (int i = 1; i < TileList.Count; i++) 
     { 
      if (TileList[i].xCoor == tileX && TileList[i].yCoor == tileY) 
      { 
       return TileList[i]; 
      } 
     } 
     return null; 
    } 

    public List<Tile> FindDiamond(int tileX, int tileY, int radius) 
    { 
     List<Tile> ReturnList = new List<Tile>(); 

     for (int r = 0; r <= radius; r++) 
     { 
      int curx = tileX + r; 
      int cury = tileY; 

      if (curx == tileX) { FindTile(curx, cury); } 
      else 
      { 
       while (curx != -r) 
       { 
        curx--; 
        cury--; 
        ReturnList.Add(FindTile(curx, cury)); 
       } 
       while (cury != -r) 
       { 
        curx++; 
        cury--; 
        ReturnList.Add(FindTile(curx, cury)); 
       } 
       while (curx != r) 
       { 
        curx++; 
        cury++; 
        ReturnList.Add(FindTile(curx, cury)); 
       } 
       while (curx != -r) 
       { 
        curx--; 
        cury++; 
        ReturnList.Add(FindTile(curx, cury)); 
       } 
      } 
     } 
     return ReturnList; 
    } 
} 

、私は終わりを行い、この作品を作るためのより良い方法、を探しています私のコードの他の部分は、実際にはこれも最良の方法ではないかもしれませんが、これを介して自分のやり方をやっています。 :)

TL;一番など、私はアドバンスウォーズのようなものをエミュレートしようとしている、と私は戦争のビジョンの霧のために範囲を選択するために、ダイヤモンド形状を必要とする、間接的な攻撃DR

答えて

0

まずと、グリッドを表現するために、2次元配列はリストよりはるかに優れた選択肢になります。リストも同様に機能しますが、冗長です。 グリッドが10x10のタイルのみを含み、その順序を保証できる場合、xおよびy座標で特定のタイルを見つけることはo(1)操作でなければなりません。 。その機能では、なぜ1から始まり、0ではないのですか?

ダイヤモンドパターンを作成するには、非常に簡単です。

開始点の行(Y)から開始します。そこからXを進んで、Xradiusのステップを進んで、radiusステップを進んでください。 radius行の開始点の下と上の行については、同じことを行いますが、それぞれの行に対して、radiusを1減らしてください。

+0

は、外部関数によって自動的に満たされます。今私はそれを質問に追加したはずなので、私はそれを編集したはずです。0(1)操作対0(n)線形検索の意味は何ですか? ..また、インデックス1でその間違いを抱えてうれしく思いました。それは本当に0だったはずです。ありがとう。とにかく、私はこれを試してみる、これは実際には良いアイデアのように聞こえる。私もダイヤモンドの内側が欲しいということを忘れないでください。しかし、私はもうちょっと小さな半径でこれをループすることができます。 – Speedy

+0

これは受け入れられた答えだと思っています.2D配列は確かに良い選択であり、私はすでに2次元配列に変更して以来、私のコードを半減しました。 ^^;ありがとう、ロテム – Speedy

0

これはなんですか?それをテストしていない。

public List<Tile> FindDiamond(int tileX, int tileY, int radius) 
{ 
    List<Tile> ReturnList = new List<Tile>(); 

    for (int x = 0; x < radius; x++) 
    { 
     for (int y = 0; y < radius-x; y++) 
     { 
      ReturnList.Add(FindTile(tileX + x, tileY + y)); 
      ReturnList.Add(FindTile(tileX + x, tileY - y)); 
      ReturnList.Add(FindTile(tileX - x, tileY + y)); 
      ReturnList.Add(FindTile(tileX - x, tileY - y)); 
     } 
    } 
    return ReturnList; 
} 
+0

私は確信していない、ちょっと同じタイルを数回追加するように見える、それは私が避けたいものです..私はそれをテストします。 :) – Speedy

+0

Rotemが提案するようにグリッド(Tile [x] [y])に修正する必要があります – Jonny

+0

また、リストを保持したい場合は、そのアイテムがまだリストにない場合にのみリストに追加する方法がありますリスト – Jonny

0

「ダイヤモンド」は、Manhattan Distanceを使用して測定された距離を持つ円として表すことができます。

マンハッタン距離は、問題の点のX座標とY座標の絶対差の合計によって測定されます。

static int ManhattanDistance(int x1, int y1, int x2, int y2) { 
    return Math.Abs(x1 - x2) + Math.Abs(y1 - y2) 
} 

これは、(LINQを使用している場合)、単一の行にあなたのFindDiamond方法を簡素化します。

List<Tile> FindDiamond(int centerX, int centerY, int radius) { 
    return TileList.Where(tile => ManhattanDistance(tile.xCoor, tile.yCoor, tileX, tileY) <= radius).ToList(); 
} 

FindTileもLINQを使用してワンライナーに簡素化することができます。

Tile FindTile(int tileX, int tileY) { 
    return TileList.FirstOrDefault(tile => tile.xCoor == tileX && tile.yCoor = tileY); 
} 

しかし、あなたはすべてFindDiamondTileListを通じて、何らかの理由だけでループをLINQを使用して返すことができない、場合Tile内の節を満たす。Where


@Rotemのように、デザインを効率化することをお勧めします。コードをより効率的かつ迅速に作成できます。 FindTileは、各フレームが何百回も呼び出されると想像できる方法なので、コードをできるだけ効率的にするのが最善です。可変幅と高さを指定しても、@Rotemで指定されたメソッドが機能します。

は、私はまた、あなたが簡単に保存し、代わりにどこにでもblahXblahYを使用してのblah.Xblah.Yを使用するための独自のPoint構造を作成することをお勧めします。 ManhattanDistanceのような有用なヘルパーを含むこともできます。

サンプルPoint構造:グリッドSorry-

struct Point { 
    public int X, Y; 

    public int ManhattanDistance(Point other) { 
     return Point.ManhattanDistance(this, other); 
    } 

    public static int ManhattanDistance(Point a, Point b) { 
     return Math.Abs(a.X- b.X) + Math.Abs(a.Y - b.Y) 
    } 
} 
+0

私がLINQを使用していない唯一の理由は、それがどのように動作するか(またはそれが何であるか、tbh)はわからないからです。それが私のコードを改善するのに役立つならば、私は喜んでそれを拾うだろう..質問しかし、これはまた、ダイヤモンドの内部を取得できますか?最も外側のタイルだけでなく、ダイヤモンド内のすべてのタイルが必要です。 :) – Speedy

+0

@スピードリ半径内のすべてのタイル*と*を取得します。 '<= radius'を' EvilTak

+0

まあ、私は間違いなくLINQを考慮する必要があります..援助ありがとう。 :) – Speedy

関連する問題