I'm currently trying to make a code, that will help to count efficient reactors set for game StarMade.
I'm using recursive method to explore the 3d tree of elements and find all related groups. For ex. group - it's a cluster of elements, that stay close to each other.
On picture something like this:
XOX
OOX
XXO
where O is nothing, and X is reactor (element).
On this picture there are 3 groups of elements. [0,0], [2,0]-[2,1], [0,2]-[1,2]
Another variant:
XXX
OOX
XXX
Here is only one group, because all elements stay close to each other.
Here is my code:
void CheckGroup(int x, int y, int z, Group group)
{
if(x >= maxz || x < 0 || y >= maxy || y < 0 || z >= maxz || z < 0)
{
return;
}
if (reactorsChecked[x, y, z])
{
return;
}
reactorsChecked[x, y, z] = true;
if (reactors[x, y, z])
{
if (group == null)
{
group = new Group();
group.MaxX = x;
group.MaxY = y;
group.MaxZ = z;
group.MinX = x;
group.MinY = y;
group.MinZ = z;
group.Blocks = 1;
}
else
{
group.MaxX = Math.Max(group.MaxX, x);
group.MaxY = Math.Max(group.MaxY, y);
group.MaxZ = Math.Max(group.MaxZ, z);
group.MinX = Math.Min(group.MinX, x);
group.MinY = Math.Min(group.MinY, y);
group.MinZ = Math.Min(group.MinZ, z);
group.Blocks += 1;
}
CheckGroup(x + 1, y, z, group);
CheckGroup(x - 1, y, z, group);
CheckGroup(x, y + 1, z, group);
CheckGroup(x, y - 1, z, group);
CheckGroup(x, y, z + 1, group);
CheckGroup(x, y, z - 1, group);
if (!groups.Contains(group))
{
groups.Add(group);
}
}
}
group - is simple class for cluster, that store data about elements count in this cluster and bounding box of this cluster.
reactorsChecked - is simple bool[,,] array, that store information about elements, that we have checked, to avoid doubles
reactor - simple bool[,,] array of random elements.
At first I insert random values to reactors array, and then call CheckGroup(x,y,z,null). If reactors array size less then 25x25x25, then all ok. In single thread size of array could be 100x100x100 and all would be ok. But if I try to use Parallel.For, then I got StackOverflow after near 9000 recursions...
Here is full code:
Parallel.For(0, Environment.ProcessorCount, (i) =>
{
Calculator calc = new Calculator(x, y, z, max, cycles);
calcs.Add(calc);
});
public class Calculator
{
Random rnd = new Random();
//List<Group> groups = new List<Group>();
HashSet<Group> groups = new HashSet<Group>();
bool[, ,] reactors;
public bool[, ,] reactorsMax;
bool[, ,] reactorsChecked;
public double maxEnergy = 0;
public string result = "";
public string resultPic = "";
int maxx, maxy, maxz;
public Calculator(int x, int y, int z, int max, int cycles)
{
maxx = x;
maxy = y;
maxz = z;
maxEnergy = max;
for (int i = 0; i < cycles; i++)//check few variants per thread
{
Calculate(x,y,z);
}
}
private void Calculate(int X, int Y, int Z)
{
//groups = new List<Group>();
groups = new HashSet<Group>();
reactors = new bool[X, Y, Z];
for (int x = 0; x < X; x++)
{
for (int y = 0; y < Y; y++)
{
for (int z = 0; z < Z; z++)
{
reactors[x, y, z] = rnd.Next(2)==1;//fill array with random values
}
}
}
reactorsChecked = new bool[X, Y, Z];
for (int x = 0; x < X; x++)
{
for (int y = 0; y < Y; y++)
{
for (int z = 0; z < Z; z++)
{
CheckGroup(x, y, z, null);//start calculations
}
}
}
double sum = 0;
int blocks = 0;
foreach(Group g in groups)
{
float dims = g.MaxX - g.MinX + g.MaxY - g.MinY + g.MaxZ - g.MinZ + 3;
sum += (2000000.0f / (1.0f + Math.Pow(1.000696f, (-0.333f * Math.Pow((dims / 3.0f), 1.7)))) - 1000000.0f + 25.0f * g.Blocks);
blocks += g.Blocks;
}
if (sum > maxEnergy)
{
maxEnergy = sum;
reactorsMax = reactors;
}
}
void CheckGroup(int x, int y, int z, Group group)
{
if(x >= maxz || x < 0 || y >= maxy || y < 0 || z >= maxz || z < 0)
{
return;
}
if (reactorsChecked[x, y, z])
{
return;
}
reactorsChecked[x, y, z] = true;
if (reactors[x, y, z])
{
if (group == null)
{
group = new Group();
group.MaxX = x;
group.MaxY = y;
group.MaxZ = z;
group.MinX = x;
group.MinY = y;
group.MinZ = z;
group.Blocks = 1;
}
else
{
group.MaxX = Math.Max(group.MaxX, x);
group.MaxY = Math.Max(group.MaxY, y);
group.MaxZ = Math.Max(group.MaxZ, z);
group.MinX = Math.Min(group.MinX, x);
group.MinY = Math.Min(group.MinY, y);
group.MinZ = Math.Min(group.MinZ, z);
group.Blocks += 1;
}
CheckGroup(x + 1, y, z, group);
CheckGroup(x - 1, y, z, group);
CheckGroup(x, y + 1, z, group);
CheckGroup(x, y - 1, z, group);
CheckGroup(x, y, z + 1, group);
CheckGroup(x, y, z - 1, group);
if (!groups.Contains(group))
{
groups.Add(group);
}
}
}
}
So the main question - is it possible to avoid stackOverflow in Parallel.For, or to rewrite it to iteration loop?
Parallel.For using default stackSize value even if you will use
Thread(()=>
{
Parallel.For(...);
},stackSize).Start()
it will use default values...
I don't like variant like this:
for(int i = 0; i < cpuCount; i++)
{
Thread t = new Thread(()=>{calculate();},stackSize).Start()
}
because I have to manage all threads, wait while all finishes, so it makes code very complicated... May be there are easier things?
There are two options:
to use recursion and try to increase the stack size (by using the Thread(ThreadStart, maxStackSize) constructor). The stack in applications is usually set to 1MB (see this link for details). Especially in DEBUG mode without optimizations (no inlining optimization done) this is a very limited value. Having a thread with separate stack for every Paralllel.For() statement
might help.
Use a iteration look instead of recursion to handle the stack depth by yourself.
I personally would go with option 1. (with or without separate stack) only in case I known the maximum depth of my recursion.
My preferred solution in most cases like yours will be the iteration approach.
Edit by #LordXaosa:
I tried this, and all works fine
int stackSize = 1024*1024*1024;//1GB limit
ManualResetEvent[] mre = new ManualResetEvent[Environment.ProcessorCount];
Parallel.For(0, Environment.ProcessorCount, (i) =>
{
mre[i] = new ManualResetEvent(false);
Thread t = new Thread((object reset) =>
{
Calculator calc = new Calculator(x, y, z, max, cycles);
calcs.Add(calc);
ManualResetEvent m = (ManualResetEvent)reset;
m.Set();
}, stackSize / (Environment.ProcessorCount * 4));
t.Start(mre[i]);
});
WaitHandle.WaitAll(mre);
But there also a limit... 50x50x50 array works fine, but more - stack overflow... In original game it can process 1000x1000x1000 sets, so may be there is another algorithm.
Thanks for your help!
Related
Given the following c# array:
const bool X = true, _ = false;
bool[,] array = new bool[,] {
{ X, X, X, X, _, X, X, X, _, _ },
{ _, _, _, _, _, X, X, X, X, _ },
{ X, X, X, X, X, X, X, X, X, X },
{ X, X, X, X, X, X, X, X, X, X },
{ _, X, X, X, _, X, _, _, X, X },
{ _, X, X, X, _, X, X, _, X, X },
{ _, _, _, X, X, _, _, _, _, _ },
{ X, X, _, X, X, _, X, X, X, _ },
{ _, X, X, _, _, X, X, X, X, X },
{ _, _, X, X, _, _, X, X, X, X },
};
Visually something like this:
Are there any existing methods for converting this to as few rectangular areas as possible?
A possible solution might be something like:
Ideally I'm looking for something that can produce a list of rectangles:
public IEnumerable<Rectangle> ReduceMap(bool[,] map)
{
List<Rectangle> rects = new List<Rectangle>();
int width = map.GetLength(0), height = map.GetLength(1);
// Reduce
// ....?
return rects;
}
The result of which would be something like:
var output = new List<Rectangle>
{
new Rectangle(0, 0, 4, 1),
new Rectangle(5, 0, 3, 2),
new Rectangle(8, 1, 1, 1),
new Rectangle(0, 2, 10, 2),
// ... etc
};
Speed is important too, the fewer rectangles the better, but finding a decent solution should not be overly computationally expensive.
Apologies if this has been answered before, if anyone has any idea where to look that would be great!
This is an interesting problem.
Have you seen the following article it provides good information on this topic and discusses different approaches to this problem (quadtree, morphological, graph):
Rectangular decomposition of binary images
This comes from Ojdo's answer in this question Link
I would start looking there! Hope this helped.
This is the best I can come up with myself, if anyone can improve on this, I'd be happy to mark it as the answer.
This method uses multiple passes to union the array and seems to reduce the array pretty well, roughly in line with my diagrams above, although definitely not optimal.
I've created a fiddle for testing:
https://dotnetfiddle.net/3iuIe6
using System;
using System.Collections.Generic;
using System.Drawing;
public class Program
{
private const string pattern1 = #"
XXXX_XXX__
_____XXXX_
XXXXXXXXXX
XXXXXXXXXX
_XXX_X__XX
_XXX_XX_XX
___XX_____
XX_XX_XXX_
_XX__XXXXX
__XX__XXXX
";
private const string pattern2 = #"
XXXXXXXXXX
XXXXXXXXXX
XXXXXXXXXX
XXXXXXXXXX
XXXXXXXXXX
XXXXXXXXXX
XXXXXXXXXX
XXXXXXXXXX
XXXXXXXXXX
XXXXXXXXXX
";
private const string pattern3 = #"
X_XXXXXXXX
X_XXXXXXXX
X_XXXXXXXX
X_XXXXXXXX
XXXXXXXXXX
XXXXXXXXXX
XXXXXXX_XX
XXXXXXX_XX
XXXXXXX_XX
XXXXXXX_XX
";
private const string pattern4 = #"
X_XXXXXXXX
X_XX__XXXX
X_XXXXXXXX
X_XXXX__XX
XXXXX_XXXX
XXX__XXXXX
XXXX_XX_XX
XXX_XXX_XX
XXXXX_X_XX
XXX_XXX_XX
";
private const string pattern5 = #"
XXXXXXXXXX
__XXXXXXXX
____XXXXXX
_____XXXXX
______XXXX
______XXXX
_____XXXXX
____XXXXXX
__XXXXXXXX
XXXXXXXXXX
";
public static void Main()
{
bool[,] map = PatternTo2DArray(pattern1);
//bool[,] map = PatternTo2DArray(pattern2);
//bool[,] map = PatternTo2DArray(pattern3);
//bool[,] map = PatternTo2DArray(pattern4);
//bool[,] map = PatternTo2DArray(pattern5);
var rects = ReduceMap(map);
int index = 0;
foreach (var rect in rects)
{
Console.WriteLine("{0}: {{ {1}, {2}, {3}, {4} }}", ((index + 1).ToString().PadLeft(1, '0')), rect.X, rect.Y, rect.Width, rect.Height);
index++;
}
var total = DumpMap(map);
Console.WriteLine("\r\nOptimised Map From: {0} to {1}", total, index);
}
public static IEnumerable<Rectangle> ReduceMap(bool[,] map)
{
int width = map.GetLength(0), height = map.GetLength(1);
MapElement[,] bin = new MapElement[width, height];
// Reduce
// Step 1: Convert to map elements:
for (int y = 0; y < height; y++)
for (int x = 0; x < width; x++)
{
if (map[x, y])
bin[x, y] = new MapElement() { X = x, Y = y, Width = 1, Height = 1, Set = true };
}
// Step 2: Process the bin map and generate a collection of Rectangles horizontally
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
// Only care about this if we are set.
if (bin[x, y].Set)
{
// Scan forward and link this tile with its following tiles
int xx = 0;
for (int xForward = x + 1; xForward < width; xForward++)
{
if (!bin[xForward, y].Set)
break;
// We can link this...
bin[xForward, y].Set = false;
bin[x, y].Width++;
xx++; // Skip over these tiles.
}
x += xx;
}
}
}
// Step 3: Process the bin map veritically and join any blocks that have equivalent blocks below them.
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
// Only care about this if we are set.
if (bin[x, y].Set)
{
// Scan down and link this tile with its following tiles
for (int yDown = y + 1; yDown < height; yDown++)
{
if (!bin[x, yDown].Set || bin[x, yDown].Width != bin[x, y].Width) // We might be able to link this if it's the same size
break;
bin[x, yDown].Set = false;
bin[x, y].Height++;
}
}
}
}
// Step 4: Convert map to rectangles
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
// Only care about this if we are set.
if (bin[x, y].Set)
{
var b = bin[x, y];
yield return new Rectangle(b.X, b.Y, b.Width, b.Height);
}
}
}
}
public static int DumpMap(bool[,] map)
{
Console.WriteLine("");
var #out = 0;
int width = map.GetLength(0), height = map.GetLength(1);
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
Console.Write(map[x, y] ? "X" : "_");
#out++;
}
Console.WriteLine();
}
return #out;
}
public static int CountDataPoints(bool[,] map)
{
var #out = 0;
int width = map.GetLength(0), height = map.GetLength(1);
for (int y = 0; y < height; y++)
for (int x = 0; x < width; x++)
if (map[x, y])
#out++;
return #out;
}
public static bool[,] PatternTo2DArray(string pattern)
{
var lines = new List<string>(pattern.Split('\n'));
for (int i = lines.Count - 1; i > -1; i--)
{
string line = lines[i].TrimEnd('\r');
if (line.Length == 0)
lines.RemoveAt(i);
else
lines[i] = line;
}
var #out = new bool[lines[0].Length, lines.Count];
for (int y = 0; y < lines.Count; y++)
{
string line = lines[y];
for (int x = 0; x < line.Length; x++)
{
#out[x, y] = !(line[x] == '_');
}
}
return #out;
}
internal struct MapElement
{
public int X;
public int Y;
public int Width;
public int Height;
public bool Set;
}
}
I just started learning c# however I have some experience with java, so one of the things I wanted to do is to generate a 2d array map filled with 1's and 0's and recursively check if there is a path without stepping on 1's.
However after writing the code and running it it shows me the stack overflow exception error.
Where did I do something wrong?
Edit: the end of the array(the cell with the largest value 9,9(it's a 10x10 array) in this case is set to 6 as the end point)
Code for the recursive method:
public static int recursiveCheck(int[,] grid,int x, int y, int finalX, int finalY, int paths)
{
if (grid[x, y] == 6)
{
paths++;
return paths;
}
if ((grid[x + 1, y] != 1) && (x+1 < finalX))
return recursiveCheck(grid, x + 1, y, finalX, finalY, paths);
if ((grid[x, y+1] != 1) && (y+1 < finalY))
return recursiveCheck(grid, x, y+1, finalX, finalY, paths);
if ((grid[x - 1, y] != 1) && (x > 0))
return recursiveCheck(grid, x - 1, y, finalX, finalY, paths);
if (grid[x, y - 1] != 1 && y >0)
return recursiveCheck(grid, x, y - 1, finalX, finalY, paths);
return 0;
}
Array Initialization code:
public static int[,] gridGen()
{
int[,] grid = new int[10, 10];
Random rnd = new Random();
int lim;
for (int i = 0; i < 10; i++)
{
for (int c = 0; c < 10; c++)
{
lim = rnd.Next(0, 2);
//Console.WriteLine($"lim: {lim} ");
grid[i, c] = lim;
}
}
grid[0, 0] = 2;
grid[grid.GetLength(0) - 1, grid.GetLength(1) - 1] = 6;
for (int i = 0; i < 10; i++)
{
for (int c = 0; c < 10; c++)
{
Console.Write(grid[i, c] + " ");
}
Console.WriteLine();
}
return grid;
}
You're not keeping track of which spaces you've already visited. So supposing your grid has two zeros right next to each other, your function will move to one in the first level of recursion, then to the other in the second level, then back to the first in the third level (even though the first level of recursion is still on the stack) and so forth forever.
There are a number of ways that you could keep track of where you've already visited. If you're willing to modify the input array temporarily when this method is called, you could just set the space you're currently on to 1 before looking at the ones around it.
public static int recursiveCheck(int[,] grid,int x, int y, int finalX, int finalY, int paths)
{
var originalValue = grid[x, y];
if (originalValue == 6)
{
paths++;
return paths;
}
grid[x, y] = 1; // prevent deeper recursion from coming back to this space
if ((grid[x + 1, y] != 1) && (x+1 < finalX))
return recursiveCheck(grid, x + 1, y, finalX, finalY, paths);
if ((grid[x, y+1] != 1) && (y+1 < finalY))
return recursiveCheck(grid, x, y+1, finalX, finalY, paths);
if ((grid[x - 1, y] != 1) && (x > 0))
return recursiveCheck(grid, x - 1, y, finalX, finalY, paths);
if (grid[x, y - 1] != 1 && y >0)
return recursiveCheck(grid, x, y - 1, finalX, finalY, paths);
grid[x, y] = originalValue; // allow other path checking to revisit this space.
return 0;
}
Also note that you can probably simplify things a little bit by turning the recursion upside down a little: do your boundary checks and wall checks as exit criteria right away, and use the number of paths purely as a return value rather than an input.
public static int recursiveCheck(int[,] grid, int x, int y, int finalX, int finalY)
{
if(x < 0 || x > finalX || y < 0 || y > finalY)
{
return 0;
}
var originalValue = grid[x, y];
if (originalValue == 1)
{
return 0;
}
if (originalValue == 6)
{
return 1;
}
grid[x, y] = 1; // prevent deeper recursion from coming back to this space
var paths = recursiveCheck(grid, x + 1, y, finalX, finalY)
+ recursiveCheck(grid, x, y + 1, finalX, finalY)
+ recursiveCheck(grid, x - 1, y, finalX, finalY)
+ recursiveCheck(grid, x, y - 1, finalX, finalY);
grid[x, y] = originalValue; // allow other path checking to revisit this space.
return paths;
}
Here's another way of doing it.
Start with a function that returns the valid neighbours of a specific location in the grid:
private IEnumerable<(int r, int c)> GetNeighbours(int[,] grid, (int r, int c) reference)
{
for (int i = -1; i <= 1; i++)
for (int j = -1; j <= 1; j++)
{
var neighbour = (r: reference.r + i, c: reference.c + j);
if ((i != 0 && j != 0)
|| neighbour == reference
|| neighbour.r < 0 || neighbour.r >= grid.GetLength(0)
|| neighbour.c < 0 || neighbour.c >= grid.GetLength(1))
{
continue;
}
yield return neighbour;
}
}
This returns the left, right, up, and down neighbour so long as it is in the valid grid.
Then we'll make a public method that triggers off the building of a path:
public List<(int r, int c)> RecursiveCheck(int[,] grid, (int r, int c) initial, int goal)
{
var path = new List<(int r, int c)>(new[] { initial });
return RecursiveCheck(grid, path, goal);
}
Its purpose is to take the initial starting point and turn that in to a path of one element and then it calls the true recursive function.
And here it is:
private List<(int r, int c)> RecursiveCheck(int[,] grid, List<(int r, int c)> path, int goal)
{
foreach (var neighbour in GetNeighbours(grid, path.Last()))
{
if (!path.Contains(neighbour))
{
var next = path.Concat(new[] { neighbour }).ToList();
if (grid[neighbour.r, neighbour.c] == goal)
{
return next;
}
else if (grid[neighbour.r, neighbour.c] == 0)
{
return RecursiveCheck(grid, next, goal);
}
}
}
return new List<(int r, int c)>();
}
This takes the existing path, finds all of neighbours of the last element in the path. It checks that it hasn't visited those neighbours and then builds the next path. It then checks if it hits the goal, and if so, returns the path. Otherwise if the current cell has the value 0 it then recurses to find a solution. If it can't find a solution it returns an empty path.
Here's an example usage:
int[,] grid = new int[3, 5]
{
{ 0, 1, 0, 0, 0},
{ 0, 1, 0, 1, 0},
{ 0, 0, 0, 1, 6},
};
List<(int r, int c)> path = RecursiveCheck(grid, (r: 0, c: 0), 6);
Console.WriteLine(path.Count);
That outputs 11 (which is the correct length to find the 6 from the top-left).
I want to split a matrix into quadrants, upper and bottom left and right, according to the current position. Here is an example(to avoid writing T/U, for example, I placed the different characters with top and left priority, but they do overlap):
o T T U o o o
B T X U L L L
B B B L L L L
B B B L L L L
o o L L L L L
o o L L L L L
X is the central element. o is an element not included in any of the quadrants, T is top left, U is top right, B is lower left and L is lower right, I hope you get the idea. My solution includes checking in which quadrant of the matrix the starting position is, and then making the quadrants accordingly, which makes a total of 4 cases each with 4 quadrants = 16. I hope there's a better way, so can you please help me with this? I'm writing the program in C#, but pseudocode is fine.
You can access the different quadrant of cartesian system through their respective property.
public class Matrix<T>
{
public T[,] Elements { get; private set; }
public int Size { get; private set; }
public Point CentralPoint { get; set; }
public T this [int y, int x]
{
get { return Elements[y, x]; }
set { Elements[y, x] = value; }
}
public Matrix(int size)
{
this.Size = size;
this.Elements = new T[Size, Size];
}
public T[,] FirstQuadrant { get { return FromCentralTo(Size - 1, 0); } }
public T[,] SecondQuadrant { get { return FromCentralTo(0, 0); } }
public T[,] ThirdQuadrant { get { return FromCentralTo(0, Size - 1); } }
public T[,] FourthQuadrant { get { return FromCentralTo(Size - 1 , Size - 1); } }
private T[,] FromCentralTo(int x1, int y1, [CallerMemberName]string caller = "")
{
var translate = Math.Min(Math.Abs(CentralPoint.X - x1), Math.Abs(CentralPoint.Y - y1));
//fix the p1, so this results in a square array
if (Math.Abs(CentralPoint.X - x1) > translate)
x1 = CentralPoint.X + translate * Math.Sign(x1 - CentralPoint.X);
if (Math.Abs(CentralPoint.Y - y1) > translate)
y1 = CentralPoint.Y + translate * Math.Sign(y1 - CentralPoint.Y);
var size = translate + 1;
var start = new Point(Math.Min(CentralPoint.Y, y1), Math.Min(CentralPoint.X, x1));
var result = new T[size, size];
for (int x = 0; x < size; x++)
for (int y = 0; y < size; y++)
result[y, x] = this[start.Y + y, start.X + x];
return result;
}
}
public struct Point
{
public int X, Y;
public Point(int y, int x) { this.X = x; this.Y = y; }
}
void Main()
{
var matrix = new Matrix<int>(7);
matrix.CentralPoint = new Point(1, 2);
int i = 0;
for(int x = 0; x < 7; x++)
for (int y = 0; y < 7; y++)
matrix[x, y] = i++;
matrix.Elements.Dump("Matrix");
matrix[matrix.CentralPoint.Y, matrix.CentralPoint.X].Dump("Central");
matrix.FirstQuadrant.Dump("1");
matrix.SecondQuadrant.Dump("2");
matrix.ThirdQuadrant.Dump("3");
matrix.FourthQuadrant.Dump("4");
}
The above code produce the following in LINQPad :
I have a 3d-array double[,,] numbers = new double[x,y,z]; and now if one imagines the 3d-array to look like a cube with numbers I need to find the smallest and biggest value of every slice along all three directions.
It is of course easy to do by simply looping over it, but does C# have any functions to find the smallest and biggest value in a slice?
To explain it a bit further, maybe this "unreal" code will help:
int i;
double[] xmin = new double[x];
double[] xmax = new double[x];
double[] ymin = new double[y];
double[] ymax = new double[y];
double[] zmin = new double[z];
double[] zmax = new double[z];
for(i = 0; i < x; i++)
{
MinOf(numbers[i, y, z]) = xmin[i];
MaxOf(numbers[i, y, z]) = xmax[i];
}
for(i = 0; i < y; i++)
{
MinOf(numbers[x, i, z]) = ymin[i];
MaxOf(numbers[x, i, z]) = ymax[i];
}
for(i = 0; i < z; i++)
{
MinOf(numbers[x, y, i]) = zmin[i];
MaxOf(numbers[x, y, i]) = zmax[i];
}
Hopefully someone can help me with that.
Cheers, Phil13131
You can make methods for enumerating the slices. This is for one dimension, you would need another two, but I think you can manage that:
public static IEnumerable<T> SliceX<T>(T[,,] data, int x) {
for (int y = 0; y < data.GetLength(1); y++) {
for (int z = 0; z < data.GetLength(2); z++) {
yield return data[x, y, z];
}
}
}
Then you can just use the Min and Max methods, but that will of course loop through the data twice:
double min = SliceX(numbers, x).Min();
double max = SliceX(numbers, x).Max();
You can make an extension method that gets both min and max in one iteration:
public static class IEnumerableExtensions {
public static void GetMinMax<T>(this IEnumerable<T> data, out T min, out T max) where T : IComparable<T> {
bool first = true;
min = max = default(T);
foreach (T value in data) {
if (first) {
min = max = value;
first = false;
} else {
if (value.CompareTo(min) < 0) min = value;
if (value.CompareTo(max) > 0) max = value;
}
}
}
}
Usage:
double min, max;
SliceX(numbers, 0).GetMinMax(out min, out max);
Are you looking for something like this?
double[, ,] numbers = new double[2, 2, 2];
numbers[0, 0, 0] = 0;
numbers[0, 0, 1] = 1;
numbers[0, 1, 0] = 2;
numbers[0, 1, 1] = 3;
numbers[1, 0, 0] = 4;
numbers[1, 0, 1] = 5;
numbers[1, 1, 0] = 6;
numbers[1, 1, 1] = 7;
double[] xmax = new double[numbers.GetLength(0)];
double[] ymax = new double[numbers.GetLength(1)];
double[] zmax = new double[numbers.GetLength(2)];
for (int x = 0; x < xmax.Length; x++) xmax[x] = int.MinValue;
for (int y = 0; y < ymax.Length; y++) ymax[y] = int.MinValue;
for (int z = 0; z < zmax.Length; z++) zmax[z] = int.MinValue;
for (int x = 0; x < xmax.Length; x++)
for (int y = 0; y < ymax.Length; y++)
for (int z = 0; z < zmax.Length; z++)
{
xmax[x] = Math.Max(xmax[x], numbers[x, y, z]);
ymax[y] = Math.Max(ymax[y], numbers[x, y, z]);
zmax[z] = Math.Max(zmax[z], numbers[x, y, z]);
}
// xmax == { 3, 7 }
// ymax == { 5, 7 }
// zmax == { 6, 7 }
Hi i just write function in C# that generate coordinate for cube but the problem i want just
generate the coordinate of cube sides not in the depth !!!
static class Util
{
public static List<string> GenerateCubeCoord(double bc,int nt,double stp)
{
List<string> list = new List<string>();
double CoorBase = bc;
int n = nt;
double step = stp;
int id = 1;
for (int x = 0; x < n; x++)
{
for (int y = 0; y < n; y++)
{
for (int z = 0; z < n; z++)
{
list.Add(string.Format("GRID {0} {1}.0 {2}.0 {3}.0 \n",
id, step * x + CoorBase, step * y + CoorBase, step * z + CoorBase));
id++;
}
}
}
return list;
}
}
I wat to generate all this coordinate not the corner coordinates of cube , in the image one
side of may cube
Without changing your code too much (assuming you meant all corner points, it's a little unclear):
for (int x = 0; x <= n; x += n)
for (int y = 0; y <= n; y += n)
for (int z = 0; z <= n; z += n)
Console.WriteLine("{0} {1} {2}", x, y, z);
A little cleaner using LINQ:
int n = 6;
var coords = from x in new[] { 0, n }
from y in new[] { 0, n }
from z in new[] { 0, n }
select new { x, y, z };
foreach(var coord in coords)
Console.WriteLine("{0} {1} {2}", coord.x, coord.y, coord.z);
Edit after updated question:
If you just want the coordinates of the sides, the allowed values for one coordinate (x,y or z) are either 0 or n-1:
var coords = from x in new[] { 0, n-1 }
from y in Enumerable.Range(0, n)
from z in Enumerable.Range(0, n)
select new { x, y, z };
Rinse and repeat for the other two and you have the set of coordinates for all 6 sides.
Edit:
With above solution there are overlaps between the different sides (the edge points), so you'd have to use the union of all 3 collections. A better solution is to query for all coordinates in one go:
var coords = from x in Enumerable.Range(0, n)
from y in Enumerable.Range(0, n)
from z in Enumerable.Range(0, n)
where ( x == 0 || x==n-1 || y == 0 || y== n-1 || z == 0 || z== n-1)
select new { x, y, z };