I began setting up my system by taking the Grid system supplied by Pack publishing (). This is how it's initialized:
public class Point
{
public int X { get; set; }
public int Y { get; set; }
public Point(int x, int y)
{
this.X = x;
this.Y = y;
}
public override bool Equals(object obj)
{
if (obj == null)
{
return false;
}
if (obj is Point)
{
Point p = obj as Point;
return this.X == p.X && this.Y == p.Y;
}
return false;
}
public override int GetHashCode()
{
unchecked
{
int hash = 6949;
hash = hash * 7907 + X.GetHashCode();
hash = hash * 7907 + Y.GetHashCode();
return hash;
}
}
public override string ToString()
{
return "P(" + this.X + ", " + this.Y + ")";
}
}
public enum CellType
{
Empty,
Road,
Structure,
SpecialStructure,
None
}
public class Grid
{
private CellType[,] _grid;
private int _width;
public int Width { get { return _width; } }
private int _height;
public int Height { get { return _height; } }
private List<Point> _roadList = new List<Point>();
private List<Point> _specialStructure = new List<Point>();
private List<Point> _houseStructure = new List<Point>();
public Grid(int width, int height)
{
_width = width;
_height = height;
_grid = new CellType[width, height];
}
public enum CellType
{
Empty,
Road,
Structure,
SpecialStructure,
None
}
public class Grid
{
private CellType[,] _grid;
private int _width;
public int Width { get { return _width; } }
private int _height;
public int Height { get { return _height; } }
private List<Point> _roadList = new List<Point>();
private List<Point> _specialStructure = new List<Point>();
private List<Point> _houseStructure = new List<Point>();
public Grid(int width, int height)
{
_width = width;
_height = height;
_grid = new CellType[width, height];
}
public void Update()
{
Console.Write("GRID IS RUNNING");
}
// Adding index operator to our Grid class so that we can use grid[][] to access specific cell from our grid.
public CellType this[int i, int j]
{
get
{
return _grid[i, j];
}
set
{
if (value == CellType.Road)
{
_roadList.Add(new Point(i, j));
}
if (value == CellType.SpecialStructure)
{
_specialStructure.Add(new Point(i, j));
}
if (value == CellType.Structure)
{
_houseStructure.Add(new Point(i, j));
}
_grid[i, j] = value;
}
}
After I initialized it, I called it from another function like this.
public int width, height;
Grid placementGrid;
private void Start()
{
placementGrid = new Grid(width, height);
Debug.Log(placementGrid.GetRandomRoadPoint());
}
It seems to initialize perfectly. But when I call the functions inside it, I'm returned a null value. I tried calling this function for example:
public Point GetRandomRoadPoint()
{
if (_roadList.Count == 0)
{
return null;
}
return _roadList[UnityEngine.Random.Range(0, _roadList.Count)];
}
I have no idea what I'm doing wrong. I'm basically trying to create a pedestrian AI system for my procedurally generated town.
I tried debugging several times, but I can't seem to find my way around it.
I am trying to create a custom texture class, and I want to be able to choose if I the texture is 8bit or float a.k.a I want to be able to set _buffer to be either RGBFloat[] or RGBByte[] but I cant figure out how to do it with out making the whole class generic but if I do it generic it will be possible to set other object types other then just the ones that I want to limit it to. Maybe its possible to use inheritance or interface in some way, I don't know.
Example C# Code: (the places with T are not correct, just placeholder)
public struct RGBFloat
{
public float R { get; }
public float G { get; }
public float B { get; }
public RGBFloat(float r, float g, float b)
{
R = r;
G = g;
B = b;
}
}
public struct RGBByte
{
public byte R { get; }
public byte G { get; }
public byte B { get; }
public RGBByte(byte r, byte g, byte b)
{
R = r;
G = g;
B = b;
}
}
public enum TextureFormat
{
RGBFloat,
RGBByte
}
public class Texture2D
{
public int Width { get; }
public int Height { get; }
private T[] _buffer; // want it to be able to be either RGBFloat[] or RGBByte[] but nothing else.
public Texture2D(int width, int height, TextureFormat textureFormat)
{
Width = width;
Height = height;
switch (textureFormat)
{
case TextureFormat.RGBFloat:
_buffer = new RGBFloat[width * height];
break;
default:
_buffer = new RGBByte[width * height];
break;
}
}
public T this[int i]
{
get { return (_buffer[i]); }
set { _buffer[i] = value; }
}
public T this[int x, int y]
{
get { return (_buffer[Width * y + x]); }
set { _buffer[Width * y + x] = value; }
}
}
Example of a working generic class I have created that is similar to my TextureClass but this one is meant to be able to support any object type.
public class Computebuffer<T>
{
public int Count { get; }
private T[] _buffer;
public Computebuffer(int count)
{
Count = count;
_buffer = new T[count];
}
public T this[int i]
{
get { return (_buffer[i]); }
set { _buffer[i] = value; }
}
public void Initialize(T value)
{
for (int i = 0; i < Count; i++)
{
_buffer[i] = value;
}
}
public void SetData(T[] data)
{
for (int i = 0; i < data.Length; i++)
{
_buffer[i] = data[i];
}
}
public void GetData(T[] data)
{
for (int i = 0; i < data.Length; i++)
{
data[i] = _buffer[i];
}
}
public void Clear()
{
_buffer = new T[Count];
}
}
EDIT 1: (Updated version, almost working):
Issue: With this code I am able to add a RGBFloat to a Texture2D and that doesn't make sense. (see main program)
public interface IRGBType { }
public struct RGBFloat : IRGBType
{
public float R { get; }
public float G { get; }
public float B { get; }
public RGBFloat(float r, float g, float b)
{
R = r;
G = g;
B = b;
}
}
public struct RGBByte : IRGBType
{
public byte R { get; }
public byte G { get; }
public byte B { get; }
public RGBByte(byte r, byte g, byte b)
{
R = r;
G = g;
B = b;
}
}
public class Texture2D<T> where T : struct, IRGBType
{
public int Width { get; }
public int Height { get; }
private IRGBType[] _buffer;
public Texture2D(int width, int height)
{
Width = width;
Height = height;
_buffer = new IRGBType[width * height];
Initialize();
}
private void Initialize()
{
Type type = this.GetType();
if (type == typeof(RGBByte))
{
for (int i = 0; i < Width * Height; i++)
{
_buffer[i] = new RGBByte(0, 0, 0);
}
}
else
{
for (int i = 0; i < Width * Height; i++)
{
_buffer[i] = new RGBFloat(0, 0, 0);
}
}
}
public IRGBType this[int i]
{
get { return (_buffer[i]); }
set { _buffer[i] = value; }
}
public IRGBType this[int x, int y]
{
get { return (_buffer[Width * y + x]); }
set { _buffer[Width * y + x] = value; }
}
}
MainProgram:
Texture2D<RGBFloat> texFloat = new Texture2D<RGBFloat>(64, 64);
Texture2D<RGBByte> texByte = new Texture2D<RGBByte>(64, 64);
texFloat[32, 32] = new RGBFloat(10, 50, 60);
texByte[32, 32] = new RGBFloat(0.9f, 0.24f, 0.5f); // this should not work I should not be able to add a RGBFloat to a RGBByte Texture2D
EDIT 2: (Updated version v3) still one issue, how would I Initialize _buffer array with an optional value, so new Texture2D<RGBFloat>(64, 64) should Initialize with new RGBFloat(0,0,0) and Texture2D<RGBFloat>(64, 64, new RGBFloat(0.5f,0.6f,0.7f)) should Initialize with value provided:
public class Texture2D<T> where T : struct, IRGBType
{
public int Width { get; }
public int Height { get; }
private T[] _buffer;
public Texture2D(int width, int height, T? initializeValue = null)
{
Width = width;
Height = height;
_buffer = new T[width * height];
Initialize(initializeValue);
}
private void Initialize(T? value)
{
Type type = this.GetType();
T rgb;
if (type == typeof(RGBFloat))
{
rgb = value ?? new RGBFloat(0, 0, 0); // Error: Operator '??' cannot be applied to operands of type 'T' and 'RGBFloat'
}
else
{
rgb = value ?? new RGBByte(0, 0, 0); // Error: Operator '??' cannot be applied to operands of type 'T' and 'RGBByte'
}
for(int i = 0; i < Width*Height; i++)
{
_buffer[i] = rgb;
}
}
public T this[int i]
{
get { return (_buffer[i]); }
set { _buffer[i] = value; }
}
public T this[int x, int y]
{
get { return (_buffer[Width * y + x]); }
set { _buffer[Width * y + x] = value; }
}
}
EDIT 3: The full final version that now works correctly:
public interface IRGBType { }
public struct RGBFloat : IRGBType
{
public float R { get; }
public float G { get; }
public float B { get; }
public RGBFloat(float r, float g, float b)
{
R = r;
G = g;
B = b;
}
}
public struct RGBByte : IRGBType
{
public byte R { get; }
public byte G { get; }
public byte B { get; }
public RGBByte(byte r, byte g, byte b)
{
R = r;
G = g;
B = b;
}
}
public class Texture2D<T> where T : struct, IRGBType
{
public int Width { get; }
public int Height { get; }
private T[] _buffer;
public Texture2D(int width, int height, T? initializeValue = null)
{
Width = width;
Height = height;
_buffer = new T[width * height];
if (initializeValue.HasValue)
{
for (int i = 0; i < Width * Height; i++)
{
_buffer[i] = initializeValue.Value;
}
};
}
public T this[int i]
{
get { return (_buffer[i]); }
set { _buffer[i] = value; }
}
public T this[int x, int y]
{
get { return (_buffer[Width * y + x]); }
set { _buffer[Width * y + x] = value; }
}
}
}
You can create an interface that your RGBFloat and RGBByte structs implement, and limit the generic type to that interface. The interface can just be a "marker", with nothing in it:
public interface IRGBType { }
public struct RGBFloat : IRGBType
{
public float R { get; }
public float G { get; }
public float B { get; }
public RGBFloat(float r, float g, float b)
{
R = r;
G = g;
B = b;
}
}
public struct RGBByte : IRGBType
{
public byte R { get; }
public byte G { get; }
public byte B { get; }
public RGBByte(byte r, byte g, byte b)
{
R = r;
G = g;
B = b;
}
}
You can then have your generic class only accept types that implement this interface:
public class Texture2D<T> where T: IRGBType
{
...
}
If you know that you'll always have this interface implemented by a struct, you can further restrict the generic:
public class Texture2D<T> where T: struct, IRGBType
{
...
}
EDIT: Make sure to use the generic T parameter everywhere in your class, not the interface. This is necessary to ensure type safety, otherwise your indexers can accept any IRGBType, which can be very problematic. Correct usage:
public class Texture2D<T> where T: struct, IRGBType
{
private T[] _buffer;
public Texture2D(int width, int height)
{
...
_buffer = new T[width * height];
...
}
public T this[int i]
{
get => _buffer[i];
set => _buffer[i] = value;
}
}
You can try using only one generic struct like this:
public struct RGB<T>
where T : struct,
IComparable, IFormattable, IConvertible,
IComparable<T>, IEquatable<T>
{
public T R { get; }
public T G { get; }
public T B { get; }
public RGB(T r, T g, T b)
{
R = r;
G = g;
B = b;
}
}
public class RGBComputeBuffer<T>
where T : struct,
IComparable, IFormattable, IConvertible,
IComparable<T>, IEquatable<T>
{
public int Count { get; private set; }
private RGB<T>[] _buffer;
public RGBComputeBuffer(int count)
{
_buffer = new RGB<T>[count];
Count = count;
}
public RGB<T> this[int i]
{
get { return _buffer[i]; }
set { if ( !_buffer[i].Equals(value) ) _buffer[i] = value; }
}
public void Initialize(RGB<T> value)
{
for ( int i = 0; i < Count; i++ )
_buffer[i] = value;
}
public void SetData(RGB<T>[] data)
{
Array.Resize(ref _buffer, data.Length);
Count = data.Length;
for ( int i = 0; i < data.Length; i++ )
_buffer[i] = data[i];
}
public void GetData(RGB<T>[] data)
{
Array.Resize(ref data, _buffer.Length);
for ( int i = 0; i < data.Length; i++ )
data[i] = _buffer[i];
}
public void Clear()
{
_buffer = new RGB<T>[Count];
}
}
Example of usage:
var bufferOfRGBByte = new RGBCompositeBuffer<byte>(100);
var bufferOfRGBFloat = new RGBCompositeBuffer<float>(100);
An interface would be your best bet. By having RGBFloat and RGBByte implement an interface then you can use that interface type in your array. It will also allow adding other RGB types later.
public interface IRGB
{
}
public struct RGBFloat : IRGB
{
public float R { get; }
public float G { get; }
public float B { get; }
public RGBFloat(float r, float g, float b)
{
R = r;
G = g;
B = b;
}
}
public struct RGBByte : IRGB
{
public byte R { get; }
public byte G { get; }
public byte B { get; }
public RGBByte(byte r, byte g, byte b)
{
R = r;
G = g;
B = b;
}
}
public enum TextureFormat
{
RGBFloat,
RGBByte
}
public class Texture2D
{
public int Width { get; }
public int Height { get; }
private IRGB[] _buffer; // want it to be able to be either RGBFloat[] or RGBByte[] but nothing else.
public Texture2D(int width, int height, TextureFormat textureFormat)
{
Width = width;
Height = height;
switch (textureFormat)
{
case TextureFormat.RGBFloat:
_buffer = new IRGB[width * height];
break;
default:
_buffer = new IRGB[width * height];
break;
}
}
public IRGB this[int i]
{
get { return (_buffer[i]); }
set { _buffer[i] = value; }
}
public IRGB this[int x, int y]
{
get { return (_buffer[Width * y + x]); }
set { _buffer[Width * y + x] = value; }
}
}
If you want to access the R,G,B variables however you may need to add some kind of accessor methods/properties to the interface.
How can I call the parameter which is inside the method instance in the other class, as I want to make a calculation with the method and display it.
class Box
{
int width = 10;
int height = 15;
public int Area(int Area)
{
Area = width * height;
return Area;
}
public int Perimeter(int Para)
{
Para = 2 * (height + width);
return Para;
}
}
\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
static void Main(string[] args)
{
Box b = new Box();
b.Area(Area);
b.Perimeter(Para);
Console.ReadLine();
}
It is giving me en error on b.Area(Area); and b.Perimeter(Para);
Maybe you wanted to do this:
class Program
{
static void Main(string[] args)
{
Box box = new Box(10, 15);
Console.WriteLine("Area is: " + box.CalculateArea());
Console.WriteLine("Perimeter is: " + box.CalculatePerimeter());
Console.ReadLine();
}
}
public class Box
{
public int Width { get; set; }
public int Height { get; set; }
public Box(int width, int height)
{
Width = width;
Height = height;
}
public int CalculateArea()
{
return Width * Height;
}
public int CalculatePerimeter()
{
return 2 * (Width + Height);
}
}
This is the static array I have been given in making a RPN calculator. From this code the RPN calculator adds and subtracts. Now I need to extend my code to multiply and divide but I cant I don't know how.
public class IntStack
{
private const int maxsize = 10;
private int top = 0;
private int[] array = new int[maxsize];
public void Push(int value)
{
array[top++] = value;
}
public int Pop()
{
return array[--top];
}
public int Peek()
{
return array[top - 1];
}
public bool IsEmpty()
{
return top == 0;
}
public bool IsFull()
{
return top == maxsize;
}
public string Print()
{
StringBuilder output = new StringBuilder();
for (int i = top - 1; i >= 0; i--)
output.Append(array[i] + Environment.NewLine);
return output.ToString();
}
}
Here are some methods you can add to your IntStack class that will perform the multiply and division operations. I've added minimal error checking.
public void Multiply()
{
if (array.Length < 2)
return;
var factor1 = Pop();
var factor2 = Pop();
Push(factor1 * factor2);
}
public void Divide()
{
if (array.Length < 2)
return;
var numerator = Pop();
var divisor = Pop();
if (divisor == 0) { // Return stack back to original state.
Push(divisor);
Push(numerator);
return;
}
Push(numerator / divisor);
}
I'm doing K-means clustering of n points and k centers.
To start off, here's my code so far:
A class for a point:
public class Point
{
public int Id { get; set; }
public double X { get; set; }
public double Y { get; set; }
public Point()
{
Id = -1;
X = -1;
Y = -1;
}
public Point(int id, double x, double y)
{
this.Id = id;
this.X = x;
this.Y = y;
}
public static double FindDistance(Point pt1, Point pt2)
{
double x1 = pt1.X, y1 = pt1.Y;
double x2 = pt2.X, y2 = pt2.Y;
double distance = Math.Sqrt(Math.Pow(x2 - x1, 2.0) + Math.Pow(y2 - y1, 2.0));
return (distance);
}
}
A class for data:
public class PointCollection : List<Point>
{
public Point Centroid { get; set; }
public PointCollection()
: base()
{
Centroid = new Point();
}
public void AddPoint(Point p)
{
this.Add(p);
UpdateCentroid();
}
public Point RemovePoint(Point p)
{
Point removedPoint = new Point(p.Id, p.X, p.Y);
this.Remove(p);
UpdateCentroid();
return (removedPoint);
}
public void UpdateCentroid()
{
double xSum = (from p in this select p.X).Sum();
double ySum = (from p in this select p.Y).Sum();
Centroid.X = (xSum / (double)this.Count);
Centroid.Y = (ySum / (double)this.Count);
}
}
Main class:
public class KMeans
{
public static List<PointCollection> DoKMeans(PointCollection points, int clusterCount)
{
List<PointCollection> allClusters = new List<PointCollection>();
List<List<Point>> allGroups = ListUtility.SplitList<Point>(points, clusterCount);
foreach (List<Point> group in allGroups)
{
PointCollection cluster = new PointCollection();
cluster.AddRange(group);
allClusters.Add(cluster);
}
int movements = 1;
while (movements > 0)
{
movements = 0;
foreach (PointCollection cluster in allClusters)
{
for (int pointIndex = 0; pointIndex < cluster.Count; pointIndex++)
{
Point point = cluster[pointIndex];
int nearestCluster = FindNearestCluster(allClusters, point);
if (nearestCluster != allClusters.IndexOf(cluster))
{
if (cluster.Count > 1)
{
Point removedPoint = cluster.RemovePoint(point);
allClusters[nearestCluster].AddPoint(removedPoint);
movements += 1;
}
}
}
}
}
return (allClusters);
}
public static int FindNearestCluster(List<PointCollection> allClusters, Point point)
{
double minimumDistance = 0.0;
int nearestClusterIndex = -1;
for (int k = 0; k < allClusters.Count; k++)
{
double distance = Point.FindDistance(point, allClusters[k].Centroid);
if (k == 0)
{
minimumDistance = distance;
nearestClusterIndex = 0;
}
else if (minimumDistance > distance)
{
minimumDistance = distance;
nearestClusterIndex = k;
}
}
return (nearestClusterIndex);
}
}
And finally helping function for list split:
public static List<List<T>> SplitList<T>(List<T> items, int groupCount)
{
List<List<T>> allGroups = new List<List<T>>();
int startIndex = 0;
int groupLength = (int)Math.Round((double)items.Count / (double)groupCount, 0);
while (startIndex < items.Count)
{
List<T> group = new List<T>();
group.AddRange(items.GetRange(startIndex, groupLength));
startIndex += groupLength;
if (startIndex + groupLength > items.Count)
{
groupLength = items.Count - startIndex;
}
allGroups.Add(group);
}
if (allGroups.Count > groupCount && allGroups.Count > 2)
{
allGroups[allGroups.Count - 2].AddRange(allGroups.Last());
allGroups.RemoveAt(allGroups.Count - 1);
}
return (allGroups);
}
So, now I'm trying to write a second method for the main class, which would accept a predefined starting centres. I have trouble grasping that though, as I can't find anything on the internet where the k-means algorithm would use initial centers. Can someone point me in a direction of such guide or give me any ideas how to modify the code? Thanks.
Edit: Maybe something more why am I trying to do this: I try to write LBG algorithm using k-means, like so https://onlinecourses.science.psu.edu/stat557/node/67
I can access the computed centers for splitting in each of the steps with my code, however I need to find a way to feed them back to the k-means class. Like, if I calculated the starting centre, i need to put this centre and another offset by epsilon into k-means algorithm.
Edit2: Code now in English(I hope)
Found a solution, maybe someone will use:
public static List<PointCollection> DoKMeans(PointCollection points, int clusterCount, Point[] startingCentres)
{
// code...
int ctr = 0;
foreach (List<Point> group in allGroups)
{
PointCollection cluster = new PointCollection();
cluster.c.X = startingCentres[ctr].X;
cluster.c.Y = startingCentres[ctr].Y;
cluster.AddRange(group);
allClusters.Add(cluster);
}
// rest of code the same
}