In: Computer Science
Module 2 Programming Assignment – Battleship Refactor
Refactor your Battleship drawing code from Module 1.
Download the OO template for the basic battleship game, BattleshipRefactor.zip (refer below)
The template has the outline of a battleship game using OO constructs. You need to add the Grid class and complete the code so that it runs correctly.
At a minimum, you need to complete the Draw and DropBomb methods with code similar to the previous assignment. There will be changes due to the different layout, but the core of your code will do the same thing.
In this Module we are adding 2 new features:
You may add as many other methods, fields or properties as you feel are required for the assignment.
Notes:
The code will be tested with grids ranging in size from 5 (the smallest you can fit a size 5 ship) upwards. Make sure that all aspects of the game work correctly without crashing or hanging.
You must use the template code provided!
Like in Module 1, please make sure you show the ships in the grid. At this point we are merely testing our game logic and hidden ships make the game very hard to test.
BattleShipGame.cs
using System;
namespace BattleshipSimple
{
internal class BattleShipGame
{
private Grid grid;
public BattleShipGame(int gridSize)
{
grid = new Grid(gridSize);
}
internal void Reset()
{
grid.Reset();
}
internal void Play()
{
while (grid.HasShipsLeft)
{
grid.Draw();
//Read input from user into x, y
int x, y;
grid.DropBomb(x, y);
}
}
}
}
Program.cs
using System;
namespace BattleshipSimple
{
class Program
{
static void Main(string[] args)
{
var game = new BattleShipGame(10);
ConsoleKeyInfo response;
do
{
game.Reset();
game.Play();
Console.WriteLine("Do you want to play again (y/n)");
response = Console.ReadKey();
} while (response.Key == ConsoleKey.Y);
}
}
}
Working code implemented in C# and appropriate comments provided for better understanding.
Here I am attaching code for all files:
Program.cs:
using System;
namespace BattleshipSimple
{
class Program
{
static void Main(string[] args)
{
var game = new BattleShipGame(10);
ConsoleKeyInfo response;
do
{
game.Play();
Console.WriteLine("Do you want to play again (y/n)");
response = Console.ReadKey();
} while (response.Key == ConsoleKey.Y);
}
}
}
Grid.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
//this class is designed to handle the data pertaining to the game
space
namespace BattleshipSimple
{
class Grid
{
//variables for parsing the different console colors
ConsoleColor planeForground = Console.ForegroundColor;
Dictionary<char, ConsoleColor> ShipColors = new
Dictionary<char, ConsoleColor>();
//variable for holding the master, unaltered grid.
internal char[,] masterGrid;
internal int size;
//initialize the grid and put the colors in the
dictionary.
public Grid(int gridSize) {
//load the colors into the dictionary
ShipColors.Add('S', ConsoleColor.Blue);
ShipColors.Add('P', ConsoleColor.Cyan);
ShipColors.Add('A', ConsoleColor.Green);
ShipColors.Add('B', ConsoleColor.Yellow);
ShipColors.Add('C', ConsoleColor.Magenta);
ShipColors.Add('.', planeForground);
masterGrid = new char[gridSize, gridSize];
size = gridSize;
}
//if it is now Hit, Miss, or '.' then
internal void DropBomb(int X, int Y)
{
if (masterGrid[X, Y] != 'H' | masterGrid[X, Y] != 'M' |
masterGrid[X, Y] != '.')
{ //than mark it as a hit.
masterGrid[X, Y] = 'H';
}
else
{ //else mark it as a miss
masterGrid[X, Y] = 'M';
}
}
//draws the current information from "workingGrid" onto the
console.
public void Draw()
{
//first clear the console
Console.Clear();
//write the top letter guide
Console.Write(" ");
for(int i = 0; i < size; i++)
{ //write the correct alphabetical char to the spot on the
grid
Console.Write(Convert.ToChar(65 + i));
if(i != size - 1)
{ //if we are not at the end, add a '-'
Console.Write("-");
}
}
Console.WriteLine();
//iterate through the rows
for (int row = 0; row < size; row++)
{
//and columns
for (int column = 0; column < size; column++)
{
//if we are on the first column of the line, add the row
number.
if (column == 0)
{
Console.Write("{0,2}", row + 1);
}
//if there is a hit at that location, set it to red and print an
X
if (masterGrid[row, column] == 'H')
{
Console.ForegroundColor = ConsoleColor.Red;
Console.Write("X");
Console.ForegroundColor = planeForground;
}
else if (masterGrid[row, column] == 'M')
{
Console.Write("X");
}
//if there is a miss at the location, set the color to
else
{
Console.ForegroundColor = ShipColors[masterGrid[row,
column]];
Console.Write(masterGrid[row, column]);
Console.ForegroundColor = planeForground;
}
//add the last piece of the grid to the row
Console.Write("|");
}
//end the current line and print the next bar to the console.
Console.WriteLine();
}
//now print the lower part of the grid.
Console.Write(" ");
for (int i = 0; i < size; i++)
{
Console.Write("#");
if (i != size - 1)
{
Console.Write("-");
}
}
}
//replace every value inside the grid with '.'
public void Reset()
{
for (int row = 0; row < size; row++) {
for (int col = 0; col < size; col++) {
masterGrid[row, col] = '.';
}
}
}
//checks to see if the grid has anything other than '.', 'H', or
'M' left.
public bool HasShipsLeft()
{
for (int row = 0; row < size; row++)
{
for (int col = 0; col < size; col++)
{
if (masterGrid[row, col] != '.' | masterGrid[row,col] != 'H' |
masterGrid[row,col] != 'M' )
{
return true;
}
}
}
return false;
}
//returns true if the ship will fit in the horizontal
direction
bool horizontalCheck(int x, int y, int length)
{
try
{
for (int i = 0; i < length; i++)
{
if (masterGrid[x, y + i] != '.')
{
return false;
}
}
return true;
}
catch (IndexOutOfRangeException)
{
return false;
}
}
//returns true if the ship will fit in the vertical
direction
bool verticalCheck(int x, int y, int length)
{
try
{
for (int i = 0; i < length; i++)
{
if (masterGrid[x + i, y] != '.')
{
return false;
}
}
return true;
}
catch (IndexOutOfRangeException)
{
return false;
}
}
//populate generates a given number of ships onto the grid in
random locations.
public void populate(int shipCount)
{
Reset(); //first, reset the grid to be empty.
Random rng = new Random(); //ship placement will be random.
int row = 0; //variables for the row and column
int col = 0;
bool vertHor = false; //vert is true, hor is false.
int shipNum = 0; //this variable holds what ship we are working on
out of our total ships.
int shipSize = 1; //shipSize holds the amount of squares the ship
takes. initialized to 1 because you cant have a ship of size
0
char shipChar = 'S'; //shipChar holds the char that the ship will
be. initialized to 'S' by default.
//iterate for each ship that needs placing.
do
{
//get a random location and direction for the ship
row = rng.Next(0, size);
col = rng.Next(0, size);
//generate a random true or false.
vertHor = (rng.Next(100) >= 50);
switch (shipNum + 1)
{
case 1: shipSize = 1; shipChar = 'S'; break;
case 2: shipSize = 2; shipChar = 'P'; break;
case 3: shipSize = 3; shipChar = 'A'; break;
case 4: shipSize = 4; shipChar = 'B'; break;
case 5: shipSize = 5; shipChar = 'C'; break;
default: shipSize = 1; shipChar = 'S'; break;
}
//first check to see if the desired location is available
if(masterGrid[row,col] == '.')
{
//make sure the ship has room.
if(horizontalCheck(row,col,shipSize) == true &
verticalCheck(row, col, shipSize) == true)
{
//if there is room, increment the counter. if there is not room,
the counter does not get incremented.
for(int i = 0; i < shipSize; i++)
{
if (vertHor)
{
masterGrid[row, col + i] = shipChar;
}
else
{
masterGrid[row + i, col] = shipChar;
}
}
shipNum++;
}
}
} while (shipNum < shipCount);
}
}
}
BattleShipGame.cs:
using System;
namespace BattleshipSimple
{
internal class BattleShipGame
{
private Grid grid;
public BattleShipGame(int gridSize)
{
grid = new Grid(gridSize);
grid.populate(5);
}
internal void Reset()
{
grid.Reset();
}
//quick function to convert chars 'a' through 'z' to an int 0 -
24 (25? off by one errors always confuse me)
private int letterToInt(string letter)
{
return letter[0] - 65;
}
internal void Play()
{
while (grid.HasShipsLeft())
{
grid.Draw();
//get the input from the user
string[] raw;
Console.WriteLine("\nEnter a coordinate in the format A:1");
//parse it, and execute dropbomb
raw = Console.ReadLine().Split(':');
grid.DropBomb(Int32.Parse(raw[1]) - 1, letterToInt(raw[0]));
}
}
}
}