GameBoard.java
import java.util.Random;
// A Battleship! game board
class GameBoard
{
public final static char ShipMask = 0x07;
public final static char isEmpty = 0x00; // location is empty
public final static char hasCarrier = 0x01; // location contains the carrier
public final static char hasBattleship = 0x02; // location contains the battleship
public final static char hasCruiser = 0x03; // location contains the cruiser
public final static char hasSubmarine = 0x04; // location contains the submarine
public final static char hasDestroyer = 0x05; // location contains the destroyer
public final static char GuessMask = 0x18;
public final static char noGuess = 0x00; // location has not been guessed yet
public final static char isHit = 0x08; // guess is a hit
public final static char isMiss = 0x10; // guess is a miss
public final static char isSunk = 0x18; // guess is sunk
public char board[][]; // the game board itself
public Carrier carrier; // the carrier
public Battleship battleship; // the battleship
public Cruiser cruiser; // the cruiser
public Submarine submarine; // the submarine
public Destroyer destroyer; // the destroyer
// Create a new game board
GameBoard()
{
board = new char[10][10];
// initialize the board to the empty state
for (int x = 0; x < 10; x++)
for (int y = 0; y < 10; y++)
board[x][y] = 0;
// select random positions for the ships
Random rand = new Random();
// select orientation and position for the carrier
boolean isVertical = (rand.nextInt() % 2 == 0) ? false : true;
int initX = Math.abs(rand.nextInt() % (isVertical ? 10 : 6));
int initY = Math.abs(rand.nextInt() % (isVertical ? 6 : 10));
for (int i = 0; i < 5; i++)
{
if (isVertical)
board[initX][initY+i] = hasCarrier;
else
board[initX+i][initY] = hasCarrier;
}
carrier = new Carrier(initX, initY, isVertical);
// select orientation and position for the battleship
do
{
isVertical = (rand.nextInt() % 2 == 0) ? false : true;
initX = Math.abs(rand.nextInt() % (isVertical ? 10 : 7));
initY = Math.abs(rand.nextInt() % (isVertical ? 7 : 10));
}
while ((board[initX][initY] != 0) ||
(isVertical &&
((board[initX][initY+1] != 0) || (board[initX][initY+2] != 0) || (board[initX][initY+3] != 0))) ||
(!isVertical &&
((board[initX+1][initY] != 0) || (board[initX+2][initY] != 0) || (board[initX+3][initY] != 0))));
if (isVertical)
board[initX][initY] = board[initX][initY+1] = board[initX][initY+2] = board[initX][initY+3] =
hasBattleship;
else
board[initX][initY] = board[initX+1][initY] = board[initX+2][initY] = board[initX+3][initY] =
hasBattleship;
battleship = new Battleship(initX, initY, isVertical);
// select orientation and position for the cruiser
do
{
isVertical = (rand.nextInt() % 2 == 0) ? false : true;
initX = Math.abs(rand.nextInt() % (isVertical ? 10 : 8));
initY = Math.abs(rand.nextInt() % (isVertical ? 8 : 10));
}
while ((board[initX][initY] != 0) ||
(isVertical && ((board[initX][initY+1] != 0) || (board[initX][initY+2] != 0))) ||
(!isVertical && ((board[initX+1][initY] != 0) || (board[initX+2][initY] != 0))));
if (isVertical)
board[initX][initY] = board[initX][initY+1] = board[initX][initY+2] = hasCruiser;
else
board[initX][initY] = board[initX+1][initY] = board[initX+2][initY] = hasCruiser;
cruiser = new Cruiser(initX, initY, isVertical);
// select orientation and position for the submarine
do
{
isVertical = (rand.nextInt() % 2 == 0) ? false : true;
initX = Math.abs(rand.nextInt() % (isVertical ? 10 : 8));
initY = Math.abs(rand.nextInt() % (isVertical ? 8 : 10));
}
while ((board[initX][initY] != 0) ||
(isVertical && ((board[initX][initY+1] != 0) || (board[initX][initY+2] != 0))) ||
(!isVertical && ((board[initX+1][initY] != 0) || (board[initX+2][initY] != 0))));
if (isVertical)
board[initX][initY] = board[initX][initY+1] = board[initX][initY+2] = hasSubmarine;
else
board[initX][initY] = board[initX+1][initY] = board[initX+2][initY] = hasSubmarine;
submarine = new Submarine(initX, initY, isVertical);
// select orientation and position for the destroyer
do
{
isVertical = (rand.nextInt() % 2 == 0) ? false : true;
initX = Math.abs(rand.nextInt() % (isVertical ? 10 : 9));
initY = Math.abs(rand.nextInt() % (isVertical ? 9 : 10));
}
while ((board[initX][initY] != 0) ||
(isVertical && (board[initX][initY+1] != 0)) || (!isVertical && (board[initX+1][initY] != 0)));
if (isVertical)
board[initX][initY] = board[initX][initY+1] = hasDestroyer;
else
board[initX][initY] = board[initX+1][initY] = hasDestroyer;
destroyer = new Destroyer(initX, initY, isVertical);
// initialize game statistics
numberSunk = 0;
numberOfHits = 0;
numberOfGuesses = 0;
duplicateGuesses = 0;
}
// Returns true if the game has been won
public boolean isGameOver()
{
return (numberSunk == 5) ? true : false;
}
// Records a guess
public char guess(int x, int y)
{
numberOfGuesses++;
if ((board[x][y] & GuessMask) != noGuess)
{
duplicateGuesses++;
return (char)(board[x][y] & GuessMask);
}
switch (board[x][y] & ShipMask)
{
case isEmpty:
board[x][y] |= isMiss;
return isMiss;
case hasCarrier:
board[x][y] |= isHit;
numberOfHits++;
carrier.registerHit(x, y);
if (carrier.isSunk())
{
for (int i = 0; i < 5; i++)
board[carrier.xPos[i]][carrier.yPos[i]] |= isSunk;
numberSunk++;
return isSunk;
}
else
return isHit;
case hasBattleship:
board[x][y] |= isHit;
numberOfHits++;
battleship.registerHit(x, y);
if (battleship.isSunk())
{
for (int i = 0; i < 4; i++)
board[battleship.xPos[i]][battleship.yPos[i]] |= isSunk;
numberSunk++;
return isSunk;
}
else
return isHit;
case hasCruiser:
board[x][y] |= isHit;
numberOfHits++;
cruiser.registerHit(x, y);
if (cruiser.isSunk())
{
for (int i = 0; i < 3; i++)
board[cruiser.xPos[i]][cruiser.yPos[i]] |= isSunk;
numberSunk++;
return isSunk;
}
else
return isHit;
case hasSubmarine:
board[x][y] |= isHit;
numberOfHits++;
submarine.registerHit(x, y);
if (submarine.isSunk())
{
for (int i = 0; i < 3; i++)
board[submarine.xPos[i]][submarine.yPos[i]] |= isSunk;
numberSunk++;
return isSunk;
}
else
return isHit;
case hasDestroyer:
board[x][y] |= isHit;
numberOfHits++;
destroyer.registerHit(x, y);
if (destroyer.isSunk())
{
for (int i = 0; i < 2; i++)
board[destroyer.xPos[i]][destroyer.yPos[i]] |= isSunk;
numberSunk++;
return isSunk;
}
else
return isHit;
}
return isMiss; // should never get here
}
// Resets the game board to its initial state
public void reset()
{
// initialize the board to the empty state
for (int x = 0; x < 10; x++)
for (int y = 0; y < 10; y++)
board[x][y] &= ~GuessMask;
// initialize game statistics
numberSunk = 0;
numberOfHits = 0;
numberOfGuesses = 0;
duplicateGuesses = 0;
}
// Displays the game board
public void display()
{
for (int y = 0; y < 10; y++)
{
for (int x = 0; x < 10; x++)
{
if (board[x][y] == 0)
System.out.print(".");
else
{
switch (board[x][y] & ShipMask)
{
case isEmpty:
System.out.print("M");
break;
case hasCarrier:
if ((board[x][y] & GuessMask) == noGuess)
System.out.print("a");
else
System.out.print("A");
break;
case hasBattleship:
if ((board[x][y] & GuessMask) == noGuess)
System.out.print("b");
else
System.out.print("B");
break;
case hasCruiser:
if ((board[x][y] & GuessMask) == noGuess)
System.out.print("c");
else
System.out.print("C");
break;
case hasSubmarine:
if ((board[x][y] & GuessMask) == noGuess)
System.out.print("s");
else
System.out.print("S");
break;
case hasDestroyer:
if ((board[x][y] & GuessMask) == noGuess)
System.out.print("d");
else
System.out.print("D");
break;
}
}
}
System.out.println();
}
System.out.println();
}
public int numberSunk; // number of ships sunk in this game
public int numberOfHits; // number of hits recorded in this game (duplicates aren't counted
public int numberOfGuesses; // number of guesses made in this game
public int duplicateGuesses; // number of duplicated guesses made in this game
}
Carrier.java
import GameBoard;
class Carrier implements Ship
{
public int xPos[];
public int yPos[];
public Carrier(int x, int y, boolean vertical)
{
xPos = new int[5];
yPos = new int[5];
isHit = new boolean[5];
for (int i = 0; i < 5; i++)
{
xPos[i] = x;
yPos[i] = y;
isHit[i] = false;
if (vertical)
y++;
else
x++;
}
numHits = 0;
}
public String name()
{
return "Carrier";
}
public boolean registerHit(int x, int y)
{
for (int i = 0; i < 5; i++)
{
if (xPos[i] == x && yPos[i] == y)
{
if (!isHit[i])
{
isHit[i] = true;
numHits++;
}
return true;
}
}
return false;
}
public boolean isSunk()
{
return (numHits == 5) ? true : false;
}
private boolean isHit[];
private int numHits;
}
Battleship.java
import GameBoard;
class Battleship implements Ship
{
public int xPos[];
public int yPos[];
public Battleship(int x, int y, boolean vertical)
{
xPos = new int[4];
yPos = new int[4];
isHit = new boolean[4];
for (int i = 0; i < 4; i++)
{
xPos[i] = x;
yPos[i] = y;
isHit[i] = false;
if (vertical)
y++;
else
x++;
}
numHits = 0;
}
public String name()
{
return "Battleship";
}
public boolean registerHit(int x, int y)
{
for (int i = 0; i < 4; i++)
{
if (xPos[i] == x && yPos[i] == y)
{
if (!isHit[i])
{
isHit[i] = true;
numHits++;
}
return true;
}
}
return false;
}
public boolean isSunk()
{
return (numHits == 4) ? true : false;
}
private boolean isHit[];
private int numHits;
}
Cruiser.java
import GameBoard;
class Cruiser implements Ship
{
public int xPos[];
public int yPos[];
public Cruiser(int x, int y, boolean vertical)
{
xPos = new int[3];
yPos = new int[3];
isHit = new boolean[3];
for (int i = 0; i < 3; i++)
{
xPos[i] = x;
yPos[i] = y;
isHit[i] = false;
if (vertical)
y++;
else
x++;
}
numHits = 0;
}
public String name()
{
return "Cruiser";
}
public boolean registerHit(int x, int y)
{
for (int i = 0; i < 3; i++)
{
if (xPos[i] == x && yPos[i] == y)
{
if (!isHit[i])
{
isHit[i] = true;
numHits++;
}
return true;
}
}
return false;
}
public boolean isSunk()
{
return (numHits == 3) ? true : false;
}
private boolean isHit[];
private int numHits;
}
Submarine.java
import GameBoard;
class Submarine implements Ship
{
public int xPos[];
public int yPos[];
public Submarine(int x, int y, boolean vertical)
{
xPos = new int[3];
yPos = new int[3];
isHit = new boolean[3];
for (int i = 0; i < 3; i++)
{
xPos[i] = x;
yPos[i] = y;
isHit[i] = false;
if (vertical)
y++;
else
x++;
}
numHits = 0;
}
public String name()
{
return "Submarine";
}
public boolean registerHit(int x, int y)
{
for (int i = 0; i < 3; i++)
{
if (xPos[i] == x && yPos[i] == y)
{
if (!isHit[i])
{
isHit[i] = true;
numHits++;
}
return true;
}
}
return false;
}
public boolean isSunk()
{
return (numHits == 3) ? true : false;
}
private boolean isHit[];
private int numHits;
}
Destroyer.java
import GameBoard;
class Destroyer implements Ship
{
public int xPos[];
public int yPos[];
public Destroyer(int x, int y, boolean vertical)
{
xPos = new int[2];
yPos = new int[2];
isHit = new boolean[2];
for (int i = 0; i < 2; i++)
{
xPos[i] = x;
yPos[i] = y;
isHit[i] = false;
if (vertical)
y++;
else
x++;
}
numHits = 0;
}
public String name()
{
return "Destroyer";
}
public boolean registerHit(int x, int y)
{
for (int i = 0; i < 2; i++)
{
if (xPos[i] == x && yPos[i] == y)
{
if (!isHit[i])
{
isHit[i] = true;
numHits++;
}
return true;
}
}
return false;
}
public boolean isSunk()
{
return (numHits == 2) ? true : false;
}
private boolean isHit[];
private int numHits;
}
PlayGame.java
import java.lang.Math;
import java.util.Random;
class PlayGame
{
public static void main(String argv[])
{
boolean alreadyGuessed[][] = new boolean[10][10];
for (int x = 0; x < 10; x++)
for (int y = 0; y < 10; y++)
alreadyGuessed[x][y] = false;
GameBoard b = new GameBoard();
b.display();
Random rand = new Random();
while (!b.isGameOver())
{
int xPos = Math.abs(rand.nextInt() % 10);
int yPos = Math.abs(rand.nextInt() % 10);
if (!alreadyGuessed[xPos][yPos])
{
alreadyGuessed[xPos][yPos] = true;
b.guess(xPos, yPos);
}
}
b.display();
System.out.println(b.numberOfGuesses + " guesses, " + b.numberOfHits + " hits, sunk " + b.numberSunk);
b.reset();
b.display();
System.out.println(b.numberOfGuesses + " guesses, " + b.numberOfHits + " hits, sunk " + b.numberSunk);
}
}