Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I need help debugging and finishing a program that would: read a file with same number of lines and same number of integer values on each line (this will be a n x n matrix). The program should determines if the matrix is a magic square.
example of magic square: "ms.txt"
8,1,6;3,5,7;4,9,2
my code (working in progress), your help would be appreciated
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace MagicSquare
{
class Program
{
static void Main(string[] args)
{
int[,]S;
string line; //to hold one line of file
string[] token; //to hold each token in line
char[] separator = { ',' };
int N;
//open file
try
{
using (StreamReader sr = new StreamReader("..\\..\\ms.txt"))
{
line = sr.ReadLine();
token = line.Split(separator);
N = token.Count();
S = new int[N, N];
for (int i = 0; i < N; i++)
S[0, i] = Convert.ToInt32(token[i]);
for (int r = 1; r < N; r++)
{
line = sr.ReadLine();
token = line.Split(separator);
for (int c = 0; c < N; c++)
S[r, c] = Convert.ToInt32(token[c]);
}
sr.Close();
}
}
catch (Exception e)
{
Console.WriteLine("The file could not be read:");
Console.WriteLine(e.Message);
}
//find Magic Number
int magic = 0;
for (int i = 0; i < N; i++)
magic += S[i, i];
int sum = 0;
for (int i=0;i<N;i++)
sum += S[i,N -1-i];
if (magic!=sum)
{
Console.Write("Not Magic");
return;
}
//check each column
for (int c=0;c<N;c++)
{
int sum1 =0;
for (int r=0;r<N;r++)
sum1 += S[r,c];
if (sum1!=magic)
{
Console.WriteLine("Not magic");
return;
}
}
}
}
}
I edit your solution. This works for rows and columns.
static void Main(string[] args)
{
int[,] S = null;
int N = 0;
string line; //to hold one line of file
string[] token; //to hold each token in line
char[] separator = { ',' };
//open file
try
{
using (StreamReader sr = new StreamReader(#"C:\Users\sb9923\Desktop\ms.txt"))
{
line = sr.ReadLine();
token = line.Split(separator);
N = token.Count();
S = new int[N, N];
for (int i = 0; i < N; i++)
S[0, i] = Convert.ToInt32(token[i]);
for (int r = 1; r < N; r++)
{
line = sr.ReadLine();
token = line.Split(separator);
for (int c = 0; c < N; c++)
S[r, c] = Convert.ToInt32(token[c]);
}
sr.Close();
}
}
catch (Exception e)
{
Console.WriteLine("The file could not be read:");
Console.WriteLine(e.Message);
}
int magicValue = GetSum(N * N) / N;
//Check for magic
bool isMagic = true;
for (int counterY = 0; counterY < S.GetLength(1); counterY++)
{
int rowValue = 0;
int columnValue = 0;
for (int counterX = 0; counterX < S.GetLength(0); counterX++)
{
rowValue += Convert.ToInt32(S[counterY, counterX]);
columnValue += Convert.ToInt32(S[counterX, counterY]);
}
if (rowValue != magicValue)
{
isMagic = false;
break;
}
if (columnValue != magicValue)
{
isMagic = false;
break;
}
rowValue = 0;
columnValue = 0;
}
if (isMagic)
{
Console.WriteLine("Yeah it is magic! :)");
}
else
{
Console.WriteLine("No magic in the air!");
}
}
private static int GetSum(int maxValue)
{
if (maxValue < 1)
{
return 0;
}
return maxValue + GetSum(maxValue - 1);
}
If you have a question go for asking ;)
Just one simple variation about "how to check if square is magical?"(and unit test, for testing purpose):
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Linq;
using System.IO;
namespace MSquareTest
{
[TestClass]
public class MSquareTest
{
/// <summary>
/// Checks if array of int's
/// is an magick square
/// </summary>
/// <param name="matrix">Input array</param>
/// <returns>True/False</returns>
public bool IsMagicSquare(int[] matrix)
{
if (matrix.Length % 3 != 0)
throw new ArgumentException("Invalid 2D cube!");
// 2x2(6 cells) is minimum
if (matrix.Length < 6)
throw new ArgumentException("Use at least 2x2 cube!");
// Cube face length
int length = matrix.Length / 3;
// calculate first row sum
int excepted = 0;
for (int y = 0; y < length; y++)
excepted += matrix[y];
// calculate and check second and another rows
for (int x = 1; x < length; x++)
{
int actual = 0;
for (int y = 0; y < length; y++)
actual += matrix[(length * x) + y];
if (actual != excepted)
return false;
}
// calculate and check columns
for (int x = 0; x < length; x++)
{
int actual = 0;
for (int y = 0; y < length; y++)
actual += matrix[(length * y) + x];
if (actual != excepted)
return false;
}
return true;
}
[TestMethod]
public void TestMS()
{
var GoodInput = "8,1,6;3,5,7;4,9,2"; // = File.ReadAllText("..\\..\\ms.txt");
var GoodArray = (from x in GoodInput.Split(',', ';') select int.Parse(x)).ToArray();
var BadInput = "6,4,1;3,0,3;1,5,9";
var BadArray = (from x in BadInput.Split(',', ';') select int.Parse(x)).ToArray();
// Good array is magick square, and bad array is not
var Result = IsMagicSquare(GoodArray) && !IsMagicSquare(BadArray);
Assert.IsTrue(Result);
}
}
}
Related
I am working on a project that compares the time bubble and selection sort take. I made two separate programs and combined them into one and now bubble sort is running much faster than selection sort. I checked to make sure that the code wasn't just giving me 0s because of some conversion error and was running as intended. I am using System.Diagnostics; to measure the time. I also checked that the machine was not the problem, I ran it on Replit and got similar results.
{
class Program
{
public static int s1 = 0;
public static int s2 = 0;
static decimal bubblesort(int[] arr1)
{
int n = arr1.Length;
var sw1 = Stopwatch.StartNew();
for (int i = 0; i < n - 1; i++)
{
for (int j = 0; j < n - i - 1; j++)
{
if (arr1[j] > arr1[j + 1])
{
int tmp = arr1[j];
// swap tmp and arr[i] int tmp = arr[j];
arr1[j] = arr1[j + 1];
arr1[j + 1] = tmp;
s1++;
}
}
}
sw1.Stop();
// Console.WriteLine(sw1.ElapsedMilliseconds);
decimal a = Convert.ToDecimal(sw1.ElapsedMilliseconds);
return a;
}
static decimal selectionsort(int[] arr2)
{
int n = arr2.Length;
var sw1 = Stopwatch.StartNew();
// for (int e = 0; e < 1000; e++)
// {
for (int x = 0; x < arr2.Length - 1; x++)
{
int minPos = x;
for (int y = x + 1; y < arr2.Length; y++)
{
if (arr2[y] < arr2[minPos])
minPos = y;
}
if (x != minPos && minPos < arr2.Length)
{
int temp = arr2[minPos];
arr2[minPos] = arr2[x];
arr2[x] = temp;
s2++;
}
}
// }
sw1.Stop();
// Console.WriteLine(sw1.ElapsedMilliseconds);
decimal a = Convert.ToDecimal(sw1.ElapsedMilliseconds);
return a;
}
static void Main(string[] args)
{
Console.WriteLine("Enter the size of n");
int n = Convert.ToInt32(Console.ReadLine());
Random rnd = new System.Random();
decimal bs = 0M;
decimal ss = 0M;
int s = 0;
int[] arr1 = new int[n];
int tx = 1000; //tx is a variable that I can use to adjust sample size
decimal tm = Convert.ToDecimal(tx);
for (int i = 0; i < tx; i++)
{
for (int a = 0; a < n; a++)
{
arr1[a] = rnd.Next(0, 1000000);
}
ss += selectionsort(arr1);
bs += bubblesort(arr1);
}
bs = bs / tm;
ss = ss / tm;
Console.WriteLine("Bubble Sort took " + bs + " miliseconds");
Console.WriteLine("Selection Sort took " + ss + " miliseconds");
}
}
}
What is going on? What is causing bubble sort to be fast or what is slowing down Selection sort? How can I fix this?
I found that the problem was that the Selection Sort was looping 1000 times per method run in addition to the 1000 runs for sample size, causing the method to perform significantly worse than bubble sort. Thank you guys for help and thank you TheGeneral for showing me the benchmarking tools. Also, the array that was given as a parameter was a copy instead of a reference, as running through the loop manually showed me that the bubble sort was doing it's job and not sorting an already sorted array.
To solve your initial problem you just need to copy your arrays, you can do this easily with ToArray():
Creates an array from a IEnumerable.
ss += selectionsort(arr1.ToArray());
bs += bubblesort(arr1.ToArray());
However let's learn how to do a more reliable benchmark with BenchmarkDotNet:
BenchmarkDotNet Nuget
Official Documentation
Given
public class Sort
{
public static void BubbleSort(int[] arr1)
{
int n = arr1.Length;
for (int i = 0; i < n - 1; i++)
{
for (int j = 0; j < n - i - 1; j++)
{
if (arr1[j] > arr1[j + 1])
{
int tmp = arr1[j];
// swap tmp and arr[i] int tmp = arr[j];
arr1[j] = arr1[j + 1];
arr1[j + 1] = tmp;
}
}
}
}
public static void SelectionSort(int[] arr2)
{
int n = arr2.Length;
for (int x = 0; x < arr2.Length - 1; x++)
{
int minPos = x;
for (int y = x + 1; y < arr2.Length; y++)
{
if (arr2[y] < arr2[minPos])
minPos = y;
}
if (x != minPos && minPos < arr2.Length)
{
int temp = arr2[minPos];
arr2[minPos] = arr2[x];
arr2[x] = temp;
}
}
}
}
Benchmark code
[SimpleJob(RuntimeMoniker.Net50)]
[MemoryDiagnoser()]
public class SortBenchmark
{
private int[] data;
[Params(100, 1000)]
public int N;
[GlobalSetup]
public void Setup()
{
var r = new Random(42);
data = Enumerable
.Repeat(0, N)
.Select(i => r.Next(0, N))
.ToArray();
}
[Benchmark]
public void Bubble() => Sort.BubbleSort(data.ToArray());
[Benchmark]
public void Selection() => Sort.SelectionSort(data.ToArray());
}
Usage
static void Main(string[] args)
{
BenchmarkRunner.Run<SortBenchmark>();
}
Results
Method
N
Mean
Error
StdDev
Bubble
100
8.553 us
0.0753 us
0.0704 us
Selection
100
4.757 us
0.0247 us
0.0231 us
Bubble
1000
657.760 us
7.2581 us
6.7893 us
Selection
1000
300.395 us
2.3302 us
2.1796 us
Summary
What have we learnt? Your bubble sort code is slower ¯\_(ツ)_/¯
It looks like you're passing in the sorted array into Bubble Sort. Because arrays are passed by reference, the sort that you're doing on the array is editing the same contents of the array that will be eventually passed into bubble sort.
Make a second array and pass the second array into bubble sort.
I need to streamwrite into a file.txt a 10 random numbers combinations (NOT REPEATED) like lottery program. I got everything except Non-repeated random numbers. it has to be seen (file.txt) like a 2D array with 10 combinations thx.
class Matriz
{
private int[,] array;
private int nfilas, ncols;
public void Ingresar()
{
Random aleatori = new Random();
nfilas = 10;
ncols = 6;
Console.WriteLine("\n");
array = new int[nfilas, ncols];
for (int filas = 0; filas < nfilas; filas++)
{
for (int columnas = 0; columnas < ncols; columnas++)
array[filas, columnas] = aleatori.Next(0, 50);
}
}
public void Imprimir()
{
StreamWriter fitxer = new StreamWriter(#"C:\andres\lotto649.txt");
int contador = 0;
for (int f = 0; f < nfilas; f++)
{
for (int c = 0; c < ncols; c++)
fitxer.Write(array[f, c] + " ");
fitxer.WriteLine();
contador++;
}
fitxer.WriteLine($"\n\n\tHay {contador} combinaciones de la Loteria 6/49");
fitxer.Close();
}
static void Main(string[] args)
{
Matriz array_menu = new Matriz();
array_menu.Ingresar();
array_menu.Imprimir();
}
}
Something like this should work.
Before inserting the new number in the given position, check the row thus far if the same number is already in there and if so, repeat the process until you get a number that isn't yet in there.
for (int filas = 0; filas < nfilas; filas++)
{
for (int columnas = 0; columnas < ncols; columnas++)
{
bool cont = true;
while(cont)
{
cont = false;
int newRand = aleatori.Next(0, 50);
for(int i = 0; i < columnas; i++)
if(array[filas, i] == newRand)
cont = true;
if(cont)
continue;
array[filas, columnas] = newRand;
break;
}
}
}
Alternatively, since the number is small you could also work with a list of ints and remove the given value from there.
This has the advantage, that you'll never have to redo your random number as it will always produce a valid result. The above example could (theoretically) run indefinitely long.
for (int filas = 0; filas < nfilas; filas++)
{
List<int> nums = new List<int>(49);
for(int i = 0; i < 49; i++)
nums.Add(i + 1); //num 1...49
for (int columnas = 0; columnas < ncols; columnas++)
{
int index = aleatori.Next(0, nums.Count)
array[filas, columnas] = nums[index];
nums.RemoveAt(index);
}
}
I have to write a program that finds the difference between the sums of square matrix diagonals for homework, but my code throws IndexOutOFRange exception and I have no idea how to fix it.
Source code below:
//input 3 11 2 4 4 5 6 10 8 -12 //desired output: 15
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
class diagonalDifference
{
static void Main()
{
int N = Convert.ToInt16(Console.ReadLine());
int[,] arr = new int[N, N];
string str = string.Empty;
for (int i = 0; i < N; ++i)
{
string[] strArr = Console.ReadLine().Split(' ');
for (int j = 0; j < strArr.Length; ++j)
{
arr[i, j] = Convert.ToInt16(strArr[j]);
}
}
int left = 0, right = N - 1, ldTotal = 0, rdTotal = 0;
while (left <= right)
{
ldTotal += arr[left, left];
rdTotal += arr[left++, right];
}
Console.WriteLine(Math.Abs(ldTotal - rdTotal));
}
}
class diagonalDifference
{
static void Main()
{
int N = Convert.ToInt16(Console.ReadLine());
int[,] arr = new int[N, N];
string str = string.Empty;
for (int i = 0; i < N; ++i)
{
string[] strArr = Console.ReadLine().Split(' ');
for (int j = 0; j < strArr.Length; ++j)
{
arr[i, j] = Convert.ToInt16(strArr[j]);
}
}
int left = 0, right = N - 1, ldTotal = 0, rdTotal = 0;
while (left <= (N-1))
{
ldTotal += arr[left, left];
rdTotal += arr[left, right];
Left++;
Right--;
}
Console.WriteLine(Math.Abs(ldTotal - rdTotal));
}
}
class Result
{
/*
* Complete the 'diagonalDifference' function below.
*
* The function is expected to return an INTEGER.
* The function accepts 2D_INTEGER_ARRAY arr as parameter.
*/
public static int diagonalDifference(List<List<int>> arr)
{
int l=arr.Count;
int d1=0;
int d2=0;
for(int i=0;i<l;i++)
{
d1=d1+arr[i][i];
d2=d2+arr[i][l-1-i];
}
return (Math.Abs(d1-d2));
}
}
So I have built my own (toy) encryption algorithm using matrices. The program is supposed to encrypt the plaintext with the key and then ask you the key and print out the decrypted plaintext. Everything is ok until the point when the C# program generates the 'key matrix' from the key to decrypt the cipher. Note that the first time that it generates the 'key matrix' from the key it is ok but the second time it freezes. Here is the code.
using System;
namespace MatrixEncryption
{
class MainClass
{
public static void Main (string[] args)
{
Console.WriteLine("Enter a relatively short piece of text:");
string txt = Console.ReadLine();
txt += "L";
Console.WriteLine("Enter an encryption key:");
string ekey = Console.ReadLine();
int times = 0;
while(true)
{
if(txt.Length + 1 < (Math.Pow((double)ekey.Length,(double)times))) break;
times++;
}
times++;
Console.WriteLine(times);
Matrix keym = new Matrix(ekey.Length^times, ekey.Length^times);
string res = ekey;
for(int i = 0; i<times - 1; i++)
{
res = GetCharRep(GenMatrix(res));
}
keym = GenMatrix(res);
Console.WriteLine(keym.cols + ":" + keym.rows);
Matrix passm = new Matrix(keym.rows, keym.cols);
int unicnt = 0;
Random a = new Random();
for(int i = 0; i<(keym.rows); i++)
{
for(int j = 0; j<(keym.cols); j++)
{
if(unicnt == 0)
{
passm[i, j] = (byte)txt.Length;
unicnt++;
continue;
}
if(unicnt < txt.Length)
{
passm[i, j] = (byte)txt[unicnt - 1];
}
else
{
int aa = a.Next();
passm[i, j] = (byte)(aa % byte.MaxValue);
}
unicnt++;
}
}
Matrix cipherm = new Matrix(keym.rows, keym.cols);
Matrix TwoMatrix = new Matrix(cipherm.rows, cipherm.cols);
for(int i = 0; i<TwoMatrix.rows; i++)
{
for(int j = 0; j<TwoMatrix.cols; j++)
{
TwoMatrix[i, j] = 2;
}
}
cipherm = NotMul(passm + TwoMatrix, keym + TwoMatrix);
Console.WriteLine("Enciphered text : " + GetCharRep(cipherm));
Console.WriteLine("Enter key now to check if decryptable cipher : ");
string keyy = Console.ReadLine();
int timesx = cipherm.cols;
double aaa = (double)timesx;
double bbb = (double)keyy.Length;
timesx = (int)Math.Log(aaa, bbb);
Matrix keymx = new Matrix(timesx, timesx);
string resss = keyy;
for(int i = 0; i<timesx; i++)
{
resss = GetCharRep(GenMatrix(resss));
}
keymx = GenMatrix(resss);
if(keymx != keym)
{
Console.WriteLine("STUPID COMPUTER xD");
Console.WriteLine(cipherm.cols.ToString() + ":" + cipherm.rows.ToString());
}
Matrix ress = new Matrix(keymx.rows, keymx.cols);
keymx = keymx + TwoMatrix;
ress = NotDiv(cipherm, keymx);
ress = ress - TwoMatrix;
Console.WriteLine(GetCharRep(ress).Substring(0, (int)(ress[0, 0])));
}
public static Matrix NotMul(Matrix m1, Matrix m2)
{
Matrix result = Matrix.ZeroMatrix(m1.cols, m1.rows);
for(int i = 0; i<m1.rows; i++)
{
for(int j = 0; j<m2.cols; j++)
{
result[i, j] = (m1[i, j] * m2[i, j]);
}
}
return result;
}
public static Matrix NotDiv(Matrix m1, Matrix m2)
{
Matrix result = Matrix.ZeroMatrix(m1.cols, m1.rows);
for(int i = 0; i<m1.rows; i++)
{
for(int j = 0; j<m2.cols; j++)
{
result[i, j] = m1[i, j] * (1/m2[i, j]);
}
}
return result;
}
public static Matrix GenMatrix(string key)
{
Matrix ret = new Matrix(key.Length, key.Length);
for(int i = 0; i<key.Length; i++)
{
for(int j = 0; j<key.Length; j++)
{
ret[i, j] = (byte)(Math.Pow((double)key[i], (double)key[j]) % byte.MaxValue);
}
}
return ret;
}
public static string GetCharRep(Matrix INM)
{
string ret = "";
for(int i = 0; i<INM.rows; i++)
{
for(int j = 0; j<INM.cols; j++)
{
ret += (char)((byte)INM[i, j] % byte.MaxValue);
}
}
return ret;
}
}
}
For a little bit of explanation:
1. The matrix class is burrowed from the internet and is too large to be put here.
2. Explaining the encryption algorithm:
Shortly all that happens is that the code generates two matrices, one from the plaintext and one from the key (you can guess how exactly it is generated by the code).
Then it multiplies each element of the key and the plaintext (NOT MATRIX MULITIPLICATION JUST EACH ELEMENT) the algorithm also involves random numbers e.t.c. But the problem I believe here is that the process of turning the key into the 'key matrix' is not repeated correctly the second time. Anyway I don't know a good solution so please help.
Ok, so I solved the first part, It isn't freezing any more I just changed the
for(int i = 0; i<times - 1; i++)
{
res = GetCharRep(GenMatrix(res));
}
to
for(int i = 0; i<times - 2; i++)
{
res = GetCharRep(GenMatrix(res));
}
But this time the dimensions of the ress matrix and the TwoMatrix Matrix don't match.
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();
}
}
}