How to calculate the Snake Index in N dimensions? - c#

I have written the following code in c# where it calculates the Snake index of a 2-dimensional point.
public static uint SnakeCurveIndex(uint bits, uint x, uint y )
{
uint index = 0;
//The dimension of the array
uint dim = (uint)Math.Pow( 2.0 , (double)bits);
if(y % (uint)2 == 0 )
{
index = x + y * dim;
}
else
{
index = (dim - 1 - x) + y * dim;
}
if (index >= dim*dim)
{
//Debug console
throw new Exception("The index is out of bounds");
}
return index;
}
The variable bits it responsible for the order of the curve. The following image represents the order of the curve for 1 to 3.
My question is who to extend this code for n-dimensional points? Do I need a multidimensional-array or some other technique?
Thank you for your time.

Related

Is it possible to write rule based iterators a 2d array of structs in C#(for nieghbours of a tile in a grid)?

I'm using C# and I used a 2d array of structs for a grid of tiles.This is not about how to find 8 neighboring tiles from a tile in the grid. I understand that in c# you can have a series of yield returns make a ienumerable. Like:
public IEnumerable<int> fakeList()
{
yield return 1;
yield return 2;
}
And call it with a foreach loop. Now, in my grid class want to have an easy way to access neighbours in grid.array[x,y] and modify it. But since it is a struct, I can't write an iterator like:
public IEnumerable<int> neighbours(int x, int y)
{
if((x+1) >=0 && y >=0 && .....)//check if node above is inside grid
yield return grid.array[x+1,y];
//rinse and repeat 7 more times for each direction
}
Instead, every time I need the neighbors, I need to copy paste the 8if conditions and check that I'm using the correct x+direction,y+direction to find valid indices. Basically, a huge pain.
I could work around by:
Not using structs and making my life easier. And getting rid of possible premature optimization. BUT I'm going to running this code every frame in my game. Possibly multiple times. So I'd like to keep the structs if possible.
Write iterator for indices instead. Ex:
Is the 2nd approach valid? Or does it generate garbage? I don't know how yield return works in detail.
public struct GridTile
{
public int x;
public int z;
public GridTile(int x, int z)
{
this.x = x;
this.z = z;
}
}
public IEnumerable<int> neighbours(int x, int y)
{
if ((x + 1) >= 0 && y >= 0 && .....)//check if right node is inside
yield return new Gridtile(x + 1, y);
//rinse and repeat 7 more times for each direction
}
If you know the coordinates of a 2D array entry, then the neighbors can be retrieved using loops:
var twoD = new int[10,10];
var someX = 5;
var someY = 5;
List<int> neighbors = new List<int>();
for(int nx = -1; nx <= 1; nx++){
for(int ny = -1; ny <= 1; ny++){
int iX = someX + nX;
int iY = someY + nY;
if(iX > 0 && iX < twoD.GetLength(0) && iY > 0 && iY < twoD.GetLength(1))
neighbors.Add(twoD[iX,iY]);
}
}

Building an exponent calculator

I'm relatively new to programming in C#. I'm building an exponent calculator, and I got it working, but while debugging I came across an issue that I do not understand why I get the output that I get.
This is the class and method in question when I get the output I know is wrong. (note i did later fix it by making it total *= lower in the for loop)
using System;
namespace stars
{
public class Exponent
{
public int Exp(int lower, int power)
{
int total = lower;
if ( power == 0 )
{
//returns 1 for any exponent of 0
Console.WriteLine(" 1");
return 1;
}
else if ( lower == 0 )
{
//returns 0 for any base of 0
Console.WriteLine("0");
return 0;
}
else if ( ( power % 1 ) == 0 ) // check for integer exponent
{
for ( int i = 1; !( i > power ); i++ ) //math
{
lower *= lower;
}
Console.WriteLine(lower);
return total;
}
else
{
Console.WriteLine("error");
}
}
}
}
at the last elseif, where I have my forloop, to (incorrectly) calculate the value of some integer to the power of another integer, I (incorrectly) perform the calculation lower = lower * lower, where lower is the base number.
i.e. 5^4,, 5 = lower, 4 = power
anyways, when I run it at 5^4, the result is 0. Why does it come out to 0? I figured it would work like this
5 * 5 = 25 ---> 25 * 25 = 625 ----> 625 * 625... etc
or is the end value so large that the compiler spits out 0.
First of all you should modify total in your routine and don't modify lower changing given parameter is often leads to errors.
Something like this:
public class Exponent
{
// static: we don't want this
public static int Exp(int lower, int power)
{
// Special cases
if (power == 0 || lower == 1)
return 1;
else if (lower == 0)
return 0;
else if (power < 0) //DONE: you've forgot about this case
throw new ArgumentOutOfRangeException(nameof(power));
// we don't want "power % 1 == 0" case - int power is always integer
// General case: math
int total = lower;
// "!( i > power )" - let's put at simpler (and correct) - "i < power"
for (int i = 1; i < power; ++i)
total *= lower;
return total;
}
}
...
// 5**4 == 625
Console.Write(Exponent.Exp(5, 4));
There are lot of issues in the code, I have fixed them. Though you have to consider other scenarios also. like if lowerand power are negative numbers, if numbers are big, it will not give you the required result.
public static int Exp(int lower, int power)
{
int total = lower;
if (power == 0) {
//returns 1 for any exponent of 0
Console.WriteLine(" 1");
return 1;
}
else if (lower == 0)
{
//returns 0 for any base of 0
Console.WriteLine("0");
return 0;
}
for (int i = 1; i < power; i++) //math
{
total *= lower;
}
Console.WriteLine(total);
return total;
}
There's quite a bit wrong styling wise with the code, and there's obviously an error somewhere or else you'd get the correct output. Let's break it down.
First I'll rewrite your code to be cleaner and easier to read:
public int Exp(int lower, int power)
{
int total = lower;
// 0 to the power of y is always 0
if ( lower == 0 )
return 0;
// x to the power of 0 is always 1
if ( power == 0 )
return 1;
// Your parameters for the Method explicitly state that
// 'power' is always an int, so no need to check
for ( int i = 1; i < power; i++ )
lower *= lower;
return total;
}
The cleanups I did:
Removed unnecessary 'else if's from code, as you are returning from within your 'if' anyways
Removed unnecessary braces reducing clutter
Moved comments to before check, as it is customary to comment code above it not below it
Now the problem is a lot more obvious: You're doing lower *= lower instead of total *= lower. So correct code would be this:
public int Exp(int lower, int power)
{
int total = lower;
// 0 to the power of y is always 0
if ( lower == 0 )
return 0;
// x to the power of 0 is always 1
if ( power == 0 )
return 1;
// Your parameters for the Method explicitly state that
// 'power' is always an int, so no need to check
for ( int i = 1; i < power; i++ )
total *= lower;
return total;
}

Drawing a line using a 1D array

Im currently having an issue using monogame where I am trying to draw a line by setting values within the data array itself rather than using the mono draw api.
Im using a modified version of the Bresenhams line algorithm, which seems to work if i draw using spritebatch, however I wish to use an array to set pixel colours.
The issue im having is finding the relevant coordinates as my monogame array is 1 Dimensional (width*height):
var data = new Microsoft.Xna.Framework.Color[width*height];
//my 1 dimensional array
int dx = Math.Abs(point2.x - point1.x);
int dy = Math.Abs(point2.y - point1.y);
int sx = (point1.x < point2.x) ? 1 : -1;
int sy = (point1.y < point2.y) ? 1 : -1;
int err = dx - dy;
for(int i=1;i<data.Length;++i)
{
data[i] = color; // me setting the pixel value
if (point1.x == point2.x && point1.y == point2.x)
{
break;
}
int e2 = 2 * err;
if (e2 > -dy)
{
err = err - dy;
point1.x = point1.x + sx;
}
if (e2 < dx)
{
err = err + dx;
point1.y = point1.y + sy;
}
}
Is there a simple way to find the pixel that relates to the point1.x and point1.y position where my pixels are contained within a 1D array.
I.E if i have (5*5) or (width*height) sized array (25), whilst looping how do i know whether the current loop counter represents the appropriate x,y position within the 1D array?
I have tried converting it into a 2D array, however i would rather avoid unnecessary loops of converting between a 1D and 2D array.
You can check it with
if(i == point.y * width + point.x)
{
//do something
}

How to find the nearest point in the chart?

.net 4
vs2010
winform
c#
added some points using
chart1.Series[0].Points.AddXY(x,y);
when I click on the chart, the cursor may not fall on any points.
Are there any functions to return the nearest point? (forget y, just x distance.)
Or I have to write my own binary search function?
private void Chart_MouseClick(object sender, MouseButtonEventArgs e)
{
LineSeries line = (LineSeries)mychart.Series[0];
Point point = e.GetPosition(line);
Int32? selectIndex = FindNearestPointIndex(line.Points, point);
// ...
}
private Int32? FindNearestPointIndex(PointCollection points, Point point)
{
if ((points == null || (points.Count == 0))
return null;
Func<Point, Point, Double> getLength = (p1, p2) => Math.Sqrt(Math.Pow(p1.X - p2.X, 2) + Math.Pow(p1.Y - p2.Y, 2)); // C^2 = A^2 + B^2
List<Points> results = points.Select((p,i) => new { Point = p, Length = getLength(p, point), Index = i }).ToList();
Int32 minLength = results.Min(i => i.Length);
return results.First(i => (i.Length == minLength)).Index;
}
To find the nearest point in a set of unordered points, you have to iterate through them all and keep track of the minimum distance. This has a time complexity of O(n).
You could significantly improve this by maintaining the points in a more organized data structure (such as an R-tree). There are third-party libraries available if you'd rather not implement your own. Many databases already support the R-tree for spatial indices.
If you really want to only search for the point with the nearest X-coordinate, this could be further simplified by storing the points in a sorted collection (such as a SortedList<TKey, TValue>) and performing a binary search (which SortedList<TKey, TValue>.IndexOfKey already implements).
/*My Fuzzy Binary Search*/
private int FindNearestId(System.Windows.Forms.DataVisualization.Charting.DataPointCollection p, uint ClickedX)
{
int ret = 0;
int low = 0;
int high = p.Count - 1;
bool bLoop = true;
while (bLoop)
{
ret = (low + high) / 2;
switch (FindNearestId_Match(p, ClickedX, ret))
{
case 0:
high = ret+1;
break;
case 1:
bLoop = false;
break;
case 2:
low = ret-1;
break;
}
}
return ret+1;
}
private int FindNearestId_Match(System.Windows.Forms.DataVisualization.Charting.DataPointCollection p, uint ClickedX, int id)
{
uint id0 = Convert.ToUInt32(p[id].XValue);
uint id1 = Convert.ToUInt32(p[id+1].XValue);
if ( (id0 <= ClickedX) && (ClickedX < id1) )
{
return 1;
}
else if ((id0 < ClickedX) && (ClickedX > id1))
{
return 2;
}
else
{
return 0;
}
}
Soultion can be more clear.
( as above you should use log complexity for accessing item )
double x-values solution:
double FindNearestPointYValueInSeries( System::Windows::Forms::DataVisualization::Charting::Series ^pxSeries, double dSearchedPosition )
{
int i_min = 0;
int i_max = pxSeries->Points->Count - 1;
int i_mean = 0;
double d ;
if ( i_max < 0 ) // not defined - minimum one point required
return Double::NaN;
while ( i_min <= i_max )
{
i_mean = (i_max + i_min ) / 2; // index of compared value in series
d = pxSeries->Points[ i_mean ]->XValue; // compared value
if ( d > dSearchedPosition ) // greater - search in right part
i_max = i_mean - 1;
else if ( d < dSearchedPosition ) // lower - search in left part
i_min = i_mean + 1;
else // equal ?
return d;
}
// delta is dSearchedPosition - pxSeries->Points[ i_mean ]->YValues[0]
// get Y value ( on index 0 )
return pxSeries->Points[ i_mean ]->YValues[0];
}

C# - Recursive Function Issue

Here's my function:
static Map AddFormation(Map _map, Tile tile, int x, int y, int length,
Random rand, Tile endTile = (Tile)Int32.MaxValue)
{
//so a call to AddFormation without the endTile will work, if I don't want a border.
if ((int)endTile == Int32.MaxValue) endTile = tile;
if (x >= 0 && x < _map.Data.GetLength(0) && y >= 0 && y < _map.Data.GetLength(1))
{
if (_map.Data[x, y].Tile != tile)
{
if (length > 0)
{
_map.Data[x, y].Tile = tile;
int newlength = length - 1;
AddFormation(_map, tile, x, y - 1, newlength, rand, endTile); // ^
AddFormation(_map, tile, x, y + 1, newlength, rand, endTile); // v
AddFormation(_map, tile, x - 1, y, newlength, rand, endTile); // <-
AddFormation(_map, tile, x + 1, y, newlength, rand, endTile); // ->
}
else
{
_map.Data[x, y].Tile = endTile;
}
}
}
return _map;
}
I have a Tile enum which is to make my life easier when working with the tiles.
I have a Cell class which contains a Tile enum called "Tile" and other info (unimportant to this)
The Map class contains a Cell[,] group called Data.
What I am trying to achieve is to create a block of the specific tile at a specific point, I will later incorporate Randomisation into this (so it wouldn't be just a diamond) but I took it out to see if that was the cause of my issue.
The problem is a call to this function always produces blocks taller than they are wide and I can't for the life of me see why..
I created a test function to see what happens if I use something like:
public static int[,] Add(int[,] grid, int x, int y, int length, int value)
{
if (x >= 0 && y >= 0 && x < grid.GetLength(0) && y < grid.GetLength(1))
{
if(grid[x,y] != value)
{
if(length > 0)
{
grid[x, y] = value;
Add(grid, x - 1, y, length - 1, value);
Add(grid, x + 1, y, length - 1, value);
Add(grid, x, y - 1, length - 1, value);
Add(grid, x, y + 1, length - 1, value);
}
}
}
return grid;
}
Which seems to suffer from the same problem if you go big enough (5 produces a perfect diamond, 6 produces a strange shape and something like 11 even stranger)
Ok, after spending a long time on this (I do like recursion), here is partway to the solution (it may be hard to explain):
The problem is that you are allowing the "path" to backtrack along the cells that have already been allocated as endTiles. If you take a look at your first method, you make the search point go down straight after it has searched up. You simply need to remove that.
This is the code I am using (notice that it calls AddFormationAlt twice, once for going up, once for going down):
class Program
{
static string left;
static string right;
static void Main(string[] args)
{
int size = 20;
int sizem = size*2 + 1;
Map m = new Map(new int[sizem,sizem]);
AddFormationAlt(m, 1, size, size, size-1, 2);
var l = left;
var r = right;
}
private class Map
{
public int[,] Data { get; set; }
public Map(int[,] data)
{
Data = data;
}
public string Print()
{
StringBuilder sb = new StringBuilder();
for (int x = 0; x < Data.GetLength(0); x++)
{
for (int y = 0; y < Data.GetLength(1); y++)
sb.Append(Data[y, x] == 0 ? " " : Data[y,x] == 1 ? "." : "#");
sb.AppendLine();
}
return sb.ToString();
}
}
static void AddFormationAlt(Map _map, int tile, int x, int y, int length, int endTile)
{
// You may need to change the cloning method when you change the tiles from ints
Map m1 = new Map((int[,])_map.Data.Clone());
Map m2 = new Map((int[,])_map.Data.Clone());
// Contains the left and right half of the Map you want, you need to join these together.
Map aleft = AddFormationAlt(m1, true, tile, x, y, length, endTile);
Map aright = AddFormationAlt(m2, false, tile, x, y + 1, length, endTile);
left = aleft.Print();
right = aright.Print();
}
static Map AddFormationAlt(Map _map, bool up, int tile, int x, int y, int length, int endTile)
{
if (x >= 0 && x < _map.Data.GetLength(0) && y >= 0 && y < _map.Data.GetLength(1))
{
if (_map.Data[y, x] != tile)
{
if (length > 0)
{
_map.Data[y, x] = tile;
int newlength = length - 1;
// Either go 'up' or 'down'
if(up)
AddFormationAlt(_map, true, tile, x, y - 1, newlength, endTile); // ^
else
AddFormationAlt(_map, false, tile, x, y + 1, newlength, endTile); // v
AddFormationAlt(_map, up, tile, x - 1, y, newlength, endTile); // <-
AddFormationAlt(_map, up, tile, x + 1, y, newlength, endTile); // ->
}
else
_map.Data[y, x] = endTile;
}
}
return _map;
}
}
I changed all your Data[x, y] to Data[y, x] because that's how I usually store them and then it worked xD.
In aleft and aright you have the left half and the right half of the diamond you want in separate Maps, you need to join them together somehow (shouldn't be too hard for a clever guy like you :). left and right show the textual representation of Maps (note the overlap in the centre):
left:
#
#.
#..
#...
#....
#.....
#......
#.......
#........
#.........
#..........
#...........
#............
#.............
#............
#...........
#..........
#.........
#........
#.......
#......
#.....
#....
#...
#..
#.
#
right:
#
.#
..#
...#
....#
.....#
......#
.......#
........#
.........#
..........#
...........#
............#
.............#
............#
...........#
..........#
.........#
........#
.......#
......#
.....#
....#
...#
..#
.#
#
You need to clean this up and change all the classes back to your own ones. I hope this helps!
When you say:
if(grid[x,y] != value)
You're telling it to only continue down this "leg" if you don't run into any blocks that have already been set to this value. The problem is that once you get a long enough length, the "leg" going out the top of the starting point "spirals around" to the left and right, and so when the recursion finally comes back to the point where it starts trying to go out the left or right, there is already a square there and you return immediately.
It looks like you want to take the if(length > 0) and put it after the if(grid[x,y] != value) block, rather than inside of it. That way, you only "set" the value if it hasn't already been set, but you will continue until you reach the appropriate length.
Of course, since "branches" (i.e. if statements) take longer than "assignments" (i.e. setting a value in an array), you might as well just remove the if(grid[x,y] != value) entirely, and risk setting spots to the same value multiple times, because it's cheaper than comparing the current value.
if (x >= 0 && y >= 0 && x < grid.GetLength(0) && y < grid.GetLength(1))
{
grid[x, y] = value;
if(length > 0)
{
Add(grid, x - 1, y, length - 1, value);
Add(grid, x + 1, y, length - 1, value);
Add(grid, x, y - 1, length - 1, value);
Add(grid, x, y + 1, length - 1, value);
}
}
return grid;
Don't you want something like
if(grid[x,y] != 0) // or whatever the initial value is
instead of
if(grid[x,y] != value)
Otherwise, when you grow out, it will grow back to the seed point.

Categories