/*
Battleship - Copyright (C) 2004 Jim Casaburi
released under the GPL (which follows)
This program is free software; you can redistribute
it and/or modify
it under the terms of the GNU General Public License
as published by
the Free Software Foundation; either version 2 of
the License, or
(at your option) any later version.
This program is distributed in the hope that it will
be useful,
but WITHOUT ANY WARRANTY; without even the implied
warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General
Public License
along with this program; if not, write to the Free
Software
Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
*/
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.net.*;
import java.io.*;
public class BattleshipGame extends javax.swing.JFrame
{
private Thread clientthread;
private Thread serverthread;
private JPanel panel = new JPanel();
private JPanel board1 = new JPanel();
private JPanel board2 = new JPanel();
private JTextField ipaddress = new
JTextField("127.0.0.1");
private JTextField listenon = new
JTextField("12345");
private JTextField broadcaston = new
JTextField("12346");
private JLabel[][] board1labels;
private JButton[][] board2buttons;
private JButton exitbutton = new JButton("Exit");
private JButton startnetwork = new JButton("Start
Network");
private JButton sendrequest = new JButton("Play
Game");
private JLabel[] horizontallabels1;
private JLabel[] horizontallabels2;
private JLabel[] verticallabels1;
private JLabel[] verticallabels2;
private JLabel yourboardlabel = new JLabel("Your
side");
private JLabel theirboardlabel = new JLabel("Your
enemy");
private JLabel ipaddresslabel = new JLabel("The
enemy IP address");
private JLabel listenonlabel = new JLabel("Listen
port");
private JLabel broadcastonlabel = new
JLabel("Broadcast port");
private JLabel enemystatus = new JLabel("Enemy: 4
boats remain");
private JLabel programstatus = new JLabel("No
connection to the network");
private boardposition[][] myboard;
private boardposition[][] theirboard;
private ship[] myships;
private int myshipcount = 4;
private int theirshipcount = 4;
private boolean playinggame = false;
private boolean ismyturn = false;
private int wantedx = -1;
private int wantedy = -1;
public BattleshipGame() {
super("Battleship
Simulator");
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {}
myboard = new
boardposition[10][10];
theirboard = new
boardposition[10][10];
myships = new
ship[5];
board1labels = new
JLabel[10][10];
board2buttons = new
JButton[10][10];
verticallabels1 = new
JLabel[10];
horizontallabels1 = new
JLabel[10];
verticallabels2 = new
JLabel[10];
horizontallabels2 = new
JLabel[10];
// have the program actually
exit when this window is closed
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
for (int a = 0; a < 10;
a++) {
verticallabels1[a] = new JLabel(""+(a+1));
verticallabels2[a] = new JLabel(""+(a+1));
horizontallabels1[a] = new JLabel(""+(a+1));
horizontallabels2[a] = new JLabel(""+(a+1));
for
(int b = 0; b < 10; b++) {
myboard[a][b] = new boardposition(a,b);
theirboard[a][b] = new boardposition(a,b);
board2buttons[a][b] = new JButton("");
board1labels[a][b] = new JLabel("");
board1labels[a][b].setOpaque(true);
board1labels[a][b].setBackground(Color.BLUE);
board1labels[a][b].setBorder(BorderFactory.createEtchedBorder());
board2buttons[a][b].setBackground(Color.BLUE);
}
}
setSize(500,400);
this.getContentPane().setLayout(null);
board1.setLayout(new
GridLayout(10,10,1,1));
board2.setLayout(new
GridLayout(10,10,1,1));
for (int a = 0; a < 10;
a++)
for (int b = 0; b < 10;
b++) {
board1.add(board1labels[a][b]);
board2.add(board2buttons[a][b]);
board2buttons[a][b].addActionListener(new BoardButtonHandler(a+1,b+1));
}
this.setResizable(false);
exitbutton.addActionListener(new ExitButtonHandler());
startnetwork.addActionListener(new starnetworkbuttonhandler());
sendrequest.addActionListener(new sendrequesthandler());
this.getContentPane().add(board1);
board1.setBounds(20,40,200,200);
this.getContentPane().add(board2);
board2.setBounds(260,40,200,200);
this.getContentPane().add(exitbutton);
exitbutton.setBounds(400,340,80,30);
this.getContentPane().add(ipaddress);
ipaddress.setBounds(20,250,150,30);
this.getContentPane().add(yourboardlabel);
yourboardlabel.setBounds(20,0,80,20);
this.getContentPane().add(theirboardlabel);
theirboardlabel.setBounds(260,0,80,20);
this.getContentPane().add(ipaddresslabel);
ipaddresslabel.setBounds(20,280,150,20);
this.getContentPane().add(listenon);
listenon.setBounds(180,250,100,30);
this.getContentPane().add(broadcaston);
broadcaston.setBounds(300,250,100,30);
this.getContentPane().add(listenonlabel);
listenonlabel.setBounds(180,280,100,20);
this.getContentPane().add(broadcastonlabel);
broadcastonlabel.setBounds(300,280,100,20);
this.getContentPane().add(startnetwork);
startnetwork.setBounds(0,340,150,30);
this.getContentPane().add(sendrequest);
sendrequest.setBounds(150,340,150,30);
this.getContentPane().add(enemystatus);
this.getContentPane().add(programstatus);
enemystatus.setBounds(20,310,200,20);
programstatus.setBounds(240,310,200,20);
for (int a = 0; a < 10;
a++) {
this.getContentPane().add(horizontallabels1[a]);
this.getContentPane().add(horizontallabels2[a]);
this.getContentPane().add(verticallabels1[a]);
this.getContentPane().add(verticallabels2[a]);
horizontallabels1[a].setBounds(a*20+20,20,20,20);
horizontallabels2[a].setBounds(a*20+260,20,20,20);
verticallabels1[a].setBounds(0,40+20*a,20,20);
verticallabels2[a].setBounds(240,40+20*a,20,20);
}
sendrequest.setEnabled(false);
layships(myships,myboard);
setVisible(true);
}
public void o(String s) {
JOptionPane.showMessageDialog(null,s);
}
public void gameplay(BufferedReader input,
PrintWriter output) {
String incoming;
String result;
while (myshipcount > 0
&& theirshipcount > 0) {
if
(ismyturn) {
programstatus.setText("Waiting for the button click");
try {
// keep on looping until the user clicks a button (which will set
ismyturn
// to be false
clientthread.setPriority(Thread.MIN_PRIORITY);
while (ismyturn) Thread.yield();
// send the coordinates that you want over to the other player
output.println(""+wantedx + " " +wantedy);
output.flush();
incoming = input.readLine();
StringTokenizer s = new StringTokenizer(incoming);
result = s.nextToken();
if (result.equals("HIT")) {
programstatus.setText("HIT!");
theirboard[wantedx][wantedy].hasahit = true;
theirboard[wantedx][wantedy].hasship = true;
board2buttons[wantedx][wantedy].setBackground(Color.RED);
if (s.hasMoreTokens()) {
theirshipcount--;
if (theirshipcount > 0) {
enemystatus.setText("Enemy: "+theirshipcount+" boats remain");
} else {
enemystatus.setText("You have vanquished your cursed enemy!");
}
}
}
else {
theirboard[wantedx][wantedy].hasahit = true;
board2buttons[wantedx][wantedy].setBackground(Color.BLACK);
}
}
catch (Exception e) {
programstatus.setText(e.getMessage());
}
if (theirshipcount > 0) programstatus.setText("Waiting for the
enemy...");
}
else
{
try {
incoming = input.readLine();
boolean theygotakill = false;
StringTokenizer s = new StringTokenizer(incoming);
int theirx = Integer.parseInt(s.nextToken());
int theiry = Integer.parseInt(s.nextToken());
boolean washit = false;
for (int a = 0; a < 4; a++) {
if (myships[a].contains(theirx,theiry)) {
washit = true;
myships[a].health--;
if (myships[a].health == 0) {
theygotakill = true;
myshipcount--;
}
}
}
if (washit) {
board1labels[theirx][theiry].setBackground(Color.RED);
if (theygotakill) output.println("HIT SHIP");
else output.println("HIT");
output.flush();
if (myshipcount == 0)
programstatus.setText("You have been vanquished!!");
}
else {
output.println("MISS");
output.flush();
board1labels[theirx][theiry].setBackground(Color.BLACK);
}
} catch (Exception e) {
programstatus.setText(e.getMessage());
}
if (myshipcount > 0) {
programstatus.setText("Choose your next attack");
ismyturn = true;
}
}
}
}
public static void main (String[ ] args)
{
new BattleshipGame();
}
private void layships(ship[] ships,
boardposition[][] board) {
int tryx;
int tryy;
boolean tryhorizontal;
for (int a = 5; a > 1;
a--) {
boolean laidship = false;
while (!laidship) {
if (Math.random() >= .5) {
tryhorizontal = true;
tryx = (int) ((Math.random() * (10-a)));
tryy = (int) (Math.random() * 10);
if (canlayship(tryx,tryy,a,tryhorizontal,board)) {
laidship = true;
ships[a-2] = new ship(a,tryx,tryy,tryhorizontal);
for (int b = 0; b < a; b++) {
board[tryx+b][tryy].hasship = true;
switch(a) {
case 5:
board1labels[tryx+b][tryy].
setBackground(Color.ORANGE);
break;
case 4:
board1labels[tryx+b][tryy].
setBackground(Color.GRAY);
break;
case 3:
board1labels[tryx+b][tryy].
setBackground(Color.CYAN);
break;
default:
board1labels[tryx+b][tryy].
setBackground(Color.GREEN);
break;
}
}
}
} else {
tryhorizontal = false;
tryx = (int) (Math.random() * 10);
tryy = (int) ((Math.random() * (10-a)));
if (canlayship(tryx,tryy,a,tryhorizontal,board)) {
laidship = true;
ships[a-2] = new ship(a,tryx,tryy,tryhorizontal);
for (int b = 0; b < a; b++) {
board[tryx][tryy+b].hasship = true;
switch(a) {
case 5:
board1labels[tryx][tryy+b].
setBackground(Color.ORANGE);
break;
case 4:
board1labels[tryx][tryy+b].
setBackground(Color.GRAY);
break;
case 3:
board1labels[tryx][tryy+b].
setBackground(Color.CYAN);
break;
default:
board1labels[tryx][tryy+b].
setBackground(Color.GREEN);
break;
}
}
}
}
}
}
}
private boolean canlayship(int cornerx, int cornery,
int size,
boolean horizontal, boardposition[][] board) {
if (cornerx < 0 ||
cornery < 0) return false;
if (horizontal) {
if
(cornerx + size-1 > 9) return false;
}
else {
if
(cornery + size-1 > 9) return false;
}
for (int a = 0; a < size;
a++) {
if
(board[horizontal?cornerx+a:cornerx][horizontal?cornery:cornery+a].hasship
== true)
return false;
}
return true;
}
private class sendrequesthandler implements
ActionListener {
public void
actionPerformed(ActionEvent ev) {
try {
Thread t = new Thread(new sendtonetworkthread());
clientthread = t;
t.start();
}
catch (Exception e) {
programstatus.setText(e.getMessage());
}
}
}
private class sendtonetworkthread implements
Runnable {
public void run() {
BufferedReader input;
PrintWriter output;
try {
Socket client = new
Socket(ipaddress.getText(),Integer.parseInt(broadcaston.getText()));
if
(!playinggame) {
serverthread.interrupt();
sendrequest.setEnabled(false);
broadcaston.setEnabled(false);
ipaddress.setEnabled(false);
playinggame = true;
input = new BufferedReader(new
InputStreamReader(client.getInputStream()));
output = new PrintWriter(client.getOutputStream());
programstatus.setText("It is my turn!");
ismyturn = true;
gameplay(input,output);
}
}
catch (Exception e) {
programstatus.setText(e.getMessage());
}
}
}
private class waitfornetworkthread implements
Runnable {
private ServerSocket server;
public
waitfornetworkthread(ServerSocket s) {
super();
server = s;
}
public void run() {
BufferedReader input;
PrintWriter output;
String indata;
try {
Socket client=server.accept();
broadcaston.setEnabled(false);
ipaddress.setEnabled(false);
//
if you're already playing, you don't care about the recieved message
if
(!playinggame) {
input = new BufferedReader(new
InputStreamReader(client.getInputStream()));
output = new PrintWriter(client.getOutputStream());
programstatus.setText("It is the turn of the enemy");
sendrequest.setEnabled(false);
playinggame = true;
ismyturn = false;
gameplay(input, output);
}
}
catch (Exception e) {
programstatus.setText(e.getMessage());
return;
}
}
}
private class starnetworkbuttonhandler implements
ActionListener {
public void
actionPerformed(ActionEvent ev) {
ServerSocket server;
try {
server = new ServerSocket(Integer.parseInt(listenon.getText()),0);
listenon.setEnabled(false);
programstatus.setText("Listening to the network
waiting...");
startnetwork.setEnabled(false);
sendrequest.setEnabled(true);
Thread t = new Thread(new waitfornetworkthread(server));
serverthread = t;
clientthread = t;
t.start();
}
catch (Exception e) {
programstatus.setText(e.getMessage());
return;
}
}
}
private class BoardButtonHandler implements
ActionListener {
private int xpos;
private int ypos;
public
BoardButtonHandler(int x, int y) {
super();
xpos
= x;
ypos
= y;
}
public void
actionPerformed(ActionEvent ev) {
if
(ismyturn) {
if (!theirboard[xpos-1][ypos-1].hasahit) {
wantedy = ypos-1;
ismyturn = false;
clientthread.setPriority(Thread.NORM_PRIORITY);
}
}
}
}
private class ExitButtonHandler implements
ActionListener {
public void
actionPerformed(ActionEvent ev) {
System.exit(0);
}
}
private class coordinate {
public int x;
public int y;
public coordinate(int newx,
int newy) {
x =
newx;
y =
newy;
}
public boolean
samecoord(coordinate that) {
return x == that.x && y == that.y;
}
}
private class ship {
public int shipsize;
public int health;
public int cornerx;
public int cornery;
public coordinate[]
coordinates;
public boolean
horizontalorientation;
public ship(int size, int
xpos, int ypos, boolean horizontal) {
coordinates = new coordinate[size];
shipsize = size;
health = size;
cornerx = xpos;
cornery = ypos;
horizontalorientation = horizontal;
for
(int a = 0; a < size; a++) {
if (horizontal) {
coordinates[a] = new coordinate(xpos + a, ypos);
} else coordinates[a] = new coordinate(xpos, ypos+a);
}
}
public boolean contains(int
x, int y) {
coordinate acord = new coordinate(x, y);
for
(int a = 0; a < shipsize; a++)
if (coordinates[a].samecoord(acord)) return true;
return false;
}
}
private class boardposition {
public int xpos;
public int ypos;
public boolean hasship =
false;
public boolean hasahit =
false;
public boardposition(int x,
int y) {
xpos
= x;
ypos
= y;
}
}
}