Grid Algorithm, similar to WPF Grid - c#
Edit
Upon further reading and experimenting my reformulated questions :
How do I measure a Star Column Contents, specially when the contents of the grid can span multiple Cols/Rows?
If I have a Control that is inside Col 0, and it spans 2 cols.
and Col 0 is a Star Col, what size would the column actually take?
Or am I missing something?
EDIT:
Since it seems I didnt explain myself well enough, what I actually need to do is find how to make each of the contents mesure themselfs and report back to the actual Col/Row. My issues is mostly, what happens when a control spans multiple rows, I might be missing something on the grid actually works.
I would like to implement a GRID similar to WPF Grid, but I am having trouble understanding how the algoritm to Mesure the Grid actually works, currently I have something like this :
protected override Size MesureOverride(Size s)
{
int colCount = Columns.Count;
int rowCount = Rows.Count;
bool emptyRows = rowCount == 0;
bool emptyCol = colCount == 0;
if (emptyRows)
rowCount = 1;
if (emptyCol)
colCount = 1;
rows = new GridSegment[rowCount];
cols = new GridSegment[colCount];
if (float.IsNaN(s.Width))
{
//We are trying to mesure our size top
//Find what our contents width is
}
if (float.IsNaN(s.Height))
{
//find what our contents height is
}
CreateCells(s, emptyRows, rows, cols, emptyCol);
float gridWidth = 0;
float gridHeight = 0;
foreach (var col in cols)
{
gridWidth += col.DesiredSize;
}
foreach (var row in rows)
{
gridHeight += row.DesiredSize;
}
float mesureHeight = 0f;
float mesureWidth = 0f;
foreach (var v in this.Childreen)
{
var layoutInfo = v.Layout<GridLayoutInfo>();
var rowspan = layoutInfo.RowSpan;
var colspan = layoutInfo.ColumSpan;
float width = 0;
float height = 0;
float x = 0;
float y = 0;
if (rowspan < 1)
rowspan = 1;
if (colspan < 1)
colspan = 0;
for (int i = 0; i < layoutInfo.Row + rowspan && i < rowCount; i++)
{
if (i > 0 && i <= layoutInfo.Row)
y += rows[i - 1].DesiredSize;
if (i >= layoutInfo.Row)
height += rows[i].DesiredSize;
}
for (int i = 0; i < layoutInfo.Column + colspan && i < colCount; i++)
{
if (i > 0 && i <= layoutInfo.Column)
x += cols[i - 1].DesiredSize;
if (i >= layoutInfo.Column)
width += cols[i].DesiredSize;
}
v.Mesure(new Size(width,height));
//Calculate the grid size
}
return new Size(gridWidth, gridHeight);
}
private void CreateCells(Size s, bool emptyRows, GridSegment[] rows, GridSegment[] cols, bool emptyCol)
{
float avaiableWith = s.Width;
float avaiableHeight = s.Height;
if (!float.IsNaN(Width))
avaiableWith = Width;
if (!float.IsNaN(Height))
avaiableHeight = Height;
float totalRowFixed = 0;
float totalColFixed = 0;
float maxStarRow = 0;
float maxStarCol = 0;
if (emptyRows)
{
rows[0] = new GridSegment(0, 0, float.PositiveInfinity, MesureType.Start);
rows[0].Stars = 1;
maxStarRow = 1;
}
else
for (int index = 0; index < Rows.Count; index++)
{
var v = Rows[index];
rows[index] = new GridSegment(0, v.Min, v.Max, v.Type);
var current = rows[index];
if (current.Type == MesureType.Fixed)
{
//our desired size in units
current.DesiredSize = Mathf.Clamp(v.Value, current.Min, current.Max);
totalRowFixed += current.DesiredSize;
}
else if (current.Type == MesureType.Start)
{
current.Stars = v.Value;
maxStarRow += current.Stars;
}
}
if (emptyCol)
{
cols[0] = new GridSegment(1, 0, float.PositiveInfinity, MesureType.Start);
cols[0].Stars = 1;
maxStarCol = 1;
}
else
for (int index = 0; index < Columns.Count; index++)
{
var v = Columns[index];
cols[index] = new GridSegment(0, v.Min, v.Max, v.Type);
var current = cols[index];
if (current.Type == MesureType.Fixed)
{
//our desired size in units
current.DesiredSize = Mathf.Clamp(v.Value, current.Min, current.Max);
totalColFixed += current.DesiredSize;
}
else if (current.Type == MesureType.Start)
{
current.Stars = v.Value;
maxStarCol += current.Stars;
}
}
//TODO::ADD THE AUTO SIZED DEFs
//Calculate the sizings for all * columns
{
var starColumns = cols.Where(x => x.Type == MesureType.Start);
var stepStarColl = (avaiableWith - totalColFixed) / maxStarCol;
foreach (var gridSegment in starColumns)
{
gridSegment.DesiredSize = stepStarColl * gridSegment.Stars;
}
var starRows = rows.Where(x => x.Type == MesureType.Start);
var stepStarRows = (avaiableHeight - totalRowFixed) / maxStarRow;
foreach (var gridSegment in starRows)
{
gridSegment.DesiredSize = stepStarRows * gridSegment.Stars;
}
}
}
protected override Size ArrangeOverride(Size s)
{
int colCount = Columns.Count;
int rowCount = Rows.Count;
bool emptyRows = rowCount == 0;
bool emptyCol = colCount == 0;
if (emptyRows)
rowCount = 1;
if (emptyCol)
colCount = 1;
rows = new GridSegment[rowCount];
cols = new GridSegment[colCount];
CreateCells(s, emptyRows, rows, cols, emptyCol);
////Loop through all controls
foreach (var v in this.Childreen)
{
var layoutInfo = v.Layout<GridLayoutInfo>();
var rowspan = layoutInfo.RowSpan;
var colspan = layoutInfo.ColumSpan;
float width = 0;
float height = 0;
float x = 0;
float y = 0;
if (rowspan < 1)
rowspan = 1;
if (colspan < 1)
colspan = 0;
for (int i = 0; i < layoutInfo.Row + rowspan && i < rowCount; i++)
{
if (i > 0 && i <= layoutInfo.Row)
y += rows[i - 1].DesiredSize;
if ( i>= layoutInfo.Row )
height += rows[i].DesiredSize;
}
for (int i = 0; i < layoutInfo.Column + colspan && i < colCount; i++)
{
if (i > 0 && i <= layoutInfo.Column)
x += cols[i - 1].DesiredSize;
if (i >= layoutInfo.Column)
width += cols[i].DesiredSize;
}
v.Arrange(new Rect(x, y, width, height));
}
float gridWidth = 0;
float gridHeight = 0;
foreach (var col in cols)
{
gridWidth += col.DesiredSize;
}
foreach (var row in rows)
{
gridHeight += row.DesiredSize;
}
return new Size(gridWidth, gridHeight);
}
This is from my custom library, but I tried to keep it as close to WPF syntax as possible.
This code works almost as I want, but fails once the grid is inside a ScrollingContainer, since the size passed to the measure is Infinity, and it makes the grid take on a infinity large size.
Does anyone have an idea on how to solve this, I am not even using Auto Cols/Rows, since I thought it would simplify the Alg alot - I dwelled into the source of WPF, but I have major hard time trying to understand how it works.
Related
Trying to perform 2D Cross correlation on 2 images without using Matlab/Numpy/etc
I am trying to perform Cross Correlation on these 2 images in C#: Image, Template Matlab says the result is supposed to look like: Matlab result But this is my result: My result Here is my Cross Correlation function: public static Signal2D CrossCorrelation2D(Signal2D signal, Signal2D pulse) { return InverseFFT2D(FFT2D(signal) * FFT2D(pulse).GetConjugate()); } Here is my FFT2D: public static Signal2D FFT2D(Signal2D signal) { Signal2D result = new Signal2D(signal.Height, signal.Width); for (int i = 0; i < result.Height; i++) result[i] = new ComplexNumber[signal[i].Length]; //rows for (int n = 0; n < signal.Height; n++) { result[n] = FFT(signal[n]); } //columns for (int i = 0; i < signal[0].Length; i++) { ComplexNumber[] col = new ComplexNumber[signal.Height]; for (int j = 0; j < col.Length; j++) { col[j] = result[j][i]; } col = FFT(col); for (int j = 0; j < col.Length; j++) { result[j][i] = col[j]; } } return result; } Here is my FFT: public static Signal FFT(Signal signal) { int N = signal.Length; if (N == 1) return signal; if ((N & (N - 1)) != 0) throw new ArgumentOutOfRangeException("signal length must be a power of 2"); Signal evenArr = new Signal(N / 2); Signal oddArr = new Signal(N / 2); for (int i = 0; i < N / 2; i++) { evenArr[i] = signal[2 * i]; } evenArr = FFT(evenArr); for (int i = 0; i < N / 2; i++) { oddArr[i] = signal[2 * i + 1]; } oddArr = FFT(oddArr); Signal result = new Signal(N); for (int k = 0; k < N / 2; k++) { double w = -2.0 * k * Math.PI / N; ComplexNumber wk = new ComplexNumber(Math.Cos(w), Math.Sin(w)); ComplexNumber even = evenArr[k]; ComplexNumber odd = oddArr[k]; result[k] = even + (wk * odd); result[k + N / 2] = even - (wk * odd); } return result; } Here is my Signal multiplication (using pointwise multiplication): public static Signal2D operator* (Signal2D a, Signal2D b) { if (a.Height != b.Height || a.Width != b.Width) throw new ArgumentException("Sizes must be equal"); Signal2D result = new Signal2D(a.Height, a.Width); for (int y = 0; y < a.Height; y++) { for (int x = 0; x < a.Width; x++) { result[y][x] = a[y][x] * b[y][x]; } } return result; } Any help is appreciated, thanks. Edit: I left the matlab image at the original size of 1023 by 1023 and overlayed my result. It looks like I may already be at the result, I am just not sure how Matlab pads the image. Overlayed results (The red is the white part from my result, the grey is the black part from my result. Black/white is from Matlab)
Neural Net - Feed Forward, Matrix Multiplication in C#
I'm attempting to make a Neural Network in C#, I based the design in a python code I made a while back. But somehow the end result is not the same. I'm new to C# and I'm using it in Unity, so I have limitation to library uses. In python numpy can do matrix multiplications with the numpy.dot() method. I Haven't found something similar in C#, especially in Unity. So I had to do it by hand. The Python code: import numpy as np class NN: def __init__(self, n_input, n_hidden_layers, n_hidden_nodes, n_output): self.weights_hidden = [] for n in range(n_hidden_layers + 1): if n == 0: size = n_input, n_hidden_nodes elif n == n_hidden_layers: size = n_hidden_nodes, n_output else: size = n_hidden_nodes, n_hidden_nodes self.weights_hidden.append( np.random.random(size) ) #staticmethod def activation(x): return np.tanh(x) def feed_forward(self, ip): input_values = (ip - np.mean(ip, axis=0)) / np.std(ip, axis=0) for w, weights in enumerate(self.weights_hidden): if w == 0: result = input_values result = np.array( map(self.activation, result.dot(weights)) ) return result ANN = NN(n_input=5, n_hidden_layers=2, n_hidden_nodes=3, n_output=1) print ANN.feed_forward([1, 2, 3, 4, 5]) My attempt to convert it to C#. using UnityEngine; using System.Collections; public class neural_net : MonoBehaviour { int n_inputs; int n_hidden_layers; int n_hidden_nodes; int n_outputs; float[] inputs; ArrayList hidden_weights; ArrayList hidden_results; float[] output_results; public void init(int n_inputs, int n_hidden_layers, int n_hidden_nodes, int n_outputs){ this.n_inputs = n_inputs; this.n_hidden_layers = n_hidden_layers; this.n_hidden_nodes = n_hidden_nodes; this.n_outputs = n_outputs; this.hidden_weights = new ArrayList (); this.hidden_results = new ArrayList (); this.output_results = new float[n_outputs]; int rows; int columns; for (int h = 0; h < n_hidden_layers + 2; h++) { if (h == 0){ // input -> hidden rows = n_inputs; columns = n_hidden_nodes; } else if(h == n_hidden_layers + 1){ // hidden -> output rows = n_hidden_nodes; columns = n_outputs; } else { // hidden -> hidden rows = n_hidden_nodes; columns = n_hidden_nodes; } float[] hidden_result = new float[rows*columns]; hidden_results.Add(hidden_results); float[,] target = new float[rows,columns]; string test = ""; for(int r = 0; r < rows; r++){ for(int c = 0; c < columns; c++){ target[r,c] = Random.Range(0.0f, 1.0f); test += target[r,c] + ", "; } } hidden_weights.Add(target); } } float activation(float x){ // tanh(x); return (1 - Mathf.Exp (-2 * x)) / (1 + Mathf.Exp (-2 * x)); } float[] _dot_matrix(float[] results, float[,] weights){ float[] new_matrix = new float[weights.GetLength(1)]; string t0 = ""; for (int r = 0; r < weights.GetLength(1); r++){ float res = 0; for (int c = 0; c < weights.GetLength(0); c++) { res += results[c] * weights[c,r]; } new_matrix[r] = res; } return new_matrix; } float[] _map_activation(float[] pre_results){ float[] results = new float[pre_results.Length]; for (int i = 0; i < results.Length; i++) { results[i] = activation(pre_results[i]); } return results; } float[] feed_forward(){ int h; for (h = 0; h < n_hidden_layers + 2; h++) { float[] dot_matrix_result; if(h == 0){ dot_matrix_result = _dot_matrix(inputs, (float[,])hidden_weights[h]); } else if (h == n_hidden_layers +1){ dot_matrix_result = _dot_matrix((float[])hidden_results[h-1], (float[,])hidden_weights[h]); output_results = _map_activation(dot_matrix_result); break; } else { dot_matrix_result = _dot_matrix((float[])hidden_results[h-1], (float[,])hidden_weights[h]); } float[] result = _map_activation(dot_matrix_result); hidden_results[h] = _map_activation(result); } return output_results; } float[] normalize_input(float[] inputs){ float sum = 0.0f; for (int i = 0; i < inputs.Length; i++) { sum += inputs[i] ; } float average = sum / inputs.Length; float[] deviations = new float[inputs.Length]; for (int i = 0; i < inputs.Length; i++) { deviations[i] = Mathf.Pow(inputs[i] - average,2); } float sum_deviation = 0; for (int i = 0; i < deviations.Length; i++) { sum_deviation += deviations[i]; } float variance = sum_deviation / deviations.Length; float std = Mathf.Sqrt (variance); for (int i = 0; i < inputs.Length; i++) { inputs[i] = (inputs[i] - average)/std; } return inputs; } public void start_net(float[] inputs){ this.inputs = normalize_input(inputs); feed_forward (); } } I run the net from other script using the init method and then the start_net() method. I made a test with not random weights and fixed input data, but it didn't came to the same result as the python code. What's wrong with the C# code?
Nested For Loops - generating a catan-style hex-grid in Unity
As the title suggests, I am trying to generate a procedural hex grid in Unity using C#. void Start () { //5 mid startRowSize = 5; for (int i = 0; i < startRowSize; i++) { GameObject newHex = (GameObject)Instantiate(hex); hexWidth = newHex.gameObject.renderer.bounds.size.z; newHex.transform.Rotate(new Vector3(0,30,0)); newHex.transform.position = new Vector3((i * hexWidth),0,0); } for (int row = 0; row <= startRowSize-1; row ++) { for (int i = 0; i < row; i++) { GameObject newHex = (GameObject)Instantiate(hex); newHex.transform.Rotate(new Vector3(0,30,0)); newHex.transform.position = new Vector3(((i*hexWidth)+((hexWidth/2))+(row*(hexWidth/2))),0,((startRowSize-row))*-(hexWidth/1.17f)); } } } The code works, however the rows are being generated "backwards", meaning the outer rows contain the higher amounts of hexes, while the inner rows contain the smallest. This is obviously the opposite effect that I am trying to achieve. I've been messing with this code for hours and I can't figure out why. Any thoughts?
So after a few more hours of messing around with the code, I figured out why it wasn't iterating properly. He's the refined code... void Start () { //5 mid startRowSize = 10; for (int i = 0; i < startRowSize; i++) { GameObject newHex = (GameObject)Instantiate(hex); hexWidth = newHex.gameObject.renderer.bounds.size.z; newHex.transform.Rotate(new Vector3(0,30,0)); newHex.transform.position = new Vector3((i * hexWidth),0,0); } for (int row = 0; row < startRowSize; row++) { for (int i = 0; i < startRowSize-1-row; i++) { GameObject newHex = (GameObject)Instantiate(hex); newHex.transform.Rotate(new Vector3(0,30,0)); if (row == 0) { newHex.transform.position = new Vector3(((i*hexWidth)+(hexWidth/2)),0,-(hexWidth/1.17f)); } else { newHex.transform.position = new Vector3((i*hexWidth)+((row+1)*(hexWidth/2)),0,(row+1)*-(hexWidth/1.17f)); } } } for (int row = 0; row < startRowSize; row++) { for (int i = 0; i < startRowSize-1-row; i++) { GameObject newHex = (GameObject)Instantiate(hex); newHex.transform.Rotate(new Vector3(0,30,0)); if (row == 0) { newHex.transform.position = new Vector3(((i*hexWidth)+(hexWidth/2)),0,(hexWidth/1.17f)); } else { newHex.transform.position = new Vector3((i*hexWidth)+((row+1)*(hexWidth/2)),0,(row+1)*(hexWidth/1.17f)); } } } } Now, can anyone suggest how to clean it up a bit? My brain is fizzled...
Just a tip, Awake happens before Start(). void Awake() { //5 mid startRowSize = 10; for (int i = 0; i < startRowSize; i++) { GameObject newHex = HexCreator(); hexWidth = newHex.gameObject.renderer.bounds.size.z; newHex.transform.position = new Vector3(i * hexWidth, 0, 0); } for (int row = 0; row < startRowSize; row++) for (int i = 0; i < startRowSize-1-row; i++) { GameObject newHex = HexCreator(); if (row == 0) newHex.transform.position = new Vector3(i*hexWidth + hexWidth/2, 0, -(hexWidth/1.17f)); else newHex.transform.position = new Vector3(i*hexWidth + ((row+1)*(hexWidth/2)), 0,(row+1)*-(hexWidth/1.17f)); } for (int row = 0; row < startRowSize; row++) for (int i = 0; i < startRowSize-1-row; i++) { GameObject newHex = HexCreator(); if (row == 0) newHex.transform.position = new Vector3(i*hexWidth+ hexWidth/2, 0, hexWidth/1.17f); else newHex.transform.position = new Vector3(i*hexWidth + ((row+1)*(hexWidth/2)), 0, (row+1)*(hexWidth/1.17f)); } } Since you have this code repeating I made it into a function. That way if you need to upgrade it all you do is go to the function and change it there. private GameObject HexCreator() { GameObject newHex = (GameObject)Instantiate(hex); newHex.transform.Rotate(new Vector3(0,30,0)); return newHex; }
Rotating matrices
Objectives Imagine that, we have matrix like a11 a12 a13 a21 a22 a23 a31 a32 a33 What I want to do is, from textbox value rotate this matrix so that, for example if I write 2 and press rotate, program must keep both diagonal values of matrix (in this case a11, a22, a33, a13, a31) and rotate 2 times clockwise other values. So result must be like a11 a32 a13 a23 a22 a21 a31 a12 a33 It must work for all N x N size matrices, and as you see every 4 rotation takes matrix into default state. What I've done So idea is like that, I have 2 forms. First takes size of matrix (1 value, for example if it's 5, it generates 5x5 matrix). When I press OK it generates second forms textbox matrix like that Form 1 code private void button1_Click(object sender, EventArgs e) { int matrixSize; matrixSize = int.Parse(textBox1.Text); Form2 form2 = new Form2(matrixSize); form2.Width = matrixSize * 50 + 100; form2.Height = matrixSize *60 + 200; form2.Show(); //this.Hide(); } Form 2 code generates textbox matrix from given value and puts random values into this fields public Form2(int matrSize) { int counter = 0; InitializeComponent(); TextBox[] MatrixNodes = new TextBox[matrSize*matrSize]; Random r = new Random(); for (int i = 1; i <= matrSize; i++) { for (int j = 1; j <= matrSize; j++) { var tb = new TextBox(); int num = r.Next(1, 1000); MatrixNodes[counter] = tb; tb.Name = string.Format("Node_{0}{1}", i, j); Debug.Write(string.Format("Node_{0}{1}", i, j)); tb.Text = num.ToString(); tb.Location = new Point(j * 50, i * 50); tb.Width = 30; tb.Visible = true; this.splitContainer1.Panel2.Controls.Add(tb); counter++; } } } Form 2 has 1 textbox for controlling rotation (others are generated on the fly, programmatically). What I want to do is, when I enter rotation count and press Enter on this textbox, I want to rotate textbox matrix as I explained above. Can't figure out how to do it.
Copy both diagonals to separate arrays, then rotate your matrix and replace diagonals. Below code shows each step: class Program { static void Main(string[] args) { int matrixSize = 3; string[,] matrix = new string[matrixSize,matrixSize]; //create square matrix for (int x = 0; x < matrixSize; x++) { for (int y = 0; y < matrixSize; y++) { matrix[x, y] = "a" + (x + 1).ToString() + (y + 1).ToString(); } } Console.WriteLine(Environment.NewLine + "Base square matrix"); for (int x = 0; x < matrixSize; x++) { for (int y = 0; y < matrixSize; y++) { Console.Write(matrix[x, y] + " "); } Console.Write(Environment.NewLine); } Console.ReadKey(); //copy diagonals string[] leftDiagonal = new string[matrixSize]; string[] rightDiagonal = new string[matrixSize]; for (int x = 0; x < matrixSize; x++) { leftDiagonal[x] = matrix[x, x]; rightDiagonal[x] = matrix[matrixSize - 1 - x, x]; } Console.WriteLine(Environment.NewLine + "Diagonals"); for (int x = 0; x < matrixSize; ++x) { Console.Write(leftDiagonal[x] + " " + rightDiagonal[x] + Environment.NewLine); } Console.ReadKey(); //rotate matrix string[,] rotatedMatrix = new string[matrixSize, matrixSize]; for (int x = 0; x < matrixSize; x++) { for (int y = 0; y < matrixSize; y++) { rotatedMatrix[x, y] = matrix[matrixSize - y - 1, x]; } } Console.WriteLine(Environment.NewLine + "Rotated"); for (int x = 0; x < matrixSize; x++) { for (int y = 0; y < matrixSize; y++) { Console.Write(rotatedMatrix[x, y] + " "); } Console.Write(Environment.NewLine); } Console.ReadKey(); //rotate matrix again string[,] rotatedMatrixAgain = new string[matrixSize, matrixSize]; for (int x = 0; x < matrixSize; x++) { for (int y = 0; y < matrixSize; y++) { rotatedMatrixAgain[x, y] = rotatedMatrix[matrixSize - y - 1, x]; } } Console.WriteLine(Environment.NewLine + "Rotated again"); for (int x = 0; x < matrixSize; x++) { for (int y = 0; y < matrixSize; y++) { Console.Write(rotatedMatrixAgain[x, y] + " "); } Console.Write(Environment.NewLine); } Console.ReadKey(); //replace diagonals for (int x = 0; x < matrixSize; x++) { rotatedMatrixAgain[x, x] = leftDiagonal[x]; rotatedMatrixAgain[matrixSize - 1 - x, x] = rightDiagonal[x]; } Console.WriteLine(Environment.NewLine + "Completed" + Environment.NewLine); for (int x = 0; x < matrixSize; x++) { for (int y = 0; y < matrixSize; y++) { Console.Write(rotatedMatrixAgain[x, y] + " "); } Console.Write(Environment.NewLine); } Console.ReadKey(); } }
I don't know C#, so I can only give a suggestion in pseudocode: Input: An N by N matrix in Output: The input matrix rotated as described in the OP out for i = 1 to N for j = 1 to N if N - j != i and i != j // Do not change values on either diagonal out[j][N-i] = in[i][j] else out[i][j] = in[i][j] Disclaimer: This algorithm is untested. I suggest you use a debugger to check that it works as you want.
This seems like quite an unorthodox UI presentation, but you're not too far off in terms of being able to achieve your functionality. Instead of a linear array, a rectangular array will make your job much easier. The actual rotation could be implemented with a for loop repeating a single rotation (which would be implemented as in the case 1 code), but I've decided to combine them into the four possible cases. This actually allows you to enter a negative number for number of rotations. Which reminds me, you really should do more error checking. At least protect against int.Parse throwing an exception both places it's used (with a try catch block or by switching to int.TryParse) and make sure it returns a meaningful number (greater than 0, possibly set a reasonable maximum other than int.MaxValue) for matrixSize in button1_Click. namespace RotatingMatrices { public class Form2 : Form { // note these class fields private TextBox[,] matrixNodes; private int matrixSize; public Form2(int matrSize) { InitializeComponent(); // note these inits matrixSize = matrSize; matrixNodes = new TextBox[matrixSize, matrixSize]; Random r = new Random(); // note the new loop limits for (int i = 0; i < matrixSize; i++) { for (int j = 0; j < matrixSize; j++) { var tb = new TextBox(); int num = r.Next(1, 1000); // note the change in indexing matrixNodes[i,j] = tb; tb.Name = string.Format("Node_{0}_{1}", i, j); Debug.Write(string.Format("Node_{0}_{1}", i, j)); tb.Text = num.ToString(); tb.Location = new Point(j * 50, i * 50); tb.Width = 30; tb.Visible = true; this.splitContainer1.Panel2.Controls.Add(tb); } } } private void buttonRotate_Click(object sender, EventArgs e) { string[,] matrix = new string[matrixSize, matrixSize]; int rotations = (4 + int.Parse(textBoxRotations.Text)) % 4; // note the addition of and mod by 4 switch(rotations) { case 1: // rotate clockwise for (int i = 0; i < matrixSize; i++) { for (int j = 0; j < matrixSize; j++) { matrix[j, matrixSize - i - 1] = matrixNodes[i, j].Text; } } break; case 2: // rotate 180 degrees for (int i = 0; i < matrixSize; i++) { for (int j = 0; j < matrixSize; j++) { matrix[i, j] = matrixNodes[matrixSize - i - 1, matrixSize - j - 1].Text; } } break; case 3: // rotate counter-clockwise for (int i = 0; i < matrixSize; i++) { for (int j = 0; j < matrixSize; j++) { matrix[i, j] = matrixNodes[j, matrixSize - i - 1].Text; } } break; default: // do nothing return; } // restore diagonals for(int i = 0; i < matrixSize; i++) { matrix[i, i] = matrixNodes[i, i].Text; matrix[i, matrixSize - i - 1] = matrixNodes[i, matrixSize - i - 1].Text; } // write strings back to text boxes for (int i = 0; i < matrixSize; i++) { for (int j = 0; j < matrixSize; j++) { matrixNodes[i, j].Text = matrix[i, j]; } } } } }
I decided to tackle the issue using a listView instead of a text box, which makes the logic easier for me. Using this method, I was able to think of the matrix as successive boxes. I start on the outside and move in toward the middle, changing the size of my box each time. Also, rather than using two forms, I use one. At the top I have a textbox where the user enters the size they want the array to be, and a button labeled "Fill" (button2). And at the bottom I have a textbox where the user enters the degree of rotation. When they click "Rotate," it kicks off a process of adding values to linked lists, combining and shifting the list, and then writing back out to the matrix. I'm sure I made it more convoluted than it has to be, but it was a great learning exercise. After looking over jerry's code above, I think I'm going to look into rectangular arrays. :) using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; namespace Recycle { public partial class Form1 : Form { public int size; public LinkedList<string> topRight = new LinkedList<string>(); public LinkedList<string> bottomLeft = new LinkedList<string>(); public LinkedList<string> myMatrix = new LinkedList<string>(); public LinkedList<string> shiftMatrix = new LinkedList<string>(); public Form1() { InitializeComponent(); } private void button2_Click(object sender, EventArgs e) { listView1.Clear(); size = int.Parse(textBox2.Text); int c = 0; int q = 0; int w = 0; string[] content = new string[size]; Random rnd = new Random(); for (c = 0; c < size; c++) { listView1.Columns.Add("", 25); } for (q = 0; q < size; q++) { for (w = 0; w < size; w++) { content[w] = rnd.Next(9,100).ToString(); } ListViewItem lvi = new ListViewItem(content); listView1.Items.Add(lvi); } } public bool iseven(int size) { if (size % 2 == 0) { return true; } else { return false; } } public void button1_Click(object sender, EventArgs e) { if (listView1.Items.Count < 3) { MessageBox.Show("Matrix cannot be rotated."); return; } bool even = false; int shift = int.Parse(textBox1.Text); //amount to shift by int box = listView1.Items.Count - 1; //size of box int half = Convert.ToInt32(listView1.Items.Count / 2); int corner = 0; //inside corner of box if (shift > listView1.Items.Count) { shift = shift % ((listView1.Items.Count - 2) * 4); } do { eachPass(shift, box, corner); ++corner; --box; } while (box >= half + 1); } public void eachPass(int shift, int box, int corner) { int x; int i; //Read each non-diagonal value into one of two lists for (x = corner + 1; x < box; x++) { topRight.AddLast(listView1.Items[corner].SubItems[x].Text); } x = box; for (i = corner + 1; i < box; i++) { topRight.AddLast(listView1.Items[i].SubItems[x].Text); } for (x = box - 1; x > corner; x--) { bottomLeft.AddLast(listView1.Items[box].SubItems[x].Text); } x = corner; for (i = box - 1; i > corner; i--) { bottomLeft.AddLast(listView1.Items[i].SubItems[x].Text); } string myTest = ""; //join the two lists, so they can be shifted foreach (string tR in topRight) { myMatrix.AddLast(tR); } foreach (string bL in bottomLeft) { myMatrix.AddLast(bL); } int sh; //shift the list using another list for (sh = shift; sh < myMatrix.Count; sh++) { shiftMatrix.AddLast(myMatrix.ElementAt(sh)); } for (sh = 0; sh < shift; sh++) { shiftMatrix.AddLast(myMatrix.ElementAt(sh)); } //we need the sizes of the current lists int trCnt = topRight.Count; int blCnt = bottomLeft.Count; //clear them for reuse topRight.Clear(); bottomLeft.Clear(); int s; //put the shifted values back for (s = 0; s < trCnt; s++) { topRight.AddLast(shiftMatrix.ElementAt(s)); } for (s = blCnt; s < shiftMatrix.Count; s++) { bottomLeft.AddLast(shiftMatrix.ElementAt(s)); } int tRn = 0; int bLn = 0; //write each non-diagonal value from one of two lists for (x = corner + 1; x < box; x++) { listView1.Items[corner].SubItems[x].Text = topRight.ElementAt(tRn); ++tRn; } x = box; for (i = corner + 1; i < box; i++) { listView1.Items[i].SubItems[x].Text = topRight.ElementAt(tRn); ++tRn; } for (x = box - 1; x > corner; x--) { listView1.Items[box].SubItems[x].Text = bottomLeft.ElementAt(bLn); ++bLn; } x = corner; for (i = box - 1; i > corner; i--) { listView1.Items[i].SubItems[x].Text = bottomLeft.ElementAt(bLn); ++bLn; } myMatrix.Clear(); shiftMatrix.Clear(); topRight.Clear(); bottomLeft.Clear(); } } }
how can i drag a 2d level array from a txt file
i am working on improving this tower defence gtame that i finished from this tutorial http://xnatd.blogspot.com/ i now wish to load the levels from a text file but not quite sure how i would do this using a streamreader, any tips? heres the source code for my level class; public class Level { protected int temperature; protected int levelNo; private Queue<Vector2> waypoints = new Queue<Vector2>(); public Queue<Vector2> Waypoints { get { return waypoints; } } int[,] map = new int[,] { {0,0,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,}, {0,0,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,}, {0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0,}, {0,0,0,0,1,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,}, {0,0,0,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,}, {0,0,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,}, {0,0,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0,}, {0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,}, {0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,}, {0,0,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,}, {0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0,}, {0,0,0,0,1,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,}, {0,0,0,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,}, {0,0,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,}, {0,0,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,1,0,0,0,}, {0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,}, }; public int Temperature // get the width of the level (how many numbers are in a row) { get { return temperature; } } public int LevelNo // get the width of the level (how many numbers are in a row) { get { return levelNo; } set { levelNo = value; } } public int Width // get the width of the level (how many numbers are in a row) { get { return map.GetLength(1); } } public int Height // get the height of our level (how many numbers are there in a column) { get { return map.GetLength(0); } } public int GetIndex(int cellX, int cellY) // return the index of the requested cell. { if (cellX < 0 || cellX > Width - 1 || cellY < 0 || cellY > Height - 1) { return 0; } else { return map[cellY, cellX]; } } public List<Texture2D> tileTextures = new List<Texture2D>(); // list to contain all the textures /// <summary> /// CONSTRUCTOR NEW LEVEL /// </summary> public Level() { SetWayPoints(map); this.temperature = 1000; this.levelNo = 2; } private void SetWayPoints(int[,] map) { int currentPosVal = map[0, 0]; int lPos = 0; int rPos = 0; int uPos = 0; int dPos = 0; int storedXPos = 99; int storedYPos = 99; int endstoredXPos = 99; int endstoredYPos = 99; int lastY = 0; int lastX = 0; //Search top ROW for start for (int i = 0; i < Width; i++) { currentPosVal = map[0, i]; if (currentPosVal == 1) { storedXPos = i; storedYPos = 0; waypoints.Enqueue(new Vector2(storedXPos, storedYPos) * 32); lastX = storedXPos; lastY = storedYPos; break; } } //if start not set if (storedXPos == 99 && storedXPos == 99) { //look in 1st coloum for start for (int i = 0; i < Height; i++) { currentPosVal = map[i, 0]; if (currentPosVal == 1) { storedXPos = 0; storedYPos = i; waypoints.Enqueue(new Vector2(storedXPos, storedYPos) * 32); lastX = storedXPos; lastY = storedYPos; break; } } } //search end COLOUM for end for (int i = 0; i < Height; i++) { currentPosVal = map[i, Width - 1]; if (currentPosVal == 1) { endstoredXPos = Width - 1; endstoredYPos = i; } } //If end not set look in bottom row for end if (endstoredXPos == 99 && endstoredYPos == 99) { for (int i = 0; i < Width; i++) { currentPosVal = map[7, i]; if (currentPosVal == 1) { endstoredXPos = i; endstoredYPos = Height - 1; } } if (endstoredXPos == 99 && endstoredYPos == 99) { } } // start midlle loop while (true) { lPos = 0; rPos = 0; uPos = 0; dPos = 0; //If current pos is not down the left hand edge if (storedXPos > 0) { lPos = map[storedYPos, storedXPos - 1]; } //If current pos square is not down the right hand edge if (storedXPos < Width - 1) { rPos = map[storedYPos, storedXPos + 1]; } //If current pos square is not in the top row if (storedYPos > 0) { uPos = map[storedYPos - 1, storedXPos]; } //If current pos square is not in the bottom row if (storedYPos < Height - 1) { dPos = map[storedYPos + 1, storedXPos]; } if (lPos == 1 && (lastX != storedXPos - 1 || lastY != storedYPos)) { lastX = storedXPos; lastY = storedYPos; storedXPos--; waypoints.Enqueue(new Vector2(storedXPos, storedYPos) * 32); } else if (rPos == 1 && (lastX != storedXPos + 1 || lastY != storedYPos)) { lastX = storedXPos; lastY = storedYPos; storedXPos++; waypoints.Enqueue(new Vector2(storedXPos, storedYPos) * 32); } else if (dPos == 1 && (lastX != storedXPos || lastY != storedYPos + 1)) { lastX = storedXPos; lastY = storedYPos; storedYPos++; waypoints.Enqueue(new Vector2(storedXPos, storedYPos) * 32); } else if (uPos == 1 && (lastX != storedXPos || lastY != storedYPos - 1)) { lastX = storedXPos; lastY = storedYPos; storedYPos--; waypoints.Enqueue(new Vector2(storedXPos, storedYPos) * 32); } if (storedXPos == endstoredXPos && storedYPos == endstoredYPos) { break; } } } public void AddTexture(Texture2D texture) // method adds a texture to our texture list. { tileTextures.Add(texture); } //Reads number from array, store its value in textureIndex, Use textureIndex to get the texture from tileTextures, public void Draw(SpriteBatch batch) //Draw appropiate texture, Repeat through all elements of the array { int textureIndex; Texture2D texture; for (int x = 0; x < Width; x++) { for (int y = 0; y < Height; y++) { if (levelNo == 0) { textureIndex = map[y, x]; if (textureIndex == -1) continue; texture = tileTextures[textureIndex]; batch.Draw(texture, new Rectangle(x * 32, y * 32, 32, 32), Color.White); } if (levelNo > 0) { textureIndex = map[y, x]; textureIndex += (levelNo * 2); if (textureIndex == -1) continue; texture = tileTextures[textureIndex]; batch.Draw(texture, new Rectangle(x * 32, y * 32, 32, 32), Color.White); } } } } } }
Since C# is compiled and can't do evals like scripted languages can (not that you should be doing that anyway) you should probably use streamreader to read the data from file (formatted perhaps as delimited text: csv or tsv) Assuming you're loading something similar to the map you have up there then a map file could look something like 0,0,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0 0,0,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0 0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0 0,0,0,0,1,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0 0,0,0,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0 0,0,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0 0,0,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0 0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0 0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0 0,0,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0 0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0 0,0,0,0,1,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0 0,0,0,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0 0,0,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0 0,0,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,1,0,0,0 0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1 where you would then loop through the file and read each line As each line is read in, you can then split the line by "," to create a 1d array which can then be assigned to an index in the 2d array. Loop for each line to create the entire 2d map array Take a look at this if you need help splitting strings in C#; note that the sample code splits at spaces " " and that you should use s.Split(','); for csv
With a file that small i would use: File.ReadAllLines , and after readling it loop over the lines with a foreach loop.