I'm new to C# - I've got a 'Treasure Hunt' game here - it hides a 't' in a box, then the user inputs coordinates - if they get 't' it says they've won, if not then a 'm' is displayed.
I'm trying to setup save games linked to the name a user enters. It writes the save game to a txt file and stores it - that much works. But when I try to load the game I keep getting an error 'Index was outside the bounds of the array'.
static string username = "";
static string saveGame = "";
public const int BoardSize = 10;
static void Main(string[] args)
{
char[,] Board = new char[10, 10];
Console.WriteLine("Would you like to:");
Console.WriteLine("1. Start New Game");
Console.WriteLine("2. Load Game");
Console.WriteLine("9 Quit.");
int mainMenuChoice = 0;
mainMenuChoice = int.Parse(Console.ReadLine());
if (mainMenuChoice == 1)
{
Console.WriteLine("What is your name?");
username = Console.ReadLine();
}
else if (mainMenuChoice == 2)
{
Console.WriteLine("What was your username?");
username = Console.ReadLine();
saveGame = username + ".txt";
LoadGame(saveGame, ref Board);
}
else if (mainMenuChoice == 9)
{
Console.WriteLine("Closing in 3 seconds.");
Thread.Sleep(3000);
Environment.Exit(0);
}
Random randomOneX = new Random();
randomOneX = new Random(randomOneX.Next(0, 10));
int randomX = randomOneX.Next(0, BoardSize);
randomOneX = new Random(randomOneX.Next(0, 10));
int randomY = randomOneX.Next(0, BoardSize);
//Console.Write(randomX);
//Console.Write(randomY);
for (int i = 0; i < Board.GetUpperBound(0); i++)
{
for (int j = 0; j < Board.GetUpperBound(1); j++)
{
Board[i, j] = ' ';
}
}
Board[randomX, randomY] = 'x';
PrintBoard(Board);
int Row = 0;
int Column = 0;
bool wonGame = false;
Console.WriteLine();
Console.WriteLine("I've hidden a 't' in a map - you're job is to find the coordinates that have the 't' in.");
Console.WriteLine();
do
{
Console.Write("Please enter a Row: ");
bool validRow = false;
do
{
try
{
Row = int.Parse(Console.ReadLine());
validRow = true;
if (Row >= 10 || Row < 0)
{
Console.WriteLine("Please pick a number between 0-9: ");
validRow = false;
}
}
catch (Exception)
{
Console.WriteLine("Ooops, you've entered something that simply cannot be, please retry.");
}
} while (validRow == false);
Console.Write("Now enter a column: ");
bool validColumn = false;
do
{
try
{
Column = int.Parse(Console.ReadLine());
validColumn = true;
if (Column >= 10 || Column < 0)
{
Console.WriteLine("Please pick a number between 0-9: ");
validColumn = false;
}
}
catch (Exception)
{
Console.WriteLine("Ooops, you've entered something that simply cannot be, please retry.");
}
} while (validColumn == false);
if (Board[Row, Column] != 'x')
{
Board[Row, Column] = 'm';
Console.ForegroundColor = ConsoleColor.DarkRed;
Console.Clear();
Console.WriteLine("You've missed the target! Feel free to retry.");
Console.ForegroundColor = ConsoleColor.Gray;
wonGame = false;
PrintBoard(Board);
SaveGame(username, ref Board);
}
else
{
Board[Row, Column] = 't';
Console.Clear();
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("You've won!");
Console.ForegroundColor = ConsoleColor.Gray;
wonGame = true;
}
} while (wonGame == false);
PrintBoard(Board);
Console.ReadLine();
}
private static void PrintBoard(char[,] Board)
{
Console.WriteLine();
Console.WriteLine("The map looks like this: ");
Console.WriteLine();
Console.Write(" ");
for (int Column = 0; Column < BoardSize; Column++)
{
Console.Write(" " + Column + " ");
}
Console.WriteLine();
for (int Row = 0; Row < BoardSize; Row++)
{
Console.Write(Row + " ");
for (int Column = 0; Column < BoardSize; Column++)
{
if (Board[Row, Column] == '-')
{
Console.Write(" ");
}
else if (Board[Row, Column] == 'x')
{
Console.Write(" ");
}
else
{
Console.Write(Board[Row, Column]);
}
if (Column != BoardSize)
{
Console.Write(" | ");
}
}
Console.WriteLine();
}
}
private static void SaveGame(string username, ref char [,] inBoard)
{
StreamWriter sGame = null;
string saveFilePath = username + ".txt";
try
{
sGame = new StreamWriter(saveFilePath);
}
catch (Exception)
{
Console.WriteLine("Ooops there seems to be an error with saving your game. Check the log for details.");
}
for (int i = 0; i < inBoard.GetUpperBound(0); i++)
{
for (int j = 0; j < inBoard.GetUpperBound(1); j++)
{
sGame.Write(inBoard[i, j]);
}
sGame.WriteLine("");
}
sGame.Close();
}
private static void LoadGame(string GameFile, ref char[,] Board)
{
StreamReader saveGameReader = null;
string Line = "";
try
{
saveGameReader = new StreamReader(GameFile);
}
catch (Exception e)
{
StreamWriter errorMessage = new StreamWriter("ErrorLog.txt", true);
errorMessage.WriteLine(DateTime.Now + "Error: " + e.ToString());
errorMessage.Close();
Debug.WriteLine(e.ToString());
Console.WriteLine("There was an error loading game, check log for info. (Press Enter to exit.)");
Console.ReadLine();
Environment.Exit(0);
}
char[,] loadedBoard = Board;
for (int Row = 0; Row < BoardSize; Row++)
{
Line = saveGameReader.ReadLine();
for (int Column = 0; Column < BoardSize; Column++)
{
loadedBoard[Row, Column] = Line[Column];
}
}
Board = loadedBoard;
saveGameReader.Close();
}
}
}
The link to a notepad screenshot is : https://imgur.com/a/hobuv
The GetUpperBound returns, as MSDN says
Gets the index of the last element of the specified dimension in the
array.
So you are getting 9 everywhere you use that method. To fix your code you need to change your loops in the saving and initialization of the Board array with <= as exit condition from the loops
for (int i = 0; i <= Board.GetUpperBound(0); i++)
{
for (int j = 0; j <= Board.GetUpperBound(1); j++)
{
Board[i, j] = ' ';
}
}
Your save has 9 rows but your board size was defined as 10
If your values in the file are like below
m m m m m m m m X m m m
m m m m m X m m X m m m
m m m X m m m m X m m m
Then you can try with this approach
int i = 0;
// Read the file and work it line by line.
string[] lines = File.ReadAllLines(gameFile);
foreach(string line in lines)
{
string[] columns = line.Split(' ');
for(int j = 0; j < columns.Length; j++)
{
loadedBoarder[i, j] = columns[j];
}
i++;
}
#captainjamie : Thanks for correcting my code.
Related
{
int woodchuckSim = 0;
int numOfDays = 0;
bool validNumber = false;
bool validDays = false;
Random ran1 = new Random();
//display banner
//Ask user how many woodchucks to simulate
while(!validNumber)
{
Write("How many woodchucks would you like to simulate? (1 - 100) ");
int.TryParse(ReadLine(), out woodchuckSim);
if((woodchuckSim <= 0) || (woodchuckSim > 100))
{
WriteLine("\nPlease enter a correct amount of woodchucks to simulate: ");
}
else
{
validNumber = true;
}
}
//Ask user how many days to simulate
while(!validDays)
{
Write("\nHow many days would you like to simulate? (1 - 10) ");
int.TryParse(ReadLine(), out numOfDays);
if((numOfDays <= 0) || (numOfDays > 10))
{
WriteLine("Please enter a positive whole number between 1 and 10: ");
}
else
{
validDays = true;
}
}
//Using random class populate each cell between 1 and 50 that represents # of pieces of wood chucked by specific woodchuck on that specific day
int[,] sim = new int[woodchuckSim, numOfDays];
WriteLine($"{woodchuckSim} {numOfDays}");
for (int i = 0; i < sim.GetLength(0); i++)
{
for (int j = 0; j < sim.GetLength(1); j++)
{
sim[i, j] = ran1.Next(1, 50);
Write(sim[i, j] + "\t");
}
{
WriteLine(i.ToString());
}
}
WriteLine("Press any key to continue...");
ReadLine();
}
This is my code so far in my woodchuck simulation coding assignment but I need a columns and rows label on the side and top like the picture. I really don't have any idea how to do this, and I'm not sure if I'm missing a code or typed something wrong. Also at the end of the code it prints out the number of woodchucks simulated in a straight line like if the user typed in 15 it would print 0-14 in a straight line at the end which is not something I want, any help will be appreciated, thanks! (The second picture is what my code is printing)
There are a few steps to do this, but it's not too hard:
Write the column headers (include blank space at the beginning where the row headers go
Write the column underlines
For each row, write the row header first
Then for each column in the row, write the column data
After the column data is written, write a newline to start the next row
Here's a sample that produces a table similar to your output. Note that we use PadLeft to pad each column data with spaces so they're all the same width. I've also included Sum and Avg columns based on your comment below. Additionally, to clean up the main code, I added methods to write text in a different color and a method to get an integer from the user:
private static readonly Random Random = new Random();
private static void WriteColor(string text,
ConsoleColor foreColor = ConsoleColor.Gray,
ConsoleColor backColor = ConsoleColor.Black)
{
Console.ForegroundColor = foreColor;
Console.BackgroundColor = backColor;
Console.Write(text);
Console.ResetColor();
}
private static void WriteLineColor(string text,
ConsoleColor foreColor = ConsoleColor.Gray,
ConsoleColor backColor = ConsoleColor.Black)
{
WriteColor(text + Environment.NewLine, foreColor, backColor);
}
public static int GetIntFromUser(string prompt, Func<int, bool> validator = null)
{
var isValid = true;
int result;
do
{
if (!isValid)
{
WriteLineColor("Invalid input, please try again.", ConsoleColor.Red);
}
else isValid = false;
Console.Write(prompt);
} while (!int.TryParse(Console.ReadLine(), out result) ||
(validator != null && !validator.Invoke(result)));
return result;
}
public static void Main()
{
int columnWidth = 6;
ConsoleColor sumForeColor = ConsoleColor.DarkRed;
ConsoleColor sumBackColor = ConsoleColor.Gray;
ConsoleColor avgForeColor = ConsoleColor.White;
ConsoleColor avgBackColor = ConsoleColor.DarkGreen;
int numWoodchucks = GetIntFromUser(
"How many woodchucks would you like to simulate? (1 - 100) ... ",
x => x >= 1 && x <= 100);
int numDays = GetIntFromUser(
"How many days would you like to simulate? (1 - 10) .......... ",
x => x >= 1 && x <= 10);
int[,] data = new int[numWoodchucks, numDays];
// Write column headers, starting with a blank row header
Console.WriteLine();
Console.Write(new string(' ', columnWidth));
for (int col = 1; col <= data.GetLength(1); col++)
{
Console.Write($"{col}".PadLeft(columnWidth));
}
Console.Write(" ");
WriteColor("Sum".PadLeft(columnWidth - 1), sumForeColor, sumBackColor);
Console.Write(" ");
WriteLineColor("Avg".PadLeft(columnWidth - 1), avgForeColor, avgBackColor);
// Write column header underlines
Console.Write(new string(' ', columnWidth));
for (int col = 0; col < data.GetLength(1); col++)
{
Console.Write(" _____");
}
Console.Write(" ");
WriteColor("_____", sumForeColor, sumBackColor);
Console.Write(" ");
WriteLineColor("_____", avgForeColor, avgBackColor);
int total = 0;
for (int row = 0; row < data.GetLength(0); row++)
{
// Write row header
Console.Write($"{row + 1} |".PadLeft(columnWidth));
int rowSum = 0;
// Store and write row data
for (int col = 0; col < data.GetLength(1); col++)
{
data[row, col] = Random.Next(1, 50);
Console.Write($"{data[row, col]}".PadLeft(columnWidth));
rowSum += data[row, col];
}
// Write sum and average
Console.Write(" ");
WriteColor($"{rowSum}".PadLeft(columnWidth - 1),
sumForeColor, sumBackColor);
Console.Write(" ");
WriteLineColor($"{Math.Round((double) rowSum / data.GetLength(1), 1):F1}"
.PadLeft(columnWidth - 1), avgForeColor, avgBackColor);
total += rowSum;
}
// Write the sum of all the items
Console.Write(new string(' ', columnWidth + columnWidth * data.GetLength(1) + 1));
WriteColor("_____", sumForeColor, sumBackColor);
Console.Write(" ");
WriteLineColor("_____", avgForeColor, avgBackColor);
// Write the average of all the items
Console.Write(new string(' ', columnWidth + columnWidth * data.GetLength(1) + 1));
WriteColor($"{total}".PadLeft(columnWidth - 1), sumForeColor, sumBackColor);
Console.Write(" ");
WriteLineColor(
$"{Math.Round((double) total / (data.GetLength(0) * data.GetLength(1)), 1):F1}"
.PadLeft(columnWidth - 1), avgForeColor, avgBackColor);
Console.Write("\nPress any key to continue...");
Console.ReadKey();
}
Output
Not tested, but something like this:
Write("\t");
for (int i = 0; i < sim.GetLength(0); i++)
{
Write(i.ToString() + "\t");
}
WriteLine("\t");
for (int i = 0; i < sim.GetLength(0); i++)
{
Write("_____\t");
}
WriteLine();
for (int i = 0; i < sim.GetLength(0); i++)
{
{
WriteLine(i.ToString().PadLeft(3) + " |\t");
}
for (int j = 0; j < sim.GetLength(1); j++)
{
sim[i, j] = ran1.Next(1, 50);
Write(sim[i, j] + "\t");
}
}
Like I said, not tested, just typed right into the editor here, but that should get you close. Also, look at the string.PadLeft(int) function to get your numbers to be right-justified like the example.
I wonder how to do or write a code that it will print out no one got 20 points and it has to write a number of line. Everything works except if (is20 == false). How to fix it?
using System;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
double[,] points = new double[50, 5];
Random r = new Random();
for (int k = 0; k < 50; k++)
{
for (int j = 0; j < 5; j++)
{
points[k, j] = r.NextDouble() * 5 + 15.5;
if (points[k, j] > 20) points[k, j] = 20;
Console.Write("{0:f1}", points[k, j]);
Console.Write(" ");
}
Console.WriteLine();
}
bestEstimated(points);
Console.ReadLine();
}
public static void bestEstimated(double[,] points)
{
bool is20 = false;
for (int line = 0; line < 50; line++)
{
for (int column = 0; column < 5; column++)
{
if (points[line, column] == 20)
{
Console.WriteLine("20 points got: " + line + " competitor");
is20 = true;
break;
}
}
}
if (is20 == false)
{
Console.WriteLine("No one got 20 points: ");
}
}
}
}
You can set is20=false in inner loop in else part and check it inside outer loop after inner loop.
public static void bestEstimated(double[,] points)
{
bool is20 = false;
for (int line = 0; line < 10; line++)
{
for (int column = 0; column < 5; column++)
{
if (points[line, column] == 20)
{
Console.WriteLine("20 points got: " + line + " competitor");
is20 = true;
break;
}
else
{
is20=false;
}
}
if (!is20)
{
Console.WriteLine("20 points not got: " + line + " competitor");
}
}
if(is20 == false)
{
Console.WriteLine("No one got 20 points: ");
}
}
Just a wild guess from your comments below your question:
public static void bestEstimated(double[,] points)
{
var not20Points = new List<int>();
for (int line = 0; line < 50; line++)
{
bool is20 = false;
for (int column = 0; column < 5; column++)
{
if (points[line, column] == 20)
{
Console.WriteLine("20 points got: " + line + " competitor");
is20 = true;
break;
}
}
if (is20 == false)
{
Console.WriteLine("competitor" + line + " didnt get 20 points"); //also can print it here if ya want...
not20Points.Add(line);
}
}
if (not20Points.Count == 50)
{
Console.WriteLine("No one got 20 points");
}
else
{
Console.WriteLine("Those lines did get 20 points: " + string.Join(",", Enumerable.Range(0, 50).Except(not20Points)));
Console.WriteLine("Those lines didnt get 20 points: " + string.Join(",", not20Points));
}
}
(Updated my version, to only print stuff if atleast one column has 20 points)
This question already has answers here:
C# dictionary value clearing out when I clear list previously assigned to it....why?
(6 answers)
What is the difference between a reference type and value type in c#?
(15 answers)
Closed 5 years ago.
My array of objects when printed only returns the value of the last group of objects entered. so if i enter a set of values in at the end it will only print out the last set of data.
namespace classschedule
{
class Program
{
static void Main(string[] args)
{
Course[] newarray = new Course[25];
Course[ , ] mycoursearray = new Course[6,5];
Course info = new Course();
int sections, classregistration, periods;
string names, classday;
for (int x1 = 0; x1 < 6; x1++)
{
for (int y1 = 0; y1 < 5; y1++)
{
mycoursearray[x1, y1] = new Course();
}
}
for (int x1 = 0; x1<5;x1++)
{
newarray[x1] = new Course();
}
int x = 0;
int y = 0;
for (int g = 0; g <= 4; g++)
{
for (int h = 0; h <= 5; h++)
{
info.busy = 0;
info.section = 0;
info.classize = 0;
info.classname = "";
mycoursearray[h, g] = info;
}
}
for (int j = 0; j < 24; j++)
{
Console.WriteLine("please enter class name: ");
names = Console.ReadLine();
char choice = 'y';
Console.WriteLine("please enter the section of your class: ");
sections = Convert.ToInt32(Console.ReadLine());
while (choice == 'y' || choice == 'Y')
{ if (sections <= 90)
{
choice = 'n';
}
else
{
Console.WriteLine("Section is to high must be below 90");
choice = 'n';
}
}
Console.WriteLine("Please enter the amount of students in the class: ");
classregistration = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("Please enter the first letter of the day of the class **for thursday please type X");
classday = Console.ReadLine();
Console.WriteLine("Please enter your class period");
periods = Convert.ToInt32(Console.ReadLine());
x = periods - 1 ;
if (classday == "M")
y = 0;
else if (classday == "T")
y = 1;
else if (classday == "W")
y = 2;
else if (classday == "X")
y = 3;
else if (classday == "F")
y = 4;
info.classname = names;
info.section = sections;
info.classize = classregistration;
info.busy = 1;
mycoursearray[x, y] = info;
newarray[y+1] = info;
}
{
for (int i = 0; i < 6; i++)
{
for (int j = 0; j < 5 ; j++)
{
Console.Write(mycoursearray[i, j].classname +" " + mycoursearray[i, j].section+ " " + mycoursearray[i, j].classize);
//Console.Write(mycoursearray[i, j].section);
//Console.Write(mycoursearray[i, j].classize);
}
Console.WriteLine();
}
}
Console.ReadLine();
}
class Course
{
public int section;
public string classname;
public int classize;
public int busy;
}
}
}
I am trying to create a program that is will take letters as input only and not duplicated. I am getting error when i put one letter in an input.
This is what i need to do, I need to get the user input in each line (like a enter, b enter, etc), if there is a duplication value i need a error message and continues with the input, and if there is incorrect value i get another error stating such. I cannot use LINQ, Hashset, nor list, it has to be arrays.
static void Main(string[] args)
{
char[] Array = new char[5];
Console.WriteLine("Please Enter 5 Letters B/W a through j only: ");
string letters = "abcdefghij";
char[] read = Console.ReadLine().ToLower().ToCharArray();
//loop through array
for (int i = 0; i < 5; i++)
{
if (letters.Contains(read[i]) && !Array.Contains(read[i]))
{
Array[i] = read[i];
}
else
{
Console.WriteLine("You have entered an incorrect value");
}
}
Console.WriteLine("You have Entered the following Inputs: ");
for (int i = 0; i < Array.Length; i++)
{
Console.WriteLine(Array[i]);
}
Console.ReadKey();
}
I think this more or less does what you want:
var max = 5;
var array = new char[max];
var letters = "abcdefghij";
var count = 0;
while (count < 5)
{
Console.WriteLine("Please Enter {0} Letters B/W a through j only: ", max);
var key = Console.ReadKey();
var read = key.KeyChar
if (!letters.Contains(read))
{
Console.WriteLine("You have entered an incorrect value");
continue;
}
var found = false;
for (int i = 0; i < count; i++)
{
if (array[i] == read)
{
found = true;
}
}
if (found)
{
Console.WriteLine("You have entered an duplicate value");
continue;
}
array[count++] = read;
}
Console.WriteLine("You have Entered the following Inputs: ");
for (int i = 0; i < array.Length; i++)
{
Console.WriteLine(array[i]);
}
Console.ReadKey();
If you want the user to enter the values individually then you would need to request each character in a loop.
Something like:
static void Main(string[] args)
{
const string validValues = "abcdefghij";
var enteredCharacters = new char[5];
for (int i = 0; i < enteredCharacters.Length; i++)
{
Console.WriteLine("Please enter a unique character between a and j");
var input = Console.ReadLine();
if (input.Length == 0)
{
Console.WriteLine("You did not enter a value.");
return;
}
if (input.Length > 1)
{
Console.WriteLine("You have entered more than 1 character");
return;
}
var character = input[0];
if (!validValues.Contains(character))
{
Console.WriteLine("You have entered an invalid character");
return;
}
if (enteredValues.Contains(character))
{
Console.WriteLine("You have already entered this character");
return;
}
enteredCharacters[i] = character;
}
// process numbers.
}
this is you problem
for (int i = 0; i < 5; i++)
this is your fix:
static void Main(string[] args)
{
char[] Array = new char[5];
Console.WriteLine("Please Enter 5 Letters B/W a through j only: ");
string letters = "abcdefghij";
char[] read = Console.ReadLine().ToLower().ToCharArray();
//loop through array
for (int i = 0; i < read.Length; i++)
{
if (letters.Contains(read[i]) && !Array.Contains(read[i]))
{
Array[i] = read[i];
}
else
{
Console.WriteLine("You have entered an incorrect value");
}
}
Console.WriteLine("You have Entered the following Inputs: ");
for (int i = 0; i < Array.Length; i++)
{
Console.WriteLine(Array[i]);
}
Console.ReadKey();
}
If I wanted to modify a console app that currently prints:
1
12
123
1234
to print
1
121
12321
1234321
Which loop should i modify?
Below is the code from the original console app.
int altura; string space = ""; int cont2 = 0;
Console.Write("Dar altura: ");
altura = int.Parse(Console.ReadLine());
for (int i = 1; i <= altura; i++)
{
space = "";
for (int j = 1; j <= i; j++)
{
space = space + Convert.ToString(j);
}
Console.WriteLine(space);
}
Console.ReadLine();
Thank you in advance.
Try this
int altura; string space = "";
int cont2 = 0;
Console.Write("Dar altura: ");
altura = int.Parse(Console.ReadLine());
for (int i = 1; i <= altura; i++)
{
space = "";
for (int j = 1; j <= i; j++)
{
space = space + Convert.ToString(j);
}
for (int k = i - 1; k >= 1 ; k--)
{
space = space + Convert.ToString(k);
}
Console.WriteLine(space);
}
Console.ReadKey();
int altura; string space = ""; int cont2 = 0;
Console.Write("Dar altura: ");
altura = int.Parse(Console.ReadLine());
for (int i = 1; i <= altura; i++)
{
var stack = new System.Collections.Generic.Stack<int>();
space = "";
for (int j = 1; j <= i; j++)
{
space = space + Convert.ToString(j);
stack.Push(j);
}
stack.Pop();
while (stack.Count > 0)
{
space = space + Convert.ToString(stack.Pop())
}
Console.WriteLine(space);
}
Console.ReadLine();
Or for fun:
int altura;
Console.Write("Dar altura: ");
altura = int.Parse(Console.ReadLine());
var lines = Enumerable.Range(1, altura).Select(i =>
{
var line = Enumerable.Range(1, i).ToArray();
var reverse = line.Reverse().Skip(1).ToArray();
return String.Join("", line.Concat(reverse).Select(c => c.ToString()).ToArray())
});
foreach(string line in lines)
{
Console.Writeline(line);
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
namespace Rextester
{
public class Program
{
public static void Main(string[] args)
{
int rows=5;
for(int i=1;i<=rows;i++){
for(int j=1;j<=i;j++){
Console.Write(" "+j);
}
for(int k=i-1;k>=1;k--){
Console.Write(" "+k);
}
Console.WriteLine();
}
}
}
}