C# AStar problems, won't do it correctly - c#

I am currently working on A* pathfinding, but I am having some problems.
It does the wrong path before taking the best path to the end.
What am I doing wrong?
Source code: http://basic.apayostudios.com/AStar.zip
Online:
Game.cs http://pastie.org/1656955
Node.cs http://pastie.org/1656956
Enums:
public enum NodeType
{
None,
Solid,
Start,
End
}
Thanks!

Here's my A-star path finder, it works and you're free to use it for learning and comparing your solution against it, rip me off if you like. But there are dependencies that are missing from this code and I'm using fixed-point arithmetic. This won't build without some changes. This code is relatively high level and should be easy enough to reverse engineer.
public class AgentPathfinder
{
class SolutionComparer : IComparer<Solution>
{
public int Compare(Solution x, Solution y)
{
return x.Cost.CompareTo(y.Cost);
}
}
class Solution
{
public List<FixedVector> Path { get; private set; }
public FixedVector LastPosition { get { return Path[Path.Count - 1]; } }
public Fixed32 Heuristic { get; set; }
public Fixed32 Cost { get; set; }
public Solution(FixedVector position, Fixed32 heuristic)
{
Path = new List<FixedVector>(2) { position };
Heuristic = heuristic;
Cost = Path.Count + heuristic;
}
public Solution(FixedVector position
, Fixed32 heuristic
, List<FixedVector> path)
{
Path = new List<FixedVector>(path) { position };
Heuristic = heuristic;
Cost = Path.Count + heuristic;
}
}
// TODO: replace with pathable terrain data
public Map Map { get; set; }
public FixedVector Position { get; set; }
public FixedVector Destination { get; set; }
public List<FixedVector> Path { get; set; }
public void Compute()
{
var visited = new bool[(int)Map.Size.Width, (int)Map.Size.Height];
var pq = new PriorityQueue<Solution>(new SolutionComparer());
var bestFit = new Solution(new FixedVector((int)(Position.X + 0.5)
, (int)(Position.Y + 0.5))
, (Destination - Position).Length
);
pq.Enqueue(bestFit);
while (pq.Count > 0)
{
var path = pq.Dequeue(); // optimal, thus far
if (path.Heuristic < bestFit.Heuristic) // best approximation?
{
// if we starve all other paths we
// fallback to this, which should be the best
// approximation for reaching the goal
bestFit = path;
}
for (int i = 0; i < FixedVector.Adjacent8.Length; i++)
{
var u = path.LastPosition + FixedVector.Adjacent8[i];
if (Map.Size.Contains(u))
{
if (Map.IsPathable(u))
{
if (!visited[(int)u.X, (int)u.Y])
{
// heuristic (straight-line distance to the goal)
var h = (Destination - u).Length;
var solution = new Solution(u, h, path.Path);
if (h < 1)
{
Path = solution.Path;
return; // OK, done
}
else
{
// keep looking
pq.Enqueue(solution);
}
visited[(int)u.X, (int)u.Y] = true;
}
}
}
}
}
Path = bestFit.Path;
}
}

Related

List sorting troubles

I have a list of programmers:
programmers.Add(new Programmer("Jake", 1.9, 2000));
programmers.Add(new Programmer("Richard", 1.0, 1300));
and I need to create a new list of sorted programmers by this
value => 2000 / 1.9.(upward)
I can't figure out how to divide int by double and sort the programmers by this result. Can you please help me how to do so?
So far I've tried:
var ProgrammersSorted = programmers.OrderBy((x,y) => x.DailyWage / y.Speed).ToList();
Programmer class:
public class Programmer
{
public string Name { get; private set; }
public double Speed { get; private set; }
public int DailyWage { get; private set; }
public Project Project { get; private set; }
public string ProjectName
{
get
{
return Project?.Name ?? "No project assigned";
}
}
public Programmer(string name, double speed, int dailyWage)
{
Name = name;
Speed = speed;
DailyWage = dailyWage;
}
}
You are very close. Try this out:
var programmersSorted = programmers.OrderBy(x => x.DailyWage / x.Speed).ToList();
Please try below code, I think this will solve your issue.
var programmers = new List<Programmer>
{
new Programmer("SS",12.3,2345),
new Programmer("ADE",1.21,22345),
new Programmer("AR",12.2,23445),
new Programmer("NK",12.5,23455)
};
var progrmrs = programmers.OrderBy(t => t.DailyWage / t.Speed).ToList();
Console.WriteLine("Name\t Speed\t DailyWage");
foreach (var prgrm in progrmrs)
{
Console.WriteLine("{0}\t {1}\t {2}", prgrm.Name, prgrm.Speed, prgrm.DailyWage);
}

Clusters of Lat, Long that are near to each other

I have a scenario where N number of items were delivered at N locations (lat, long). I want to find group of items which are delivered near to each other(100 meters). Say for example (Item1, Item9,...Item499) were delivered such that they had distance less than 100 between them. Item9 can be more than 100 meters away from Item499 but it will be in that group if it has less than 100 meters distance from any one of the item in the group.
Find all such groups.
I want someone to point out the right algorithm. I'll then work on that. Preferable Language is C#
Below is the algorithm to solve this problem which I found here
public class ClusterCreator
{
public Dictionary<int, SimpleCluster> GetClusters(List<SimpleCluster> clusterList, int maxDistance)
{
//LOAD DATA
//var clusterList = new List<SimpleCluster>(); // LoadSimpleClusterList();
//var latitudeSensitivity = 3;
//var longitutdeSensitivity = 3;
//CLUSTER THE DATA
return ClusterTheData(clusterList, maxDistance);
}
public Dictionary<int, SimpleCluster> ClusterTheData(List<SimpleCluster> clusterList, int maxDistance)
{
//CLUSTER DICTIONARY
var clusterDictionary = new Dictionary<int, SimpleCluster>();
//Add the first node to the cluster list
if (clusterList.Count > 0)
{
clusterDictionary.Add(clusterList[0].ID, clusterList[0]);
}
//ALGORITHM
for (int i = 1; i < clusterList.Count; i++)
{
SimpleCluster combinedCluster = null;
SimpleCluster oldCluster = null;
foreach (var clusterDict in clusterDictionary)
{
//Check if the current item belongs to any of the existing clusters
if (CheckIfInCluster(clusterDict.Value, clusterList[i], maxDistance))
{
//If it belongs to the cluster then combine them and copy the cluster to oldCluster variable;
combinedCluster = CombineClusters(clusterDict.Value, clusterList[i]);
oldCluster = new SimpleCluster(clusterDict.Value);
}
}
//This check means that no suitable clusters were found to combine, so the current item in the list becomes a new cluster.
if (combinedCluster == null)
{
//Adding new cluster to the cluster dictionary
clusterDictionary.Add(clusterList[i].ID, clusterList[i]);
}
else
{
//We have created a combined cluster. Now it is time to remove the old cluster from the dictionary and instead of it add a new cluster.
clusterDictionary.Remove(oldCluster.ID);
clusterDictionary.Add(combinedCluster.ID, combinedCluster);
}
}
return clusterDictionary;
}
public static SimpleCluster CombineClusters(SimpleCluster home, SimpleCluster imposter)
{
//Deep copy of the home object
var combinedCluster = new SimpleCluster(home);
combinedCluster.LAT_LON_LIST.AddRange(imposter.LAT_LON_LIST);
combinedCluster.NAMES.AddRange(imposter.NAMES);
//Combine the data of both clusters
//combinedCluster.LAT_LON_LIST.AddRange(imposter.LAT_LON_LIST);
//combinedCluster.NAMES.AddRange(imposter.NAMES);
//Recalibrate the new center
combinedCluster.LAT_LON_CENTER = new LAT_LONG
{
LATITUDE = ((home.LAT_LON_CENTER.LATITUDE + imposter.LAT_LON_CENTER.LATITUDE) / 2.0),
LONGITUDE = ((home.LAT_LON_CENTER.LONGITUDE + imposter.LAT_LON_CENTER.LONGITUDE) / 2.0)
};
return combinedCluster;
}
public bool CheckIfInCluster(SimpleCluster home, SimpleCluster imposter, int maxDistance)
{
foreach (var item in home.LAT_LON_LIST)
{
var sCoord = new GeoCoordinate(item.LATITUDE, item.LONGITUDE);
var eCoord = new GeoCoordinate(imposter.LAT_LON_CENTER.LATITUDE, imposter.LAT_LON_CENTER.LONGITUDE);
var distance = sCoord.GetDistanceTo(eCoord);
if (distance <= maxDistance)
return true;
}
return false;
//if ((home.LAT_LON_CENTER.LATITUDE + latitudeSensitivity) > imposter.LAT_LON_CENTER.LATITUDE
// && (home.LAT_LON_CENTER.LATITUDE - latitudeSensitivity) < imposter.LAT_LON_CENTER.LATITUDE
// && (home.LAT_LON_CENTER.LONGITUDE + longitutdeSensitivity) > imposter.LAT_LON_CENTER.LONGITUDE
// && (home.LAT_LON_CENTER.LONGITUDE - longitutdeSensitivity) < imposter.LAT_LON_CENTER.LONGITUDE
// )
//{
// return true;
//}
//return false;
}
}
public class SimpleCluster
{
#region Constructors
public SimpleCluster(int id, string name, double latitude, double longitude)
{
ID = id;
LAT_LON_CENTER = new LAT_LONG
{
LATITUDE = latitude,
LONGITUDE = longitude
};
NAMES = new List<string>();
NAMES.Add(name);
LAT_LON_LIST = new List<LAT_LONG>();
LAT_LON_LIST.Add(LAT_LON_CENTER);
}
public SimpleCluster(SimpleCluster old)
{
ID = old.ID;
LAT_LON_CENTER = new LAT_LONG
{
LATITUDE = old.LAT_LON_CENTER.LATITUDE,
LONGITUDE = old.LAT_LON_CENTER.LONGITUDE
};
LAT_LON_LIST = new List<LAT_LONG>(old.LAT_LON_LIST);
NAMES = new List<string>(old.NAMES);
}
#endregion
public int ID { get; set; }
public List<string> NAMES { get; set; }
public LAT_LONG LAT_LON_CENTER { get; set; }
public List<LAT_LONG> LAT_LON_LIST { get; set; }
}
public class LAT_LONG
{
public double LATITUDE { get; set; }
public double LONGITUDE { get; set; }
}

Object creation & equivalent attribute signatures. Does this satisfy the requirements?

I'm trying to upgrade my general class design skills in C#, and want you guys to reveal code-smells I might have. (hope general discussions are allowed at Stackoverflow.com)
Regarding to This Tutorial, I wrapped this up to C# and tried to chain constructors, avoid same attribute signatures and solve it the right way, without duplicating code.
The problem in this tutorial: The Running Back and Wide Receiver would use the same attribute signatures. Multiple constructions for each player role would cause errors. Instead you might use object creation.
Below, how I solved it.
Football Player class:
public class FootballPlayer
{
public double PasserRating { get; set; } // Specific to QBs
public int RushingYards { get; set; } // Specific to RBs & QBs
public int ReceivingYards { get; set; } // Specific to RBs & WRs
public int TotalTackles { get; set; } // Specific to DEF
public int Interceptions { get; set; } // Specific to DEF
public int FieldGoals { get; set; } // Specific to Kickers
public double AvgPunt { get; set; } // Specific to Punters
public double AvgKickoffReturn { get; set; }// Specific to Special Teams
public double AvgPuntreturn { get; set; } // Specific to Special Teams
private FootballPlayer() : this(0.0, 0, 0, 0, 0, 0, 0.0, 0.0, 0.0) { }
private FootballPlayer(double passerRating, int rushingYards, int receivingYards, int totalTackles, int interceptions, int fieldGoals, double avgPunt, double avgKickoffReturn, double avgPuntreturn)
{
PasserRating = passerRating;
RushingYards = rushingYards;
ReceivingYards = receivingYards;
TotalTackles = totalTackles;
Interceptions = interceptions;
FieldGoals = fieldGoals;
AvgPunt = avgPunt;
AvgKickoffReturn = avgKickoffReturn;
AvgPuntreturn = avgPuntreturn;
}
public static FootballPlayer CreateQb(double passerRating, int rushingYards)
{
return new FootballPlayer
{
PasserRating = passerRating,
RushingYards = rushingYards
};
}
public static FootballPlayer CreateRb(int rushingYards)
{
return new FootballPlayer
{
RushingYards = rushingYards
};
}
public static FootballPlayer CreateWr(int receivingYards)
{
return new FootballPlayer
{
ReceivingYards = receivingYards
};
}
}
Program:
class Program
{
static void Main()
{
var aaronRodgers = FootballPlayer.CreateQb(132.0, 259);
var drewBrees = FootballPlayer.CreateQb(129.6, 244);
Console.WriteLine("Aaron Rodgers passer Rating: {0}", aaronRodgers.PasserRating);
// OUTPUT: Aaron Rodgers passer Rating: 132
Console.WriteLine("Drew Brees passer Rating: {0}", drewBrees.PasserRating);
// OUTPUT: Drew Brees passer Rating: 129.6
Console.ReadLine();
}
}
Would you guys say that's the way to go?
Or what should I take into account?

Give an Array a Value

I am trying to make a game where an image appears, and if it is not clicked the image should disappear. I need help giving my array a value of three, then subtract it in another method.
Code:
NameCount = -1;
NameCount++;
Grid.SetColumn(mole, ranCol);
Grid.SetRow(mole, ranRow);
grid_Main.Children.Add(mole);
for (int i = 0; i < NumofImages; i++)
{
//Where I must give a value to the array of the array to 3 for every image that appears.
}
//Where I am trying to make the image disappear after 3 seconds.
private void deleteMole()
{
NumofImages = TUtils.GetIniInt(Moleini, "NumPictures", "pictures", 8);
NumberofImages = Convert.ToInt32(NumofImages);
for (int j = 0; j < NumofImages; j++)
{
CounterArray[j]--;
if (CounterArray[j] == 0)
{
//Not Sure How to delete image
Thanks for the help!
You could keep track of the images in another array.
After you add the image to the view you should also add it to the array:
images[j] = mole;
Then later:
if (CounterArray[j] == 0)
{
grid_Main.Children.Remove(images[j]);
}
But using static arrays and separating data is not a good idea.
If you can you should better aggregate all the metadata and the image together in the same structure:
class Mole
{
public int Counter { get; set; }
public Control Image { get; set; }
}
and manage them in a single List<Mole>; adding and removing them will be simpler.
Here is some code that illustrates the idea (won't compile):
class Mole
{
public int X { get; set; }
public int Y { get; set; }
public int Counter { get; set; }
public Control Image { get; set; }
public bool IsNew { get; set; }
}
class Test
{
IList<Mole> moles = new List<Mole>();
private static void AddSomeMoles()
{
moles.Add(new Mole{ X = rand.Next(100), Y = rand.Next(100), Counter = 3, Image = new PictureBox(), IsNew = true });
}
private static void DisplayMoles()
{
foreach (Mole mole in moles)
{
if (mole.IsNew)
{
grid_Main.Children.Add(mole.Image);
mole.IsNew = false;
}
}
}
private static void CleanupMoles()
{
foreach (Mole mole in moles)
{
mole.Counter -= 1;
if (mole.Counter <= 0)
{
grid_Main.Children.Remove(mole.Image);
moles.Remove(mole);
}
}
}
static void Main()
{
while (true)
{
AddSomeMoles();
DisplayMoles();
Thread.Sleep(1000);
CleanupMoles();
}
}
}
If you want to give every element in a List a certain value, use a foreach loop. In this case, it would look like:
foreach(int currentElement in CounterArray)
{
currentElement = 3;
}
This will loop through each element of the List and set it to 3.
EDIT: If you're using an array, which you are, you would do the following:
for (int i = 0; i < CounterArray.Length; i++)
{
CounterArray[i] = 3;
}

Compare properties of two objects fast c#

I have two objects of same type with different values:
public class Itemi
{
public Itemi()
{
}
public int Prop1Min { get; set; }
public int Prop1Max { get; set; }
public int Prop2Min { get; set; }
public int Prop2Max { get; set; }
public int Prop3Min { get; set; }
public int Prop3Max { get; set; }
...................................
public int Prop25Min { get; set; }
public int Prop25Max { get; set; }
}
Now I instantiate two objects of this type and add some values to their properties.
Itemi myItem1 = new Itemi();
myItem1.Prop1Min = 1;
myItem1.Prop1Max = 4;
myItem1.Prop2Min = 2;
myItem1.Prop2Max = 4;
myItem1.Prop3Min = -1;
myItem1.Prop3Max = 5;
.............................
myItem1.Prop25Min = 1;
myItem1.Prop25Max = 5;
Itemi myItem2 = new Itemi();
myItem2.Prop1Min = 1;
myItem2.Prop1Max = 5;
myItem2.Prop2Min = -10;
myItem2.Prop2Max = 3;
myItem2.Prop3Min = 0;
myItem2.Prop3Max = 2;
................................
myItem2.Prop25Min = 3;
myItem2.Prop25Max = 6;
What is the best and fastest way to do this comparison:
take each properties from myItem1 and check if values from Prop1-25 Min and Max are within the range values of myItem2 Prop1-25 Min and Max
Example:
myItem1.Prop1Min = 1
myItem1.Prop1Max = 4
myItem2.Prop1Min = 1
myItem2.Prop1Max = 5
this is True because mtItem1 Prop1 min and max are within the range of myItem2 min and max.
the condition should be AND in between all properties so in the end after we check all 25 properties if all of them are within the range of the second object we return true.
Is there a fast way to do this using Linq or other algorithm except the traditional if-else?
I would refactor the properties to be more along the lines of:
public class Item
{
public List<Range> Ranges { get; set; }
}
public class Range
{
public int Min { get; set; }
public int Max { get; set; }
}
Then your comparison method could be:
if (myItem1.Ranges.Count != myItem2.Ranges.Count)
{
return false;
}
for (int i = 0; i < myItem1.Ranges.Count; i++)
{
if (myItem1.Ranges[i].Min < myItem2.Ranges[i].Min ||
myItem1.Ranges[i].Max > myItem2.Ranges[i].Max)
{
return false;
}
}
return true;
Otherwise you will have to use Reflection, which is anything but fast.
Linq is using standart statements like if...then, for each and other, there is no magic :)
If the final goal only to compare, without needing to say, which properties are not in the range, then you not need to check them all, on the first unequals you can end checking.
Because you have so much properties, you must think about saving it in Dictionary, or List, for example. Or to use dynamic properties (ITypedList), if it will use for binding.
You really should do something like Ginosaji proposed.
But if you want to go with your current data model, here is how I would solve it. Happy typing. :)
public static bool RangeIsContained(int outerMin, int outerMax, int innerMin, int innerMax)
{
return (outerMin <= innerMin && outerMax >= innerMax);
}
public bool IsContained(Itemi outer, Itemi inner)
{
return RangeIsContained(outer.Prop1Min, outer.Prop1Max, inner.Prop1Min, inner.Prop1Max)
&& RangeIsContained(outer.Prop2Min, outer.Prop2Max, inner.Prop2Min, inner.Prop2Max)
// ...
&& RangeIsContained(outer.Prop25Min, outer.Prop25Max, inner.Prop25Min, inner.Prop25Max);
}
With your data model this is basically the only way to go except for reflection (slow!). LINQ cannot help you because your data is not enumerable.
For the sake of completeness, here is a LINQ solution (but it's less performant and less readable than Ginosaji's solution!)
public class Range
{
public int Min { get; set; }
public int Max { get; set; }
public static bool IsContained(Range super, Range sub)
{
return super.Min <= sub.Min
&& super.Max >= sub.Max;
}
}
public class Itemi
{
public Itemi()
{
properties = new Range[25];
for (int i = 0; i < properties.Length; i++)
{
properties[i] = new Range();
}
}
private Range[] properties;
public IEnumerable<Range> Properties { get { return properties; } }
public static bool IsContained(Itemi super, Itemi sub)
{
return super.properties
.Zip(sub.properties, (first, second) => Tuple.Create(first, second))
.All((entry) => Range.IsContained(entry.Item1, entry.Item2));
}
public Range Prop1
{
get { return properties[0]; }
set { properties[0] = value; }
}
public Range Prop2
{
get { return properties[1]; }
set { properties[1] = value; }
}
// ...
}

Categories