Transpose jagged 2d list to 1d list - c#

I am implementing ZoomableCanvas http://blogs.msdn.com/b/kaelr/archive/2010/08/11/zoomableapplication2-a-million-items.aspx
It's a WPF control that allows for virtualized display of objects in a canvas. To take advantage of the virtualization, the library requires you to implement a method called 'Query' on your datasource object. The Query method lazily returns IEnumerable<int> given a Rect, where the int represents the position in the datasource of the element and the Rect is the visible area of the canvas (items not visible in the canvas are not returned and therefore not drawn). My data source is sorted such that the X and Y values are sorted (myList[0] would contain the smallest X,Y coordinates )
Given this info, I can simply do the following to get my items
int c = this.Count;
for (int j = 0; j < c; j++)
{
if (rectangle.Contains(new Point(this[j].left, this[j].top)))
{
yield return (int)j;
}
}
However, we're traversing the entire list and there's 100k+ items in the list. This performs remarkably badly, especially when viewing the bottom-right of the canvas as those items are at the end of the list.
So I tried transposing the data so that I can take the points in my visible area on the canvas and know exactly what indexes correspond in the array.
var tilewidth = MapWidthInTiles;
for (var x = Math.Max(left, 0); x <= right; x++)
{
for (var y = Math.Max(top, 0); y <= bottom; y++)
{
var i = (y * tilewidth) + x;
if (i < Count)
{
yield return (int)i;
}
}
}
This works except my dataset is irregular (I'm drawing a map), as the map may have missing or incomplete 'tiles'. Hence my array essentially is jagged.
Basically, I'm looking for a way where I can quickly identify elements given a 2D geometry in a 1D array, where the elements in the 2D array may not be complete or contiguous. Normally the [y * widthOfAllItems] + x would give me the proper 2d -> 1d transposition. But because of the missing elements, the equation is off. Any help is appreciated!

You need not to STORE your items in a 1D Array, you need to RETURN them to the ZoomableCanvas in a 1D Array. So feel free to store them in the most efficient way you can think of.
QuadTree might be one solution to store your points : a tree where each node has 4 children NE, SE, SW, NW, (NE=North-East, ...) each one is either empty, filled with one color, or has 4 children also.
Another solution : Working with the islands as base objects, using the bounding box to go faster.... and maybe store the islands in a tree.

Related

[Puzzle Game]Finding Combination of squares in a 2D Grid

I am making a game like Lumines Remastered (https://www.youtube.com/watch?v=8aJqNGjLtaY&t=358s) and I was pretty much successful in it. But, I got stuck in one place in clearing the pieces.
I have a 2d Array grid of 16x10 and each individual pieces are stored in it.
I was successful in finding all the matching pieces using the flood fill algorithm and storing every same color matching pieces in a separate list.
Now, the condition is I only want to delete the pieces that are in combination of squares with others and not the individual ones.
For example:-
Like this. 1 is in square combination and I only want to delete them.
But,
2 in this image is also a valid square (so, 1 & 2 combined should get deleted).
I quite can't seem to figure out how to check for square combination.
Any suggestions and ideas would be great.
You could probably loop over all of the cells, and check whether they are the bottom corner of a 2x2 square of the same colour and if so, mark all the cells in that square for deletion. After the loop finishes, you delete/empty all the marked cells.
This will also work for larger groups of cells, since they are made up of (overlapping) 2x2 squares.
While looping, make sure you stop short of the last row and column in the grid, to avoid going out of bounds when trying to check the next row/column.
I ended up taking #Vera suggestion and looped over the entire grid and checking if the blocks adjacent to the current block are of the same color and forming a square in 2x2 config. It works for larger groups of cells.
for (int j = 0; j < height; j++)
{
for (int i = 0; i < width; i++)
{
if (grid[i, j].tag == grid[i + 1, j].tag && grid[i, j].tag == grid[i, j + 1].tag && grid[i, j].tag == grid[i + 1, j + 1].tag)
{
Debug.Log("It's a square piece in 2x2 config");
}
}
}

Algorithm for drawing a trees where nodes can attach to others with a depth greater than itself + 1

This is not a duplicate of the Reingold-tolford, since that's just for drawing normal tree like structures. specifically I am looking for an algorithm where a node can link to a node thats not only on the level below it.
I'm building a tree like structure within a canvas control in WPF.
Currently I have a structure built like this(ignore the collisions of boxes I have that fixed) that generates automatically from my data.
While this structure isn't to bad, it'd be nice to work towards something with less collisions.
Therefore are there any algorithms I can follow and work with to draw a graph like this with less collisions.
I'm calculating all positions of the boxes like this currently,
flattenedList is a List < List< Object>> hence the i, j itteration. and that object has a treePosition Property with an X and Y double.
var canvasWidthFinder = new List<int>();
//Loop through all componentversions, use indexes to calc their positions.
for (int i = 0; i < flattenedList.Count; i++)
{
canvasWidthFinder.Add(flattenedList[i].Count);
for (int j = 0; j < flattenedList[i].Count; j++)
{
flattenedList[i][j].TreePosition.YPosition = (i * 150) + 25;
flattenedList[i][j].TreePosition.XPosition = ((Canvas.ActualWidth / (flattenedList[i].Count + 1)) * (j + 1)) - (125 / 2);
}
}
Canvas.Width = (canvasWidthFinder.Max() * 160);
These values are then used to draw borders with text inside and lines drawn between the connecting ones.
You could represent links that skip layers by creating dummy items in the intermediate layers. Then when you display the tree you could replace each dummy item with a vertical line instead of a block.

2D array with four infinite directions

I want to create a 2D map of tiles. Example:
Cell[,] cells;
for(int x = 0; x < columns; x++)
{
for(int y = 0; y < rows; y++)
{
cells[x, y] = new Cell();
}
}
The first cell would be at (0|0). What if I want to have this cell as my center and create new cells on the left and top side? These cells would have negative indices.
One way to fix this would be a value that determines the maximum length of one direction. Having a map of 100 tiles per side would place the center of the map at (50|50).
Let's say there would be no hardware limitations and no maximum length per side, what is the best way to create a 2D map with a (0|0) center? I can't image a better way than accessing a cell by its x and y coordinate in a 2D array.
Well, Arrays are logical constructs, not physical ones.
This means that the way we look at the the 0,0 as the top left corner, while might help visualize the content of a 2-D array (and in fact, a 2-D array is also somewhat of a visualization aid), is not accurate at all - the 0,0 "cell" is not a corner, and indexes are not coordinates, though it really helps to understand them when you think about them like they are.
That being said, there is nothing stopping you from creating your own class, that implement an indexer that can take both positive and negative values - in fact, according to Indexers (C# Programming Guide) -
Indexers do not have to be indexed by an integer value; it is up to you how to define the specific look-up mechanism.
Since you are not even obligated to use integers, you most certainly can use both positive and negative values as your indexer.
I was testing an idea to use a list of lists for storage and dynamically calculate the storage index based on the class indexer, but it's getting too late here and I guess I'm too tired to do it right. It's kinda like the solution on the other answer but I was attempting to do it without making you set the final size in the constructor.
Well, you can't use negative indices in an array or list, they're just not the right structure for a problem like this... You could, however, write your own class that handles something like this.
Simply pass in the size of the grid into the constructor, and then use the index operator to return a value based off of an an adjusted index... Something like this... Wrote it up really fast, so it probably isn't ideal in terms of optimization.
public class Grid<T> {
T[,] grid { get; }
int adjustment { get; }
int FindIndex(int provided) {
return provided + adjustment;
}
public Grid(int dimension) {
if (dimension <= 0)
throw new ArgumentException("Grid dimension cannot be <= 0");
if (dimension % 2 != 0)
throw new ArgumentException("Grid must be evenly divisible");
adjustment = dimension / 2;
grid = new T[dimension, dimension];
}
public T this[int key, int key2] {
get {
return grid[FindIndex(key), FindIndex(key2)];
}
set {
grid[FindIndex(key), FindIndex(key2)] = value;
}
}
}
I used these to test it:
var grid = new Grid<int>(100);
grid[-50, -50] = 5;
grid[0, 1] = 10;
You can just switch it to:
var grid = new Grid<Cell>(100);
This only works for a grid with equal dimensions... If you need separate dimensions, you'll need to adjust the constructor and the FindIndex method.
I think that an infinitely sized grid would be dangerous. If you increase the size to the right, you'd have to reposition the center.. Which means, what you think will be at 0,0 will now be shifted as the grid is no longer properly centered.
Additionally, performance of such a structure would be a nightmare as you cannot rely on an array to be infinite (as it inherently isn't). So you'd either have to continuously copy the array (like how a list works) or use a linked list.. If using a linked list, you would have to do enormous amounts of iteration to get whatever value you want.

Using List Indicies is not object oriented? c#

In the homework I am doing:
It is stated: "You may NOT use a number to access a tile - if you are using a number to find a tile, then it is most likely your design is not object oriented."
So essentially, my question is this:
If one were to not use an index to get an object from a list of objects, would the only solution be to use a foreach loop, every time you needed to retrieve a specific object?
If not, could you please provide an example (e.x. using a "for loop in an object oriented way", or other solutions instead of using an index)?
My concern is the amount of bloat (in lines) that might be created when not using for loops - and the affect that might have on speed.
e.g., I have the following:
for (int i = dimensions-1; i >= 0; i--)
{
map += "-";
for (int j = 0; j < dimensions; j++)
{
//For 4X4Y is 24. 3X4Y is 19. and so on.
//For 4X3Y is 23. 3X3Y is 18. and so on.
//As you can see: j * dimensions represents a "generalized" x value. adding it by i, represents its y value.
Tile currentTile = _game.TileSet[(j * dimensions) + i];
if (currentTile.Visitor == null)
map += "X-"; //X implies no robot
else
map += "R-"; //R implies robot
}
}
Yes this code is kind of ugly, but my list is formatted in such a way that I can't just use one foreach loop, and split the line on each x amount of tiles per line, as the list is stored vertically, and then horizontally, as opposed to horizontally, and then vertically (which would allow a simple foreach to suffice).
My concern is that if this is "not object oriented" - then using a foreach loop, would require a LOT more iterations.
Anyway, if anyone has an answer to the question I would really appreciate your thoughts.
Thanks.
Edit: Instead of using X and Y values, in a 2D List/Array, the list is 1d, and we are required to use association by having a list of connecting tiles, 4 elements, each element representing a typical compass direction in which the adjacent tile is located. There are no properties - however there is one method which can return an adjacent tile at a specified direction GetTileAtDirection(Direction).
The tileSet is a list of 25 elements, with 0 through 4 being the first 5 elements, X = 0, Y = 0 X = 0, Y = 1 X = 0, Y = 2 X = 0, Y = 3 X = 0, Y = 4. For the next five elements, X is incremented by one, representing the next five values in this "Y line"...
Note that there are no X and Y variables in which each tile can be accessed. This is a requirement in the homework.
If one were to not use an index to get an object from a list of
objects, would the only solution be to use a foreach loop, every time
you needed to retrieve a specific object?
No. I think the idea is that each tile should have a mapping of Direction to Tile, and GetTileAtDirection simply looks it up. The code that creates the tiles would need to assign the relationships, something like this:
nextTile = new Tile();
nextTile.AdjacentTiles[Direction.Left] = previousTile;
previousTile.AdjacentTiles[Direction.Right] = nextTile;
and so on. Of course, this code would probably be looking up the indices in TileSet, but the key is that an individual tile object can be completely independent from it -- the Tile class wouldn't even need a reference to a Game object or TileSet.

Largest Empty Rectangle Within a Rectangle

I'm not really good in maths, so I'm having really hard times converting formulas into code, and I can't find anything ready-made googling around. I have a big rectangle containing a lot of small rectangles... and all what I need to do is to calculate the largest empty rectangle. Anyonne can help me?
Here is what I came up with... nothing to say, it's a big fail.
Rect result = new Rect();
for (Double l = 0; l < bigRect.Width; ++l)
{
for (Double t = 0; t < bigRect.Height; ++t)
{
Double h = 0;
Double w = 0;
while ((h <= bigRect.Width) && (w <= bigRect.Height))
{
Rect largestEmpty = new Rect(l, t, w, h);
if (smallRects.TrueForAll(smallRect => !smallRect.IntersectsWith(largestEmpty)) && ((largestEmpty.Height * largestEmpty.Width) > (result.Height * result.Width)))
result = largestEmpty;
else
break;
++h;
++w;
}
}
}
From your Perdue Docs Link it says there is a set (let's call it ASD) of points in the Big Rect and you would to have find the largest Rect containing no points of the set ASD. Looking at your code, it seems you didn't (directly) incorporate these points. I would extract the points from the smaller Rects ans create set ASD. Since your working in type double, you should have access to the points, otherwise the algorithm would have a significantly higher run time since you need to check all possible doubles in a specific range (the entire Big Rect). Using the points, I would trying find the points with the shortest distance form each other (sqrt(dx^2+ dy^2)) (shortest shouldn't contain any points) then go to the next shortest and see if any points are contained and etc. In other words, create a order list of all combinations (not permutations, (a,b) to (c, d) should be == (c, d) to (a,b)) ordered by the distance in between them. Might not be optimal, but gets the job done.
EDIT: All order pair besides the diagonals of the smaller Rects should be in the order list, since the smaller Rects should not be conatined, You can also exclude pairs with the same x or y value.

Categories

Resources