import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Iterator;
import java.util.Vector;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Gobang extends JFrame {
ToePanel p[][] = new ToePanel[15][15]; //15X15的棋盘
MessagePanel mp = new MessagePanel(); //系统消息面板
boolean t = false; //游戏是否已开始
boolean t2 = false; // 对方是否已开始
int c = 1; //棋子颜色,主机为黑色1,客户机为白色-1
int x = -1, y = -1; //对方下棋的位置
boolean isExercise = false; //是否处于练习模式(即人机大战模式)
//菜单对象**************************************************************
private JMenuBar mb = new JMenuBar();
private JMenu game = new JMenu("游戏");
private JMenuItem playerVsComputer = new JMenuItem("练习");
private JMenuItem server = new JMenuItem("主机");
private JMenuItem client = new JMenuItem("客户端...");
private JMenuItem cencal = new JMenuItem("断开");
private JMenuItem start = new JMenuItem("开始");
private JMenuItem stop = new JMenuItem("结束");
//网络对战的socket对象***************************************************
private ServerSocket ss;
private Socket s;
private BufferedReader in;
PrintWriter out; //ToePanel类要用到这个对象,所以设为默认访问权限
//线程对象***************************************************************
private WaitClient wc; //等待客户端连接的线程
private Client_in c_in; //监视对方状态的线程
//存放所有的格子刷新的监听器的集合*****************************************
private Vector ActionListeners = new Vector();
public static void main(String[] args) {
Gobang gobang = new Gobang();
gobang.setResizable(false);
Dimension s = Toolkit.getDefaultToolkit().getScreenSize(); //获得屏幕对象,以便使窗体居中显示
gobang.setSize(450, 500);
gobang.setLocation((s.width - gobang.getWidth()) / 2, (s.height - gobang.getHeight()) / 2);
gobang.setVisible(true);
}
public Gobang() {
super("五子棋");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
menuEvent(); //添加各个菜单的事件监听器
menuInit(); //设置各个菜单的Enable属性
//添加棋子面板
JPanel p1 = new JPanel(new BorderLayout());
p1.add(mp, BorderLayout.CENTER);
JPanel p2 = new JPanel(new GridLayout(15, 15));
for (int i = 0; i < 15; i++) {
for (int j = 0; j < 15; j++) {
p[i][j] = new ToePanel(i, j, this);
p2.add(p[i][j]);
playerVsComputer.addActionListener(p[i][j].ms); //点"练习"菜单时清空所有的棋子
server.addActionListener(p[i][j].ms); //点"主机"菜单时清空所有的棋子
client.addActionListener(p[i][j].ms); //点"客户端"菜单时清空所有的棋子
start.addActionListener(p[i][j].ms); //点"开始"菜单时清空所有的棋子
addActionListener(p[i][j].ms); //调用notifyActionListeners()方法时清空所有的棋子
}
}
Container conPane = this.getContentPane();
conPane.setLayout(new BorderLayout());
conPane.add(p1, BorderLayout.NORTH);
conPane.add(p2, BorderLayout.CENTER);
}
//等待客户端连接的线程
class WaitClient extends Thread {
public void run() {
try {
ss = new ServerSocket(10000);
s = ss.accept();
out = new PrintWriter(s.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(s.getInputStream()));
c_in = new Client_in(); //建立显示对方棋子的进程
c_in.start();
mp.setMessage("请你先下!");
//连接成功后再设置这些属性
t = true; //主机先下
t2 = true; //对方已经准备好,这样才能下棋
c = 1; //主机的棋子颜色为黑色1
x = -1; //刚开始时对方还未下棋,所以置为-1
y = -1;
stop.setEnabled(true);
} catch (IOException ie) {
mp.setMessage("五子棋");
menuInit();
JOptionPane.showMessageDialog(Gobang.this, "创建主机失败!", "五子棋",
JOptionPane.ERROR_MESSAGE);
}
}
}
//此进程负责用socket的输入流(in)中的信息来显示对方下棋位置
class Client_in extends Thread {
public void run() {
try {
while (true) {
int h = Integer.parseInt(in.readLine());
int l = Integer.parseInt(in.readLine());
//收到-1表示对方结束了游戏,-2表示对方开始了游戏,否则收到的是对方落子的行号和列号
if (h == -1) {
//如果"结束"菜单可用,则说明正在游戏中,可以弹出消息框;否则只是对方取消了开始,可不弹出消息框
if (stop.isEnabled()) {
mp.setMessage("五子棋");
JOptionPane.showMessageDialog(Gobang.this, "对方已经结束了游戏!", "五子棋",
JOptionPane.INformATION_MESSAGE);
}
gameOver();
} else if (h == -2) {
t2 = true;
//如果自己还未准备好游戏(也就是还没点开始菜单),就显示对方请求游戏的消息框,否则不显示
if (!t) {
int k = JOptionPane.showConfirmDialog(Gobang.this, "对方请求与你游戏,是否同意开始?",
"五子棋", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
if (k == 0) {
mp.setMessage("可以落子了!");
myRun();
notifyActionListeners(); //通知所有的格子刷新监听器进行刷新
}
} else {
mp.setMessage("可以落子了!");
}
} else {
//保存对方下棋的位置,因为自己下棋时要调用这个格子的停止提示stopTiShi()方法
x = h;
y = l;
p[h][l].xiaQi(-c); //画上对方的棋子
p[h][l].tiShi(); //开启提示对方落子位置的功能
t = true; //将这个变量设为true,这样才轮到自己下棋
mp.setMessage("该你下了!");
checkWin(h, l, -c); //判断胜负
}
}
} catch (Exception e) {
mp.setMessage("与对方断开了连接!");
gameOver();
menuInit();
try {
//关闭占用的端口,不关的话就不能再建主机了!
//如果正在游戏时是主机断了,那么这句就一定会发生空指针错误,
//因为关闭端口是主机关,而不是客户端关,
if (ss != null)
ss.close();
} catch (IOException ie) {
}
s = null;
JOptionPane.showMessageDialog(Gobang.this, "连接已断开!请重新建主机或客户端!", "五子棋",
JOptionPane.ERROR_MESSAGE);
}
}
}
/********************************************
函数功能:初始化各个菜单的Enabled属性
输入参数:无
输出参数:无
*******************************************/
private void menuInit() {
playerVsComputer.setEnabled(true);
server.setEnabled(true);
client.setEnabled(true);
cencal.setEnabled(false);
start.setEnabled(false);
stop.setEnabled(false);
}
/********************************************
函数功能:添加各个菜单的事件监听器
输入参数:无
输出参数:无
*******************************************/
private void menuEvent() {
//添加菜单
game.add(playerVsComputer);
game.addSeparator();
game.add(server);
game.add(client);
game.add(start);
game.add(stop);
game.add(cencal);
mb.add(game);
this.setJMenuBar(mb);
//为菜单添加事件监听器
//"练习"菜单
playerVsComputer.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (isExercise)
gameOver();
isExercise = true; //激活练习模式
mp.setMessage("请你先下!");
}
});
//"主机"菜单
server.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
isExercise = false; //取消练习模式
playerVsComputer.setEnabled(false);
server.setEnabled(false);
client.setEnabled(false);
cencal.setEnabled(true);
try {
InetAddress ip = InetAddress.getLocalHost();
String address = ip.getHostName(); //获得本机机器名
mp.setMessage(address + "正等待客户端连接...");
} catch (Exception ee) {
}
wc = new WaitClient();
wc.start();
}
});
//"客户端"菜单
client.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
//连主机
try {
mp.setMessage("五子棋");
isExercise = false; //取消练习模式
String ip = JOptionPane.showInputDialog(Gobang.this, "请输入主机IP地址或主机名称:",
"127.0.0.1");
//ip=null表示用户取消了该输入框
if (ip != null) {
Socket s = new Socket(ip, 10000);
out = new PrintWriter(s.getOutputStream(), true);
in = new BufferedRe