I have the following classes:
public class Layer
{
public Tile[,] Grid; //50x50 positions filled with my own Tile struct
}
public class Level
{
public Layer[] Layers; //An array of layers in the level
public List<object> Objects; //And a couple of lists of say, characters or such in the level.
}
public class Area
{
private Level[,] _activeLevels; //3x3 array of the current level and surrounding ones.
}
What I want is to be able to call for instance..
Area.Layers[0].Grid[112, 64];
To get the Tile in Grid[12, 14] from Level[2,1].
More explanation:
Assuming a layer has 50 x 50 positions, I hope the following will explain what I want.
"if I call" => "then I actually want"
Area.Layers[0].Grid[0,0] => Area.Level[0,0].Layers[0].Grid[0,0]
Area.Layers[0].Grid[0,10] => Area.Level[0,0].Layers[0].Grid[0,10]
Area.Layers[0].Grid[0,49] => Area.Level[0,0].Layers[0].Grid[0,49]
Area.Layers[0].Grid[0,50] => Area.Level[0,1].Layers[0].Grid[0,0]
Area.Layers[0].Grid[0,60] => Area.Level[0,1].Layers[0].Grid[0,10]
Area.Layers[0].Grid[0,112] => Area.Level[0,2].Layers[0].Grid[0,12]
--[next part already answered, see below]--
Also, I want to be able to call for instance..
foreach (object o in Area.Objects)
//dostuff
To call a foreach on -all- the objects from the nine levels.
Could anyone give me a nudge in the right direction, some advice on how to achieve this, or heck, plainly code it out?
For Area.Layers[0].Grid[112, 64] you'd probably be better off with a method of the form Area.GetTile(0, 112, 64) implemented as
public Tile GetTile(int layer, int overallX, int overallY)
{
return _activeLevels[overallX / 50, overallY / 50]
.Layers[layer]
.Grid[overallX % 50, overallY % 50];
}
Not sure what you want in the first example, you may want to check it's correct.
You can loop over all the objects in 1 iterator by implementing your own IEnumerable:
public class Area {
private Level[,] _activeLevels; //3x3 array of the current level and surrounding ones.
IEnumerable<object> Objects {
get {
foreach (Level lvl in _activeLevels)
foreach (object o in lvl.Objects)
yield return o;
}
}
}
Can the same object be share dbetween different levels? in that case you may want to filter for duplicates.
Related
I am trying to add a few different members to a list, but when the list is added to it contains copies of only the last member added:
private PotentialSolution tryFirstTrack(PotentialSolution ps, List<PotentialSolution> possibleTracks)
{
for (Track trytrack = Track.Empty + 1; trytrack < Track.MaxVal; trytrack++)
{
if (validMove(ps.nextSide, trytrack))
{
ps.SetCell(trytrack);
possibleTracks.Add(ps);
}
}
return tryNextTrack(ps, possibleTracks);
}
The PotentialSolution class looks like this:
public class PotentialSolution
{
public Track[,] board;
public Side nextSide;
public int h;
public int w;
static int cellsPerSide;
static bool testing;
static int minTracks;
.....
public void SetCell(Track t)
{
board[h, w] = t;
}
}
So we are trying to make several copies of the board which only differ by which 'track' is placed in the current cell.
If I have a breakpoint at possibleTracks.Add(ps) then I can see by inspecting ps that the required cell contents is changing each time, as required.
But when the code reaches the next line (or the return statement), the cell content is the same in each member of the list (it's the last one that was added).
What I am doing wrong here? I have tried using an ArrayList and also a basic array instead, but get the same result. It's acting as though the board member is decared as static, but it's not.
[edit]
In response to those who suggested making copies of ps, you are correct and I had tried this before - but only tried single-stepping after the change and didn't run the full program (this method is used hundreds of times). When running the full program, making copies of ps certainly makes a difference to the result (although it's still not correct). The problem now, and why I didn't stick with using the copies, is that an added test still shows the list to contain the same versions of ps, even though the debugger has shown 2 or 3 different tracks being deployed:
private PotentialSolution tryFirstTrack(PotentialSolution ps, List<PotentialSolution> possibleTracks)
{
for (Track trytrack = Track.Empty + 1; trytrack < Track.MaxVal; trytrack++)
{
if (validMove(ps.nextSide, trytrack))
{
PotentialSolution newps = new PotentialSolution(ps);
newps.SetCell(trytrack);
possibleTracks.Add(newps);
}
}
// temporary test, can be removed
if (possibleTracks.Count >= 2)
{
PotentialSolution ps1 = new PotentialSolution(possibleTracks.First());
PotentialSolution ps2 = new PotentialSolution(possibleTracks.Last());
if (ps1.GetCell() != ps2.GetCell())
{
// should always get here but never does
int foo = 1;
}
}
return tryNextTrack(ps, possibleTracks);
}
By the way, Track and nextSide are just enum integers, they will be 0-6, and the list will contain 0,1,2,or 3 members, never more.
You are adding references to the same object: ps in possibleTracks.Add(ps)
You could add a constructor to PotentialSolution duplicating the class:
public class PotentialSolution
{
public Track[,] board;
public Side nextSide;
public int h;
public int w;
static int cellsPerSide;
static bool testing;
static int minTracks;
//.....
public PotentialSolution()
{
}
public PotentialSolution(PotentialSolution ps)
{
board = ps.board;
nextSide = ps.nextSide;
h = ps.h;
w = ps.w;
}
//.....
Then use:
private PotentialSolution tryFirstTrack(PotentialSolution ps, List<PotentialSolution> possibleTracks)
{
for (Track trytrack = Track.Empty + 1; trytrack < Track.MaxVal; trytrack++)
{
if (validMove(ps.nextSide, trytrack))
{
ps.SetCell(trytrack);
possibleTracks.Add(new PotentialSolution(ps)); // duplicate object
}
}
return tryNextTrack(ps, possibleTracks);
}
This creates a new instance of the class each time it is added to the list.
Consider giving the PotentialSolution type value semantics by making it a struct and implementing a Clone method, or a constructor that takes another PotentialSolution as an argument. Also, to clone a 2D array of value types, call Object.Clone() and cast the result to T[,].
When making a copy of your PotentialSolution, you'll need to make sure your clone your board array, because, in your case, each PotentialSolution keeps its own representation of the state of the board.
I feel like the critical part you're missing is how to shallow clone a 2D array, which in general, is:
T[,] copy = (T[,])original.Clone();
WARNING: Clone creates a shallow copy of the array. For value-types this copies the values of each element, so for your int-like "Track" type it does what you want, but for other readers who may be using reference-types (like classes) it does not clone each object referred to by each element of the array. The elements of the new array are just object references, and will still refer to the same objects referred to by the elements of the original array. See the documentation.
Full example below that changes the middle cell of a 3x3 board from A to B.
using System;
using System.Linq;
public enum Track { A, B, C }
public enum Side { X, Y, Z }
public struct PotentialSolution
{
public Track[,] board;
public Side nextSide;
public int h;
public int w;
public void SetCell(Track t)
{
board[h, w] = t;
}
public PotentialSolution(Track[,] board, Side nextSide, int h, int w)
{
this.board = (Track[,])board.Clone();
this.nextSide = nextSide;
this.h = h;
this.w = w;
}
public PotentialSolution Clone()
{
return new PotentialSolution(board, nextSide, h, w);
}
// This `ToString` is provided for illustration only
public override string ToString()
{
var range0 = board.GetLength(0);
var range1 = board.GetLength(1);
var b = board;
return string.Join(",",
Enumerable.Range(0, range0)
.Select(x => Enumerable.Range(0, range1)
.Select(y => b[x, y]))
.Select(z => "[" + string.Join(",", z) + "]"));
}
}
class Program
{
static void Main(string[] args)
{
Track[,] someBoard = new Track[3, 3];
PotentialSolution ps1 = new PotentialSolution(someBoard, Side.X, 1, 1);
ps1.SetCell(Track.A);
PotentialSolution ps2 = ps1.Clone();
ps2.SetCell(Track.B);
Console.WriteLine(ps1);
Console.WriteLine(ps2);
}
}
I'm filling in the blanks liberally, so please excuse any assumptions I have made that differ from your actual situation, because I have done so only to make this example self-contained. My ToString implementation and its usage of System.Linq is not necessary; it's purely for the purposes of displaying the 2D array in my example.
You always call SetCell on the same ps object you received as a parameter then add the same instance to the possibleTracks list. The result is: possibleTrack contains ps n times and because it is the same instance you used in each cycle it will have the last change you applied via SetCell call.
Not sure what you wanted to achieve but it looks you need a modified copy of ps in each cycle for adding to possibleTrack list. Making PotentialSolution a struct instead of class could be enough? Structs are copied in such a way but may hit your performance if PotentialSolution is big.
The board member will still generate the same problem, because despite ps will be copied but the board inside it will contain same Track references. The trick can be applied to Track too, but the performance issues may raise more.
Just implement a Clone on PotentialSolution to have fully detached instances of it, then call ````SetCell``` on cloned instance and add that instance to the list.
I can type
Square[,,,] squares = new Square[3, 2, 5, 5];
squares[0, 0, 0, 1] = new Square();
In fact, I expect I could keep going adding dimensions to Int.MaxValue though I have no idea how much memory that would require.
How could I implement this variable indexing feature in my own class? I want to encapsulate a multi dimensional array of unknown dimensions and make it available as a property thus enabling indexing in this manner. Must I always know the size in which case how does Array work?
EDIT
Thanks for the comments, here is what I ended up with - I did think of params but didn't know where to go after that not knowing about GetValue.
class ArrayExt<T>
{
public Array Array { get; set; }
public T this[params int[] indices]
{
get { return (T)Array.GetValue(indices); }
set { Array.SetValue(value, indices);}
}
}
ArrayExt<Square> ext = new ArrayExt<Square>();
ext.Array = new Square[4, 5, 5, 5];
ext[3, 3, 3, 3] = new Square();
TBH I don't really need this now. I was just looking for a way to extend Array to initialize its elements having resolved to avoid for loop initialization code outside the class whenever I was using a multi array (mainly in unit tests). Then I hit intellisense and saw the Initialize method...though it restricts me to a default constructor and value types. For reference types an extension method would be required. Still I learnt something and yes, there was a runtime error when I tried an array with more than 32 dimensions.
Arrays types are magic – int[] and int[,] are two different types, with separate indexers.
These types are not defined in source code; rather, their existence and behavior are described by the spec.
You would need to create a separate type for each dimensionality – a Matrix1 class with a this[int], a Matrix2 class with a this[int, int], and so on.
You could use varargs:
class Squares {
public Square this[params int[] indices] {
get {
// ...
}
}
}
You'd have to handle the fact indices can have an arbitrary length yourself, in whicheevr way you feel is appropriate. (E.g. check the size of indices against the array rank, type it as Array and use GetValue().)
use the this[] operator:
public int this[int i, int j]
{
get {return 1;}
set { ; }
}
Note that you can't have a variable number of dimensions in one operator - you have to code each method separately:
public int this[int i, int j, int k]
{
get {return 1;}
set { ; }
}
public int this[int i, int j]
{
get {return 1;}
set { ; }
}
public int this[int i]
{
get {return 1;}
set { ; }
}
I expect I could keep going adding dimensions to Int.MaxValue
You'd be wrong:
An array can have a maximum of 32 dimensions.
Lets assume you have a function that returns a lazily-enumerated object:
struct AnimalCount
{
int Chickens;
int Goats;
}
IEnumerable<AnimalCount> FarmsInEachPen()
{
....
yield new AnimalCount(x, y);
....
}
You also have two functions that consume two separate IEnumerables, for example:
ConsumeChicken(IEnumerable<int>);
ConsumeGoat(IEnumerable<int>);
How can you call ConsumeChicken and ConsumeGoat without a) converting FarmsInEachPen() ToList() beforehand because it might have two zillion records, b) no multi-threading.
Basically:
ConsumeChicken(FarmsInEachPen().Select(x => x.Chickens));
ConsumeGoats(FarmsInEachPen().Select(x => x.Goats));
But without forcing the double enumeration.
I can solve it with multithread, but it gets unnecessarily complicated with a buffer queue for each list.
So I'm looking for a way to split the AnimalCount enumerator into two int enumerators without fully evaluating AnimalCount. There is no problem running ConsumeGoat and ConsumeChicken together in lock-step.
I can feel the solution just out of my grasp but I'm not quite there. I'm thinking along the lines of a helper function that returns an IEnumerable being fed into ConsumeChicken and each time the iterator is used, it internally calls ConsumeGoat, thus executing the two functions in lock-step. Except, of course, I don't want to call ConsumeGoat more than once..
I don't think there is a way to do what you want, since ConsumeChickens(IEnumerable<int>) and ConsumeGoats(IEnumerable<int>) are being called sequentially, each of them enumerating a list separately - how do you expect that to work without two separate enumerations of the list?
Depending on the situation, a better solution is to have ConsumeChicken(int) and ConsumeGoat(int) methods (which each consume a single item), and call them in alternation. Like this:
foreach(var animal in animals)
{
ConsomeChicken(animal.Chickens);
ConsomeGoat(animal.Goats);
}
This will enumerate the animals collection only once.
Also, a note: depending on your LINQ-provider and what exactly it is you're trying to do, there may be better options. For example, if you're trying to get the total sum of both chickens and goats from a database using linq-to-sql or linq-to-entities, the following query..
from a in animals
group a by 0 into g
select new
{
TotalChickens = g.Sum(x => x.Chickens),
TotalGoats = g.Sum(x => x.Goats)
}
will result in a single query, and do the summation on the database-end, which is greatly preferable to pulling the entire table over and doing the summation on the client end.
The way you have posed your problem, there is no way to do this. IEnumerable<T> is a pull enumerable - that is, you can GetEnumerator to the front of the sequence and then repeatedly ask "Give me the next item" (MoveNext/Current). You can't, on one thread, have two different things pulling from the animals.Select(a => a.Chickens) and animals.Select(a => a.Goats) at the same time. You would have to do one then the other (which would require materializing the second).
The suggestion BlueRaja made is one way to change the problem slightly. I would suggest going that route.
The other alternative is to utilize IObservable<T> from Microsoft's reactive extensions (Rx), a push enumerable. I won't go into the details of how you would do that, but it's something you could look into.
Edit:
The above is assuming that ConsumeChickens and ConsumeGoats are both returning void or are at least not returning IEnumerable<T> themselves - which seems like an obvious assumption. I'd appreciate it if the lame downvoter would actually comment.
Actually simples way to achieve what you what is convert FarmsInEachPen return value to push collection or IObservable and use ReactiveExtensions for working with it
var observable = new Subject<Animals>()
observable.Do(x=> DoSomethingWithChicken(x. Chickens))
observable.Do(x=> DoSomethingWithGoat(x.Goats))
foreach(var item in FarmsInEachPen())
{
observable.OnNext(item)
}
I figured it out, thanks in large part due to the path that #Lee put me on.
You need to share a single enumerator between the two zips, and use an adapter function to project the correct element into the sequence.
private static IEnumerable<object> ConsumeChickens(IEnumerable<int> xList)
{
foreach (var x in xList)
{
Console.WriteLine("X: " + x);
yield return null;
}
}
private static IEnumerable<object> ConsumeGoats(IEnumerable<int> yList)
{
foreach (var y in yList)
{
Console.WriteLine("Y: " + y);
yield return null;
}
}
private static IEnumerable<int> SelectHelper(IEnumerator<AnimalCount> enumerator, int i)
{
bool c = i != 0 || enumerator.MoveNext();
while (c)
{
if (i == 0)
{
yield return enumerator.Current.Chickens;
c = enumerator.MoveNext();
}
else
{
yield return enumerator.Current.Goats;
}
}
}
private static void Main(string[] args)
{
var enumerator = GetAnimals().GetEnumerator();
var chickensList = ConsumeChickens(SelectHelper(enumerator, 0));
var goatsList = ConsumeGoats(SelectHelper(enumerator, 1));
var temp = chickensList.Zip(goatsList, (i, i1) => (object) null);
temp.ToList();
Console.WriteLine("Total iterations: " + iterations);
}
What I'm trying to achieve is say i have an array, i want to be able to modify a specific array element throughout my code, by pointing at it.
for example in C++ i can do this
int main(){
int arr [5]= {1,2,3,4,5};
int *c = &arr[3];
cout << arr[3] <<endl;
*c = 0;
cout << arr[3]<<endl;
}
I did some googling and there seems to be a way to do it through 'unsafe', but i don't really want to go that route.
I guess i could create a variable to store the indexes, but I'm actually dealing with slightly more complexity (a list within a list. so having two index variables seems to add complexity to the code.)
C# has a databinding class, so what I'm currently doing is binding the array element to a textbox (that i have hidden) and modifying that textbox whenever i want to modify the specific array element, but that's also not a good solution (since i have a textbox that's not being used for its intended purpose - a bit misleading).
A C# example of how you would like the use to look would help. If I understand what you're asking, a simple class like this might do it. What you're asking for though, doesn't seem like a very good idea. If you showed the larger scope in which you need this, someone might be able to point out a better design where you didn't need this sort of functionality at all.
public class ListElement<T> {
private IList<T> list;
private int index;
public ListElement(IList<T> list, int index) {
this.list = list;
this.index = index;
}
public T Value {
get {
return list[index];
}
set {
list[index] = value;
}
}
}
a use of this would look like
int[] arr = new int[] {1,2,3,4,5};
ListElement<int> third = new ListElement<int>(arr, 2);
Console.WriteLine(third.Value);
third.Value = 0;
Console.WriteLine(third.Value);
i'm not sure if this fits exactly, but the problem is that these pointers are not possible in c#.
if you have more complicated lists, you can take a look at LinkedList<T>
it provides a performant way if you want to change elements within a list.
I came up with a somewhat solution in C#. Granted this is off the cuff, so it may not work in all situations but I did test it briefly on your situation.
class Wrapper<T>
{
private T[] array;
private T item;
private int index;
public T Item { get { return item; } set { item = value;
array[Index] = value;
} }
public int Index
{
get { return index; }
set
{
index = value;
Item = array[value];
}
}
public Wrapper(T[] arr)
{
array = arr;
}
}
You can then use the class like this:
class Program
{
static void Main(string[] args)
{
int[] i = {1, 2, 3, 4, 5};
i.ToList().ForEach(x => Console.WriteLine(x));
Wrapper<int> w = new Wrapper<int>(i);
w.Index = 2;
w.Item = 5;
i.ToList().ForEach(x => Console.WriteLine(x));
Console.ReadLine();
}
}
This will give the output: 1234512545
It isn't as pretty as the solution in C++ but it will work as you want and provides a more "automatic" version of referencing the array.
I would wrap your arrays in Objects. In C#, stuff that needs pointer manipulation is usually best done with objects.
The advantage is that objects allow clearer naming and access to more complex data structures. You are right, it is not ideal to pass around sets of indices - the ordering and indexing is easily jumbled.. In fact, I think it was people in your position who decided Object-oriented programming would be a good idea!!
So you have class MyArray { }, and can use the 'object reference' as you would a pointer,
plus you can create arrays of MyArray[].
I have a object, let's call it "Friend".
This object has method "GetFriendsOfFriend", that returns a List<Friend>.
Given a user input of say 5, all of the Friends friends and the friends friends friends (you get the point) down in a level of 5 (this can be up to 20).
This may be a lot of calculations, so I don't know if recursion is the best solution.
Does anyone have a smart idea of
1. How to do this recursive function best?
2. How to do it without recursion.
Thanks!
Whilst is is certainly possible to do this without recursion, I don't see a particular problem with what you're trying to do. To prevent things going crazy, it might make sense to set a maximum to prevent your program from dying.
public class Friend
{
public static readonly int MaxDepth = 8; // prevent more than 8 recursions
private List<Friend> myFriends_ = new List<Friend>();
// private implementation
private void InternalFriends(int depth, int currDepth, List<Friend> list)
{
// Add "us"
if(currDepth > 1 && !list.Contains(this))
list.Add(this);
if(currDepth <= depth)
{
foreach(Friend f in myFriends_)
{
if(!list.Contains(f))
f.InternalFriends(depth, depth + 1, list); // we can all private functions here.
}
}
} // eo InternalFriends
public List<Friend> GetFriendsOfFriend(int depth)
{
List<Friend> ret = new List<Friend>();
InternalFriends(depth < MaxDepth ? depth : MaxDepth, 1, ret);
return ret;
} // eo getFriendsOfFriend
} // eo class Friend
EDIT: Fixed an error in the code in that an actual friend would not get added, just "their" friends. This is only necessary when adding friends after a depth of "1" (the first call). I also made use of Contains to check for duplicates.
Here is a non recursive version of this code:
public static void ProcessFriendsOf(string person) {
var toVisit = new Queue<string>();
var seen = new HashSet<string>();
toVisit.Enqueue(person);
seen.Add(person);
while(toVisit.Count > 0) {
var current = toVisit.Dequeue();
//process this friend in some way
foreach(var friend in GetFriendsOfFriend(current)) {
if (!seen.Contains(friend)) {
toVisit.Enqueue(friend);
seen.Add(friend);
}
}
}
}
It avoids infinite loop by keeping a HashSet of all members already seen and not adding a member to be processed more than once.
It visits friends using a Queue, in a way that is known as Breadth-first search. If we use a Stack instead of a Queue, it becomes a Depth-first search, and would behave pretty much the same as a recursive approach (which uses an implicit stack - the call stack).