I recently whipped up a Battleship program with Java as part of my Basic OOP class in university. The class is done but all we get are grades. I would really love, though, to know where and what I can improve upon. Is there a better way to implement my code? (It's still my first year in software engineering, just in case you see glaring misunderstandings of programming concepts.)
Grid Class
public class Grid {
private boolean isGrenade;
private boolean isPShip;
private boolean isCShip;
private boolean shotAt;
private char state;
public Grid() {
isGrenade = false;
isPShip = false;
isCShip = false;
shotAt = false;
state = '-';
}
//sets a player ship
public void setPShip(Grid[][] a, int i, int j) {
a[i][j].isPShip = true;
a[i][j].state = 'S';
}
//sets a computer ship
public void setCShip(Grid[][] a, int i, int j) {
a[i][j].isCShip = true;
a[i][j].state = 's';
}
//sets a player grenade
public void setPGrenade(Grid[][] a, int i, int j) {
a[i][j].isGrenade = true;
a[i][j].state = 'G';
}
//sets a computer grenade
public void setCGrenade(Grid[][] a, int i, int j) {
a[i][j].isGrenade = true;
a[i][j].state = 'g';
}
//returns whether a cell has been shot already
public boolean alreadyShot(Grid[][] a, int i, int j) {
return a[i][i].shotAt;
}
//changes a cell's state to one that has been shot
public void changeState(Grid[][] a, int i, int j) {
a[i][j].state = '*';
}
//sets a cell's state to one that has been shot
public void setState(Grid[][] a, int i, int j) {
a[i][j].shotAt = true;
}
//returns whether a cell is occupied by a ship/grenade
public boolean getCellState() {
return (this.state != '-');
}
//prints out the cell's state
public char printState(Grid[][] a, int i, int j) {
if (a[i][j].shotAt == true) {
return a[i][j].state;
}
else {
return '-';
}
}
//prints out the cell's state - cheat mode
public char revealedState(Grid[][] a, int i, int j) {
return a[i][j].state;
}
}
BattleshipDriver Class
/**
* This program simulates the game, Battleship.
* The player and the computer each have six ships.
* They also have four grenades each.
* Shooting a grenade makes one lose a turn.
* The first to sink all the opponent's ships wins.
*/
import java.util.Scanner;
public class BattleshipDriver {
//Global constant declarations
public static final int GRID_ROWS = 8;
public static final int GRID_COLS = 8;
public static final int PLAYER_SHIPS = 6;
public static final int PLAYER_GRENADES = 4;
public static final int COMP_SHIPS = 6;
public static final int COMP_GRENADES = 4;
public static final int PROMPT_SIZE = 7;
//Global variable declarations
public static boolean cheats = false;
public static int playerLives = PLAYER_SHIPS;
public static int compLives = COMP_SHIPS;
public static Scanner in = new Scanner(System.in);
//Main battleship driver
public static void main(String[] args) {
String menuChoice = "";
//Main menu screen
while (true) {
printTitle();
System.out.println("To have the best possible experience, please set your console window to the maximum size.");
System.out.println();
System.out.println("Press 1 to play against the computer.");
System.out.println("Press 2 to play WITH CHEATS against the computer (reveals the grid).");
System.out.println("Press 3 to see the game's rules.");
System.out.println("Press 4 to exit.");
System.out.print("Your choice: ");
menuChoice = in.next();
switch (menuChoice) {
case "1":
startGame();
break;
case "2":
cheats = true;
startGame();
break;
case "3":
clearScreen();
printRules();
break;
case "4":
clearScreen();
System.out.println("Thank you for playing!");
in.close();
System.exit(0);
break;
default:
System.out.println("That is not a valid choice.");
pressEnter();
clearScreen();
}
}
}
//Game proper
public static void startGame () {
Grid[][] currentGame = new Grid[GRID_ROWS][GRID_COLS];
String coords = "";
int x, y;
boolean playerLostTurn = false;
boolean compLostTurn = false;
//Constructor loop
for (int i = 0; i < GRID_ROWS; i++) {
for (int j = 0; j < GRID_COLS; j++) {
currentGame[i][j] = new Grid();
}
}
playerInit(currentGame);
compInit(currentGame);
System.out.println("Let the games begin!");
System.out.println();
while (checkVictory()) {
//Checks for cheat mode
if (cheats) {
revealedGrid(currentGame);
}
else {
printGrid(currentGame);
}
//Player's turn
if (playerLostTurn) {
System.out.println("Sorry Captain, you lost a turn from that grenade.");
playerLostTurn = false;
pressEnter();
}
else {
do {
System.out.print("It's your turn! Please input coordinates for your missile: ");
coords = in.next();
x = coords.charAt(1) - 49; //converts x-coord to corresponding int
y = ((int) Character.toUpperCase(coords.charAt(0))) - 65; //converts y-coord to corresponding int
//out of bounds clause
if ((x > 7) || (y > 7) || (x < 0)) {
System.out.println("Sorry, those coordinates are beyond grid size.");
System.out.println("Make sure to hit within the map, oh Captain.");
pressEnter();
}
} while ((x > 7) || (y > 7) || (x < 0));
//shot at the same place clause
if (currentGame[x][y].alreadyShot(currentGame, x, y)) {
System.out.println("Sorry, that cell was already shot at.");
System.out.println("Make sure we don't shoot at the same thing twice, oh Captain.");
pressEnter();
clearScreen();
}
//shot an enemy ship clause
else if (currentGame[x][y].revealedState(currentGame, x, y) == 's') {
System.out.println("Bullseye! You hit the enemy ship");
currentGame[x][y].setState(currentGame, x, y);
if (cheats) { currentGame[x][y].changeState(currentGame, x, y); }
compLives--;
pressEnter();
clearScreen();
}
//shot own ship clause
else if (currentGame[x][y].revealedState(currentGame, x, y) == 'S') {
System.out.println("Oh no! You shot your own ship! What kind of captain are you?!");
currentGame[x][y].setState(currentGame, x, y);
if (cheats) { currentGame[x][y].changeState(currentGame, x, y); }
playerLives--;
pressEnter();
clearScreen();
}
//shot a grenade clause
else if ((currentGame[x][y].revealedState(currentGame, x, y) == 'g') || (currentGame[x][y].revealedState(currentGame, x, y) == 'g')) {
System.out.println("BOOM! You hit a grenade! You lost a turn! Oh Captain!");
currentGame[x][y].setState(currentGame, x, y);
if (cheats) { currentGame[x][y].changeState(currentGame, x, y); }
playerLostTurn = true;
pressEnter();
clearScreen();
}
//shot at nothing clause
else {
System.out.println("We hit water! Adjust sights to port, oh Captain!");
currentGame[x][y].setState(currentGame, x, y);
currentGame[x][y].changeState(currentGame, x, y);
pressEnter();
clearScreen();
}
}
//checks if computer previously hit a grenade and lost a turn
if (compLostTurn == true) {
System.out.println ("The dumb computer lost a turn. It's your time to shine again, oh Captain!");
pressEnter();
clearScreen();
compLostTurn = false;
}
else {
compLostTurn = compTurn(currentGame);
}
}
//checks to see who won
if (compLives == 0) {
clearScreen();
printVictory();
}
else {
clearScreen();
printGameOver();
}
}
//Player's turn to set ships and grenades
public static void playerInit(Grid[][] currentGame) {
String coords = "";
int x, y;
int counter = 0;
//Set player ships
while (counter < PLAYER_SHIPS) {
clearScreen();
revealedGrid(currentGame);
System.out.println();
System.out.printf("Please input the coordinates for ship #%d: ", (counter + 1));
coords = in.next();
x = coords.charAt(1) - 49; //converts x-coord to corresponding int
y = ((int) Character.toUpperCase(coords.charAt(0))) - 65; //converts y-coord to corresponding int
if ((x > 7) || (y > 7) || (x < 0)) {
System.out.println("Sorry, those coordinates are beyond grid size.");
pressEnter();
}
else if (currentGame[x][y].getCellState()) {
System.out.println("Sorry, that cell is already occupied.");
pressEnter();
}
else {
currentGame[x][y].setPShip(currentGame, x, y);
counter++;
}
}
//Set player grenades
counter = 0;
while (counter < PLAYER_GRENADES) {
clearScreen();
revealedGrid(currentGame);
System.out.println();
System.out.printf("Please input the coordinates for grenade #%d: ", (counter + 1));
coords = in.next();
x = coords.charAt(1) - 49; //converts x-coord to corresponding int
y = ((int) Character.toUpperCase(coords.charAt(0))) - 65; //converts y-coord to corresponding int
if ((x > 7) || (y > 7) || (x < 0)) {
System.out.println("Sorry, those coordinates are beyond grid size.");
pressEnter();
}
else if (currentGame[x][y].getCellState()) {
System.out.println("Sorry, that cell is already occupied.");
pressEnter();
}
else {
currentGame[x][y].setPGrenade(currentGame, x, y);
counter++;
}
}
clearScreen();
}
//Computer's turn to set ships and grenades
public static void compInit(Grid[][] currentGame) {
int x, y = 0;
int counter = 0;
//Set ships
while (counter < COMP_SHIPS) {
do {
x = (int) (Math.random() * (GRID_ROWS - 1)) + 1;
y = (int) (Math.random() * (GRID_COLS - 1)) + 1;
} while (currentGame[x][y].getCellState());
currentGame[x][y].setCShip(currentGame, x, y);
counter++;
}
//Set grenades
counter = 0;
while (counter < COMP_GRENADES) {
do {
x = (int) (Math.random() * (GRID_ROWS - 1)) + 1;
y = (int) (Math.random() * (GRID_COLS - 1)) + 1;
} while (currentGame[x][y].getCellState());
currentGame[x][y].setCGrenade(currentGame, x, y);
counter++;
}
}
//Computer's turn to fire missiles
public static boolean compTurn(Grid[][] currentGame) {
int x, y = 0;
do {
x = (int) (Math.random() * (GRID_ROWS - 1)) + 1;
y = (int) (Math.random() * (GRID_COLS - 1)) + 1;
} while (currentGame[x][y].alreadyShot(currentGame, x, y));
char xCoord = (char) (x + 48); //converts random coords to grid coords (e.g. A1)
char yCoord = (char) (y + 64);
System.out.printf("The dumb computer launched his missile at: %c%c\n", yCoord, xCoord);
x--; //sets coords to array indices
y--;
//if the computer hits one of the player's ships clause
if (currentGame[x][y].revealedState(currentGame, x, y) == 'S') {
System.out.println("Oh no! The dumb computer sank one your ships! It wasn't so dumb after all.");
currentGame[x][y].setState(currentGame, x, y);
if (cheats) { currentGame[x][y].changeState(currentGame, x, y); }
playerLives--;
System.out.println();
return false;
}
//if the computer hits one of his own ships clause
else if (currentGame[x][y].revealedState(currentGame, x, y) == 's') {
System.out.println("Oh no! The dumb computer shot one of his own ships!");
currentGame[x][y].setState(currentGame, x, y);
if (cheats) { currentGame[x][y].changeState(currentGame, x, y); }
compLives--;
System.out.println();
return false;
}
//if the computer hits nothing but water clause
else if (currentGame[x][y].revealedState(currentGame, x, y) == '-') {
System.out.println("The dumb computer hit nothing but water.");
currentGame[x][y].setState(currentGame, x, y);
currentGame[x][y].changeState(currentGame, x, y);
System.out.println();
return false;
}
//if computer shoots at the same thing twice clause
else if (currentGame[x][y].alreadyShot(currentGame, x, y)) {
System.out.println("The dumb computer tried to shoot at the same thing twice.");
System.out.println();
return false;
}
//if computer hits a grenade clause
else if ((currentGame[x][y].revealedState(currentGame, x, y) == 'G') || (currentGame[x][y].revealedState(currentGame, x, y) == 'g')) {
System.out.println("BOOM! The dumb computer hit a grenade! It lost a turn!");
currentGame[x][y].setState(currentGame, x, y);
if (cheats) { currentGame[x][y].changeState(currentGame, x, y); }
System.out.println();
return true;
}
return false;
}
//Checks victory condition
public static boolean checkVictory () {
return ((playerLives > 0) && (compLives > 0)) ;
}
//Prints the grid
public static void printGrid (Grid[][] currentGame) {
System.out.print(" ");
for (char ch = 'A'; ch < 'I'; ch++) { // prints the column headings
System.out.print(ch + " ");
}
System.out.println();
for (int i = 0; i < (GRID_ROWS) ; i++) {
System.out.print((i + 1) + " "); // prints the row headings
for (int j = 0; j < (GRID_COLS) ; j++) {
System.out.print(currentGame[i][j].printState(currentGame, i, j) + " ");
}
System.out.println();
}
System.out.println("LEGEND: ");
System.out.println("S - your ship s - enemy ship");
System.out.println("G - your grenade g - enemy grenade");
System.out.println("* - cell has already been shot");
System.out.printf("Player Ships Left: %d\n", playerLives);
System.out.printf("Computer Ships Left: %d\n", compLives);
System.out.println();
}
//Prints a revealed grid (cheats mode)
public static void revealedGrid (Grid[][] currentGame) {
System.out.print(" ");
for (char ch = 'A'; ch < 'I'; ch++) { // prints the column headings
System.out.print(ch + " ");
}
System.out.println();
for (int i = 0; i < (GRID_ROWS) ; i++) {
System.out.print((i + 1) + " "); // prints the row headings
for (int j = 0; j < (GRID_COLS) ; j++) {
System.out.print(currentGame[i][j].revealedState(currentGame, i, j) + " ");
}
System.out.println();
}
System.out.println("LEGEND: ");
System.out.println("S - your ship s - enemy ship");
System.out.println("G - your grenade g - enemy grenade");
System.out.println("* - cell has already been shot");
System.out.printf("Player Ships Left: %d\n", playerLives);
System.out.printf("Computer Ships Left: %d\n", compLives);
System.out.println();
}
//Prints the game over screen
public static void printGameOver () {
System.out.println(" _____ ____ ");
System.out.println(" / ____| / __ \\ ");
System.out.println("| | __ __ _ _ __ ___ ___ | | | |_ _____ _ __ ");
System.out.println("| | |_ |/ _` | '_ ` _ \\ / _ \\ | | | \\ \\ / / _ \\ '__|");
System.out.println("| |__| | (_| | | | | | | __/ | |__| |\\ V / __/ |");
System.out.println(" \\_____|\\__,_|_| |_| |_|\\___| \\____/ \\_/ \\___|_|");
System.exit(0);
}
//Prints the victory screen
public static void printVictory () {
System.out.println("VVVVVVVV VVVVVVVVIIIIIIIIII CCCCCCCCCCCCCTTTTTTTTTTTTTTTTTTTTTTT OOOOOOOOO RRRRRRRRRRRRRRRRR YYYYYYY YYYYYYY !!!");
System.out.println("V::::::V V::::::VI::::::::I CCC::::::::::::CT:::::::::::::::::::::T OO:::::::::OO R::::::::::::::::R Y:::::Y Y:::::Y!!:!!");
System.out.println("V::::::V V::::::VI::::::::I CC:::::::::::::::CT:::::::::::::::::::::T OO:::::::::::::OO R::::::RRRRRR:::::R Y:::::Y Y:::::Y!:::!");
System.out.println("V::::::V V::::::VII::::::IIC:::::CCCCCCCC::::CT:::::TT:::::::TT:::::TO:::::::OOO:::::::ORR:::::R R:::::RY::::::Y Y::::::Y!:::!");
System.out.println("V:::::V V:::::V I::::I C:::::C CCCCCCTTTTTT T:::::T TTTTTTO::::::O O::::::O R::::R R:::::RYYY:::::Y Y:::::YYY!:::!");
System.out.println("V:::::V V:::::V I::::IC:::::C T:::::T O:::::O O:::::O R::::R R:::::R Y:::::Y Y:::::Y !:::!");
System.out.println("V:::::V V:::::V I::::IC:::::C T:::::T O:::::O O:::::O R::::RRRRRR:::::R Y:::::Y:::::Y !:::!");
System.out.println("V:::::V V:::::V I::::IC:::::C T:::::T O:::::O O:::::O R:::::::::::::RR Y:::::::::Y !:::!");
System.out.println("V:::::V V:::::V I::::IC:::::C T:::::T O:::::O O:::::O R::::RRRRRR:::::R Y:::::::Y !:::!");
System.out.println("V:::::V V:::::V I::::IC:::::C T:::::T O:::::O O:::::O R::::R R:::::R Y:::::Y !:::!");
System.out.println("V:::::V:::::V I::::IC:::::C T:::::T O:::::O O:::::O R::::R R:::::R Y:::::Y !!:!!");
System.out.println("V:::::::::V I::::I C:::::C CCCCCC T:::::T O::::::O O::::::O R::::R R:::::R Y:::::Y !!! ");
System.out.println("V:::::::V II::::::IIC:::::CCCCCCCC::::C TT:::::::TT O:::::::OOO:::::::ORR:::::R R:::::R Y:::::Y");
System.out.println("V:::::V I::::::::I CC:::::::::::::::C T:::::::::T OO:::::::::::::OO R::::::R R:::::R YYYY:::::YYYY !!!");
System.out.println("V:::V I::::::::I CCC::::::::::::C T:::::::::T OO:::::::::OO R::::::R R:::::R Y:::::::::::Y !!:!!");
System.out.println("VVV IIIIIIIIII CCCCCCCCCCCCC TTTTTTTTTTT OOOOOOOOO RRRRRRRR RRRRRRR YYYYYYYYYYYYY !!!");
System.exit(0);
}
//Prints the main title screen
public static void printTitle() {
System.out.println("8 888888888o .8. 8888888 8888888888 8888888 8888888888 8 8888 8 8888888888 d888888o. 8 8888 8 8 8888 8 888888888o");
System.out.println("8 8888 `88. .888. 8 8888 8 8888 8 8888 8 8888 .`8888:' `88. 8 8888 8 8 8888 8 8888 `88.");
System.out.println("8 8888 `88 :88888. 8 8888 8 8888 8 8888 8 8888 8.`8888. Y8 8 8888 8 8 8888 8 8888 `88 ");
System.out.println("8 8888 ,88 . `88888. 8 8888 8 8888 8 8888 8 8888 `8.`8888. 8 8888 8 8 8888 8 8888 ,88 ");
System.out.println("8 8888. ,88' .8. `88888. 8 8888 8 8888 8 8888 8 888888888888 `8.`8888. 8 8888 8 8 8888 8 8888. ,88' ");
System.out.println("8 8888888888 .8`8. `88888. 8 8888 8 8888 8 8888 8 8888 `8.`8888. 8 8888 8 8 8888 8 888888888P' ");
System.out.println("8 8888 `88. .8' `8. `88888. 8 8888 8 8888 8 8888 8 8888 `8.`8888. 8 8888888888888 8 8888 8 8888 ");
System.out.println("8 8888 88 .8' `8. `88888. 8 8888 8 8888 8 8888 8 8888 8b `8.`8888. 8 8888 8 8 8888 8 8888 ");
System.out.println("8 8888 ,88'.888888888. `88888. 8 8888 8 8888 8 8888 8 8888 `8b. ;8.`8888 8 8888 8 8 8888 8 8888 ");
System.out.println("8 888888888P .8' `8. `88888. 8 8888 8 8888 8 888888888888 8 888888888888 `Y8888P ,88P' 8 8888 8 8 8888 8 8888 ");
System.out.println();
}
//Prints the game's rules
public static void printRules() {
System.out.println("THE RULES");
System.out.printf("The player has %d ships and %d grenades\n", PLAYER_SHIPS, PLAYER_GRENADES);
System.out.println("The computer has the same number of ships and grenades.");
System.out.println("Each player gets a turn to fire a missile on the board.");
System.out.println("If the chosen tile has already been shot, you may pick another tile.");
System.out.println("If the chosen tile has a grenade, the player/computer will lose a turn.");
System.out.println("The first one to destroy all the opponent's ships wins.");
System.out.println("Are you ready?");
System.out.println();
pressEnter();
clearScreen();
return;
}
//Clears the screen by moving down 50 lines
public static void clearScreen () {
System.out.println(System.lineSeparator().repeat(50));
}
//Enter key prompt to pause between events
private static void pressEnter () {
System.out.print("Press Enter to continue...");
System.out.println();
try {
System.in.read();
}
catch(Exception e)
{}
}
}
Oh, and should you need a reference, these were the instructions. Thanks!