Jagged Array Initialization and Assignment - c#

Working on a "Find the Island" game program. Will read in the number of rows and columns from the user and create a game map for play, using a char[][] array. Problem is, while it compiles and assigns the first character with no problem, after that I get an IndexOutOfRange exception and have to terminate the program. The code snippet is posted below, with the offending line marked. How do I fix this?
char[][] Waves = new char[Rows + 1][];
for (int counter = 0; counter < Rows+1; counter++)
Waves[counter] = new char[Columns];
MapRows = Rows;
MapCols = Columns;
for (int c = 0; c < Rows; c++)
{
for (int d = 0; d < Columns; d++)
{
if (c == 0 && d == 0)
Waves[c][d] = 'X';
else if (c == 0)
Waves[c][d] = (char)d; // Offending line here
else if (d == 0)
Waves[c][d] = (char)c;
else
Waves[c][d] = '~';
}
}
The map should appear as follows for a 3x3 map (spaces and line breaks will be added when printing):
X123
1~~~
2~~~
3~~~
Second, and much less important, I plan on printing the map to a read-only text box. How do I write it to the text box where I print a row of characters from the array, before ending that line and printing the next row of characters? The for loops are easy, getting it to print is not.

Related

Text from file to the end of 2d char array

I'm trying to solve the problem, but I just can't find the answer.
It is required to read a names.txt file, consisting of 5 words. After that, needs to convert them into char and then put the left side of the matrix and the bottom (look picture down). Other empty spaces need to fill with symbol "+".
I've tried many variations, but it doesn't display correctly.
Please help!
String txtFromFile = File.ReadAllText(#"C:\Users\source\names.txt");
Console.WriteLine("Words from file:\n{0}", txtFromFile);
int rows = 10;
int column = 10;
char[,] charArray = new char[rows, column];
for (int a = 0; a < rows; a++)
{
for (int b = 0; b < column; b++)
{
charArray[a, b] = '+';
Console.Write(string.Format("{0} ", charArray[a, b]));
}
Console.Write(Environment.NewLine + Environment.NewLine);
}
If you are inexperienced with Linq her is a solution without using it.
int rows = 10;
int column = 10;
int lineCount = 0; //pointer variable to be used when padding lines with +
string emptyLine = "";
emptyLine = emptyLine.PadRight(column, '+'); //create empty line string
string[] lines = File.ReadLines(#"C:\Users\source\names.txt").ToArray(); //read all lines and store in a string array variable
//add lines with only +
for (int row = 0; row < rows - lines.Length; row++)
{
Console.WriteLine(emptyLine);
}
//loop through all read lines and pad them
foreach (string line in lines)
{
lines[lineCount] = lines[lineCount].Replace(line, line.PadRight(column, '+')); //pad the line and replace it in the collection
Console.WriteLine(lines[lineCount]);
lineCount++;
}
This solution uses string instead of char[]. However, if you need to get the array you can simply find it in the read lines collection by
char[] charArray = lines[i].ToCharArray();
for an arbitrary index i in the read lines collection.
You can do it in one Line,
using System.Linq;
...
//Read all lines instead of reading all inputs in form of text.
//Note: Expecting all words should be are stored on different line.
string[] txtFromFile = File.ReadAllLines(#"C:\Users\source\names.txt");
var result = Enumerable.Range(0, 10) //Iterate for 10 lines
.Select(x => x < 5 // Check for line number
? new string('+', 10) //If line is from 0..4, then print ++++++++++
: txtFromFile[x-5].PadRight(10, '+') //else print word then pad it with ++
);
//Print the result
Console.WriteLine(string.Join(Environment.NewLine, result));
.NET Fiddle
output:
++++++++++
++++++++++
++++++++++
++++++++++
++++++++++
DOG+++++++
SHEEP+++++
CHIMPANZEE
BREAVER+++
LION++++++

Any idea why second element of array is not being assigned a value?

I have set up a spreadsheet program with a 26 by 26 grid of cell objects. I set up a method which processes a formula entered by the user. The user can enter, for example, =A1+A2 and the method checks the values of cells A1 and A2 and adds them together. For some reason, the value of the second cell is not being assigned to the array.
https://pasteboard.co/IqRO23M.png
The code continues the switch case statement for other operators but that's not important for this problem.
public static void ProcessBasicFormula(Cell selectedCell,Cell[,]
cell,string[] cellsInUse, char operatorInUse)
{
int[] valueOfCell = new int[cellsInUse.Length]; //valueOfCell and
cellInUse have same length
int counter = 0;
double answer = 0.0;
switch(operatorInUse)
{
case ('+'):
for (int i = 0; i < cellsInUse.Length; i++)
{
for (int j = 0; j < cellsInUse.GetLength(0); j++)
{
for (int k = 0; k < cellsInUse.GetLength(0); k++)
{
if (cellsInUse[i] == cell[j, k].CellID)
{
valueOfCell[counter] =Convert.ToInt32(cell[j,k].Text);
counter++;
}
}
}
}
answer = valueOfCell[0] + valueOfCell[1];
break;
I expect the values of the two cells to be added together but instead, I am getting the first value added by 0.
my assumptions are:
the cellsInUse array length is accurate
List item the cell value at index 1 is not zero
the new int[int] will initialize the array to zeros;
int[] valueOfCell = new int[cellsInUse.Length];
cellsInUse is one dimensional array;
string[] cellsInUse
the getLength(0) of one dimensional array is the same as .length
cellsInUse.length == 2 is true;
cellsInUse.GetLength(0) == 2 is true;
so the j and k loops are looping to 2.
I am assuming the first cell value was lucky enough to be in first subset of [2,2] cells.
should the cellsInUse.GetLength(0) be cell.GetLength(0) => j and cell.GetLength(1) => k

Simplify Selecting 2nd list based on a previous list in C#

I have 2 checked list boxes, where you select the main idea in the first one, and select a narrower focus in the 2nd box. After much work, I finally made it work, but it still seems horribly inefficient. Is there a way to optimize this?
List<int> k= new List<int>();
int f = 0;
for(int j = 0; j < SubRaces.Items.Count; j++) {
if(SubRaces.GetItemCheckState(j) == CheckState.Checked) {
f = j;
}
}
for(int i = 0; i < DNDSubRace.allSubRaces.Count; i++){
if(DNDSubRace.allSubRaces[i].MainRace.Name == Races.SelectedItem) {
k.Add(i);
}
}
DNDSubRace.allSubRaces [k [f]].DNDSubRaceDescription();
SubRaceBenefits.Text = DNDSubRace.allSubRaces [k [f]].Details;
You can optimize the code a little bit, for example you can add a break statement in the first for loop (this requires you to reverse the loop to get the exact same behaviour, provided SubRaces.GetItemCheckState() does not need to be called for every element)
List<int> k = new List<int>();
int f = 0;
for(int j = SubRaces.Items.Count - 1; j >= 0; j--) {
if(SubRaces.GetItemCheckState(j) == CheckState.Checked) {
f = j;
break;
}
}
for(int i = 0; i < DNDSubRace.allSubRaces.Count; i++){
if(DNDSubRace.allSubRaces[i].MainRace.Name == Races.SelectedItem) {
k.Add(i);
}
}
DNDSubRace.allSubRaces [k [f]].DNDSubRaceDescription();
SubRaceBenefits.Text = DNDSubRace.allSubRaces [k [f]].Details;
Another possibility is using Linq which will be slower, but is shorter to write. When using Linq to shorten the above solution, the result is:
List<int> k = DNDSubRace.allSubRaces.Where(r=>r.MainRace.Name == Races.SelectedItem).ToList();
int f = 0;
for(int j = SubRaces.Items.Count - 1; j >= 0; j--) {
if(SubRaces.GetItemCheckState(j) == CheckState.Checked) {
f = j;
break;
}
}
DNDSubRace.allSubRaces [k [f]].DNDSubRaceDescription();
SubRaceBenefits.Text = DNDSubRace.allSubRaces [k [f]].Details;
The first way of optimizing the code is reducing the number of cycles the upper for loop will be run for. When there are two matching elements in SubRaces then the variable f will be set to the index two times and the last match will stay (in the unoptimized version). If you reverse the for loop and exit it as soon as you get a match you will end up with the same behaviour, but it will be quicker.
The second rewrite wraps the second for loop into a Linq statement, which is slower but is shorter to write. Essentially it applies a filter and then copies the matching elements over to a new List.
I hope this helps!
Your answer would be to use events. When the item in the first list gets selected you can populate the second list with only its related options.

Appending to StringBuilder while there is nothing left

I have to the task to rearrange the words in a sentence backwards, but i am able to do it only for the first letter.Example: Fun exam right.What i have until now:
var sentance = Console.Readline().Split(' ');
var rearrangedSentence = new StringBuilder();
for(int i = 0,i<sentance.Lenght,i++)
{
rearrangedSentence.Append(sentance[i].Last());//this gives me "nmt"
}
My question is how to make this loop repeat itself while there is nothing left.
Any help will be greatly appriciated :)
EDIT: Question is
I mean if i have the sentence "Fun exam right" the result should be :nmtuahFxgeir . We first take the last chars of each word append that results in "nmt" then take the next one and add them resulting in "nmtuah" and so on
When you use sentance[i].Last(), you are only picking up the last element of your array.
EDIT: As per your updated requirements, you can use this code.
//Get the sentence array
var sentence = Console.ReadLine().Split(' ');
var rearrangedSentence = new StringBuilder();
//Get the length of longest word in array
int loopLength = sentence.OrderBy(n => n.Length).Last().Length;
int x = 0;
// Run for the length of longest word
for (int i = loopLength-1; i >=0 ; i--)
{
// need to pick up an element at every run for each element.
for (var j = 0; j < sentence.Length; j++)
{
//Picking the position of item to be picked up
int val = sentence[j].Length - (x + 1);
// If index not out of bounds
if(val >= 0 && val <= sentence[j].Length)
{
// Pick the character and append to stringbuilder.
rearrangedSentence.Append(sentence[j][val]);
}
}
// Next letter should be n-1, then n-2.
// Increase this. Val will decrease
x++;
}
Console.WriteLine(rearrangedSentence.ToString());
Console.ReadLine();

C# Printing a border around a 2D Array

I have a multidimensional array that I'm using as a box, and I have code that generates a border around it, like this:
#######
# #
# #
# #
# #
#######
However what I don't understand is that I can have either a 0 or a 1 in the "j == ProcArea.GetUpperBound(...)" part and it works successfully without any errors or unexpected output.
int[,] ProcArea = new int[rows, columns];
//Generate border
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < columns; j++)
{
if (i == 0 || j == 0 || i == ProcArea.GetUpperBound(0) || j == ProcArea.GetUpperBound(1))
{
ProcArea[i, j] = 2;
}
}
}
Why does this work, and what is the correct value I should be using?
Thanks
If the number of rows and columns are the same, then GetUpperBound(0) and GetUpperBound(1) are going to return the same value.
Arrays you create in C# (unless you call Array.CreateInstance directly) are always 0-based. So GetUpperBound(0) will always return rows - 1, and GetUpperBound(1) will always return columns - 1.
So the code will "work" regardless of which upper bound you check, although I think you'll find that if rows != columns, then using GetUpperBound(0) will create a different sized box than GetUpperBound(1).
By the way, an alternate way of making your border would be:
var maxRow = ProcArea.GetUpperBound(0);
var maxCol = ProcArea.GetUpperBound(1);
// do top and bottom
for (int col = 0; col <= maxCol; ++col)
{
ProcArea[0, col] = 2;
ProcArea[maxRow, col] = 2;
}
// do left and right
for (int row = 0; row <= maxRow; ++row)
{
ProcArea[row, 0] = 2;
ProcArea[row, maxCol] = 2;
}
It's slightly more code, true, but you don't waste time checking indexes unnecessarily. Won't make a difference with small arrays, of course.
Check the documentation http://msdn.microsoft.com/en-us/library/system.array.getupperbound.aspx. Your array has 2 dimensions (rows and columns).
ProcArea.GetUpperBound(0) is equivalent to rows - 1
ProcArea.GetUpperBound(1) is equivalent to columns - 1

Categories

Resources