This is a C# program for a battleship game. When the user inputs their guess, I need either a black X for miss or a red X for hit to display on the grid. I rendered the original grid and added letters for columns and numbers for rows. I'm not sure what I need to do to get the hit and miss to show up on the grid and could use some suggestions. This is my very first C# program so I'm a little new to this. Thanks!
//the basic grid
private static readonly char[,] Grid = new char[,]
{
{'.', '.', '.', '.', 'S', 'S', 'S', '.', '.', '.'},
{'P', 'P', '.', '.', '.', '.', '.', '.', '.', '.'},
{'.', '.', '.', '.', '.', '.', '.', '.', '.', 'P'},
{'.', '.', '.', '.', '.', '.', '.', '.', '.', 'P'},
{'.', '.', 'A', 'A', 'A', 'A', 'A', '.', '.', '.'},
{'.', '.', '.', '.', '.', '.', '.', 'B', '.', '.'},
{'.', 'S', '.', '.', '.', '.', '.', 'B', '.', '.'},
{'.', 'S', '.', '.', '.', '.', '.', 'B', 'P', 'P'},
{'.', 'S', '.', '.', '.', '.', '.', 'B', '.', '.'},
{'.', '.', '.', '.', '.', '.', '.', '.', '.', '.'},
};
public static void printGrid(Char[,] Grid)
{
//Improve the rendering so that the grid
Console.WriteLine(" | A | B | C | D | E | F | G | H | I | J |");
Console.WriteLine("-----#-----#-----#-----#-----#-----#-----#-----#-----#-----#------#");
for (int i = 0; i < 10; i )
{
if (i == 9)
{
Console.Write(" {0} ", i 1);
}
else
Console.Write(" {0} ", i 1);
for (int j = 0; j < 10; j )
{
ShipColors(Grid[i, j]);
}
//match header
Console.Write(" |\r\n");
Console.WriteLine("-----#-----#-----#-----#-----#-----#-----#-----#-----#-----#------#");
}
}
//declare colors of each ship
public static void ShipColors(char color)
{
/*
* A = Aircraft Carrier
* B = Battleship
* P = patrol boat
* S = Submarine
* H = Hit
* M = Miss
*/
switch (color)
//color ships
{
case '.':
Console.Write(" | ");
//Blank space here needed to be added for formatting the cells properly.
Console.Write(" ");
break;
case 'A':
Console.Write(" | ");
Console.BackgroundColor = ConsoleColor.Yellow;
Console.Write(" A ");
break;
case 'B':
Console.Write(" | ");
Console.BackgroundColor = ConsoleColor.Cyan;
Console.ForegroundColor = ConsoleColor.Black;
Console.Write(" B ");
break;
case 'P':
Console.Write(" | ");
Console.BackgroundColor = ConsoleColor.DarkBlue;
Console.ForegroundColor = ConsoleColor.Black;
Console.Write(" P ");
break;
case 'S':
Console.Write(" | ");
Console.BackgroundColor = ConsoleColor.Red;
Console.ForegroundColor = ConsoleColor.Black;
Console.Write(" S ");
break;
case 'H':
Console.Write(" | ");
Console.ForegroundColor = ConsoleColor.Red;
Console.Write(" X ");
break;
case 'M':
Console.Write(" | ");
Console.ForegroundColor = ConsoleColor.White;
Console.Write(" X ");
break;
}
Console.ResetColor();
}
}
}
CodePudding user response:
After you have validated the player's move, you're showing what they did;
if (char.IsLetter(Grid[rowNumber, colNumber]))
{
Console.WriteLine(userGuess " is a HIT!");
}
else
{
Console.WriteLine(userGuess " is a MISS.");
}
But you aren't storing anything to remember it.
Do you want to show the player where the ships are? Or do you want to reveal them only when they are hit?
I would create a second grid to represent the "fog of war", as visible to the player.
private static readonly char[,] FOW = new char[,] { ... };
Assign the Hit or Miss into that array;
if (char.IsLetter(Grid[rowNumber, colNumber]))
{
Console.WriteLine(userGuess " is a HIT!");
FOW[rowNumber, colNumber] = 'H';
}
else
{
Console.WriteLine(userGuess " is a MISS.");
FOW[rowNumber, colNumber] = 'M';
}
And print it instead;
printGrid(FOW);
When the game is over, you can print the grid showing where all the ships really were.
CodePudding user response:
I've made a version of your code that does what you want and might give you some coding ideas moving forward.
The key thing I did was to define a second grid for your guesses.
char[,] grid = new char[,]
{
{ '.', '.', '.', '.', 'S', 'S', 'S', '.', '.', '.' },
{ 'P', 'P', '.', '.', '.', '.', '.', '.', '.', '.' },
{ '.', '.', '.', '.', '.', '.', '.', '.', '.', 'P' },
{ '.', '.', '.', '.', '.', '.', '.', '.', '.', 'P' },
{ '.', '.', 'A', 'A', 'A', 'A', 'A', '.', '.', '.' },
{ '.', '.', '.', '.', '.', '.', '.', 'B', '.', '.' },
{ '.', 'S', '.', '.', '.', '.', '.', 'B', '.', '.' },
{ '.', 'S', '.', '.', '.', '.', '.', 'B', 'P', 'P' },
{ '.', 'S', '.', '.', '.', '.', '.', 'B', '.', '.' },
{ '.', '.', '.', '.', '.', '.', '.', '.', '.', '.' },
};
int numbers = grid.GetLength(0);
int letters = grid.GetLength(1);
char?[,] guesses = new char?[numbers, letters];
The above code is the first part of the Main
method.
The grid guesses
is automatically created with every value being null
. When you get a hit or a miss you can assign H
and M
respectively.
I changed printGrid
to PrintGrid
to follow the C# naming conventions.
I also made PrintGrid
responsible for all Console
manipulation. It's job is to display the grid, plus any messages.
static void PrintGrid(char[,] grid, char?[,] guesses, int numbers, int letters, string message)
{
Console.Clear();
var colors = new Dictionary<char, (ConsoleColor back, ConsoleColor fore)>()
{
{ 'A', (back: ConsoleColor.Black, fore: ConsoleColor.Yellow) },
{ 'B', (back: ConsoleColor.Black, fore: ConsoleColor.Cyan) },
{ 'P', (back: ConsoleColor.Black, fore: ConsoleColor.DarkBlue) },
{ 'S', (back: ConsoleColor.Black, fore: ConsoleColor.Red) },
{ 'H', (back: ConsoleColor.White, fore: ConsoleColor.Red) },
{ 'M', (back: ConsoleColor.Black, fore: ConsoleColor.White) },
};
IEnumerable<char> GetRow(int n)
{
for (int i = 0; i < letters; i )
{
yield return guesses[n, i] ?? grid[n, i];
}
}
void WriteLine(int? number, IEnumerable<char> line, char filler, char separator, bool useColors = false)
{
Console.Write($"{number}{filler}".PadLeft(5, filler));
Console.Write(separator);
foreach (var c in line)
{
Console.Write($"{filler}{filler}");
if (useColors && colors.ContainsKey(c))
{
Console.BackgroundColor = colors[c].back;
Console.ForegroundColor = colors[c].fore;
}
Console.Write(c);
Console.ResetColor();
Console.Write($"{filler}{filler}{separator}");
}
Console.WriteLine();
}
WriteLine(null, Enumerable.Range(0, letters).Select(n => (char)('A' n)), ' ', '|');
WriteLine(null, new string('-', letters), '-', '#');
for (int i = 0; i < numbers; i )
{
WriteLine(i 1, GetRow(i), ' ', '|', true);
}
WriteLine(null, new string('-', letters), '-', '#');
if (!String.IsNullOrWhiteSpace(message))
{
Console.WriteLine();
Console.WriteLine(message);
}
Console.WriteLine();
Console.Write("Enter your guess (e.g. A2) or Q to quit: ");
}
It has also been written to handle any practical size grid - just change the initial definition of grid
to have any number of rows or columns you like.
Finally, to display a hit or a miss rather than the ship in the grid I've included this code:
yield return guesses[n, i] ?? grid[n, i];
This returns the guess if there's a value and the underlying grid value if there isn't.
The remainder of the code in the Main
method is this:
char lastLetter = (char)('A' letters - 1);
Regex regex = new Regex($"^([A-{lastLetter}])(\\d{{1,2}})$");
string message = "";
while (true)
{
PrintGrid(grid, guesses, numbers, letters, message);
string userGuess = (Console.ReadLine() ?? "").ToUpper();
if (userGuess == "Q") return;
Match match = regex.Match(userGuess);
if (match.Success)
{
int rowNumber = int.Parse(match.Groups[2].Value) - 1;
if (rowNumber < numbers)
{
int colNumber = userGuess[0] - 65;
bool isHit = char.IsLetter(grid[rowNumber, colNumber]);
guesses[rowNumber, colNumber] = isHit ? 'H' : 'M';
message = $"{userGuess} is a {(isHit ? "HIT" : "MISS")}!";
}
}
else
{
message = "Guess must be in the form of ColumnRow, like: B5";
}
}
Here's an example of a smaller grid in action:
| A | B | C | D |
-----#-----#-----#-----#-----#
1 | . | . | . | . |
2 | P | H | . | . |
3 | . | M | A | A |
4 | M | . | . | . |
5 | . | S | . | . |
6 | . | S | . | . |
7 | . | S | . | . |
8 | . | . | . | . |
-----#-----#-----#-----#-----#
B2 is a HIT!
Enter your guess (e.g. A2) or Q to quit:
I hope this is of interest.