java双人对战五子棋(socket通信)

学习java的时候一直想要做出一个像样的小游戏,所以就动手做了一个远程联网对战的java五子棋小游戏。这个程序我前前后后也是改动了几次,这次发出来的是最终版本了,虽然还是有很多不足,但本人已经没有精力去修改了

 

下面开始进入正题:

--------------------------------------------------------------------分割线----------------------------------------------------------------------------

        该程序基于java语言,由于是远程双人对战,所以本程序由服务器和客户端组成,运行时需要先运行服务器。界面使用的是javafx而非javaSwing。联机对战用的是javaSocket通信,但使用javaSocket进行远程联机对战需要主机有公网ip(对计算机网络知识有点了解都知道,我们上网所用的ip地址基本都是路由器或者运营商提供的局域网ip地址,这种ip地址是不能在外网直接访问到的。要实现直接被访问的效果需要使用公网ip),没有的话可以自行百度怎么使用javaSocket实现远程通信,由于一些原因笔者就不说了。。。如果距离很近,可以连接同一wifi使用局域网直接对战。由于是早期作品,所以代码可读性比较差,本人也懒得重构了~~~

       由于要尽量把功能做到和市面上的五子棋程序差不多,比如各种对话框提示,实时聊天,玩家退出提示啥的,所以代码比较多,对初学者来说并不是那么容易看懂,不过还是有不错的参考价值,是一个不错的小游戏。

服务器:

      相当于一个大厅,自动等待玩家加入,为每两个玩家创建一个房间,实现多组玩家同时在线对战

客户端:

     玩家游戏界面

游戏界面如下:

服务器:

玩家一:

玩家二:

服务器代码:

package server;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.TextArea;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;

import zhou.pane.FiveChessGameConstants;

import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;

public class FiveChessGameServer extends Application implements FiveChessGameConstants
{

	public static void main(String[] args)
	{
		launch(args);
	}

	@Override
	public void start(Stage primaryStage)
	{
		// UI界面
		TextArea textArea = new TextArea();
		textArea.setEditable(false);

		Scene scene = new Scene(new Pane(textArea), 650, 250);
		// 文本域背景透明
//        scene.getStylesheets().add(getClass().getResource("BackgroundColor.css").toExternalForm());
		primaryStage.setScene(scene);
		primaryStage.setTitle("五子棋服务器");
		primaryStage.show();

		// 关闭线程
		primaryStage.setOnCloseRequest(new EventHandler<WindowEvent>()
		{
			@Override
			public void handle(WindowEvent event)
			{
				System.exit(0);
			}
		});

		new Thread(() ->
		{
			ServerSocket serverSocket = null;
			try
			{
				// 一个服务器端口
				serverSocket = new ServerSocket(9520);
				Platform.runLater(() ->
				{
					textArea.appendText(new Date() + ":服务器端口为9520!\n");
				});
				// 等待用户连接
				while (true)
				{
					Platform.runLater(() ->
					{
						textArea.appendText("\n" + new Date() + ":等待玩家连接。。。\n");
					});
					// 等待用户一连接
					Socket user1 = serverSocket.accept();
					Platform.runLater(() ->
					{
						textArea.appendText(new Date() + ":玩家一连接成功!\n");
						textArea.appendText("玩家一的名称和IP地址为:" + user1.getInetAddress().getHostName() + " "
								+ user1.getInetAddress().getHostAddress() + "\n");
					});
					// IO流
					DataOutputStream toUser1 = new DataOutputStream(user1.getOutputStream());
					// 提示玩家一其为黑子
					toUser1.writeInt(player1);

					// 等待用户二连接
					Socket user2 = serverSocket.accept();
					Platform.runLater(() ->
					{
						textArea.appendText(new Date() + ":玩家二连接成功!\n");
						textArea.appendText("玩家二的名称和IP地址为:" + user2.getInetAddress().getHostName() + " "
								+ user2.getInetAddress().getHostAddress() + "\n");
					});
					// IO流
					DataOutputStream toUser2 = new DataOutputStream(user2.getOutputStream());
					// 提示玩家二其为白子
					toUser2.writeInt(player2);

					// 开始一局游戏
					new Thread(new HandleASession(user1, user2)).start();
				}

			} catch (IOException e)
			{
				e.printStackTrace();
			}

		}).start();
	}
}
package server;

import zhou.pane.FiveChessGameConstants;
import zhou.pane.UtilsConnet;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.concurrent.CopyOnWriteArrayList;

//一个游戏进程
class HandleASession implements Runnable, FiveChessGameConstants
{
    private int row, col;
    private boolean waiting = true;
    private boolean chessBack = false;

    //游戏线程结束标志
    private boolean exit = false;

    //两个玩家
    private Socket user1;
    private Socket user2;
    
    //容器
    private CopyOnWriteArrayList<Socket> all = new CopyOnWriteArrayList<Socket>();
    //棋盘
    private int[][] cell = new int[15][15];

    private  DataOutputStream toUser1;
    private DataOutputStream toUser2;

    public HandleASession(Socket user1, Socket user2)
    {

        this.user1 = user1;
        this.user2 = user2;
        all.add(user1);
        all.add(user2);
        try
        {
            toUser1 = new DataOutputStream(this.user1.getOutputStream());
            toUser2 = new DataOutputStream(this.user2.getOutputStream());
        }
        catch (IOException e){
        	System.out.println("-----2-----");
        	release();
        }


        //两个接收玩家信息的类定义
        new Thread(new ChatWith(user1, user2)).start();
        new Thread(new ChatWith(user2,user1)).start();

        //初始化棋盘
        for (int i = 0; i < cell.length; i++) {
            for (int j = 0; j < cell[0].length; j++) {
                cell[i][j] = 0;
            }
        }
    }

    @Override
	public void run()
	{
		try
		{
			// 告诉玩家 1 开始
			toUser1.writeInt(0);
		} catch (Exception e)
		{
			release();
		}
		// 开始一场游戏
		while (!exit)
		{
			try
			{
				// 判断是否需要等待
				waitingForPleyer();
				// 玩家一棋子落子
				cell[row][col] = 1;
				// 判断玩家一是否胜出
				if (isWon() == 1)
				{
					toUser1.writeInt(1);
					toUser1.writeInt(player1_won);
					toUser2.writeInt(1);
					toUser2.writeInt(player1_won);
					sendMove(toUser2, row, col);
					// 游戏结束
					exit = true;
					break;
				} else if (isFull())
				{
					toUser1.writeInt(1);
					toUser1.writeInt(draw);
					toUser2.writeInt(1);
					toUser2.writeInt(draw);
					sendMove(toUser2, row, col);
					// 游戏结束
					exit = true;
					break;
				} else
				{
					// 没有玩家胜出,继续游戏
					toUser2.writeInt(1);
					toUser2.writeInt(keep);
					sendMove(toUser2, row, col);
				}

				// 判断是否需要等待
				waitingForPleyer();
				cell[row][col] = 2;

				if (isWon() == 2)
				{
					toUser1.writeInt(1);
					toUser1.writeInt(player2_won);
					toUser2.writeInt(1);
					toUser2.writeInt(player2_won);
					sendMove(toUser1, row, col);
					// 游戏结束
					exit = true;
					break;
				} else
				{
					// 没有玩家胜出,继续游戏
					toUser1.writeInt(1);
					toUser1.writeInt(keep);
					sendMove(toUser1, row, col);
				}
			} 
			catch (Exception e)
			{
				release();
			}
		}
	}

    //判断是否需要等待
    private void waitingForPleyer() throws InterruptedException{
        while(waiting){
            //判断是否悔棋
            if(chessBack)
            {
                cell[row][col] = 0;
                chessBack = false;
            }


            Thread.sleep(100);
        }
        waiting = true;
    }

    //判断是否胜出
    private int isWon() {
        int user;
        for (int i = 0; i < cell.length; i++) {//判断一行中是否有四个棋子相同
            for (int j = 0; j < cell[0].length && cell[0].length - j >= 5; j++) {//只需判断到倒数第四个棋子,往后则不满足四子相同
                user = cell[i][j];
                int t = 1;
                for (int k = j; k < cell[0].length - 1; k++) {//采用col-1作为限定条件,避免比较时数组越界
                    if (user != 0 && user == cell[i][k + 1]) {
                        t++;
                        if (t == 5) {
                            return user;
                        }
                    } else {
                        break;
                    }
                }
            }
        }
        for (int j = 0; j < cell[0].length; j++) {//判断某一列中是否有五个棋子相同
            for (int i = 0; i < cell.length && cell.length - i >= 5; i++) {
                user = cell[i][j];
                int t = 1;//判断条件,达到五个棋子就退出
                for (int k = i; k < cell.length - 1; k++) {
                    if (user != 0 && user == cell[k + 1][j]) {
                        t++;
                        if (t == 5) {
                            return user;
                        }
                    } else {
                        break;
                    }
                }
            }
        }
        for (int i = 0; i < cell.length && cell.length - i >= 5; i++) {//判断某一对角线上是否有五个棋子相同(右上左下对角线)
            for (int j = 0; j < cell[0].length && cell[0].length - j >= 5; j++) {
                user = cell[i][j];
                int t = 1;
                for (int x = i, y = j; x < cell.length - 1 && y < cell[0].length - 1; x++, y++) {
                    if (user != 0 && user == cell[x + 1][y + 1]) {
                        t++;
                        if (t == 5) {
                            return user;
                        }
                    } else {
                        break;
                    }
                }
            }
        }
        for (int i = 14; i >= 4; i--) {//判断某一对角线上是否有五个棋子相同(右下左上对角线)
            //只有当列行数都大于等于5时,才存在对角线上的五子相同情况
            for (int j = 0; j < cell[0].length && cell[0].length - j >= 5; j++) {
                user = cell[i][j];
                int t = 1;
                for (int x = i, y = j; x >= 1 && y < cell[0].length - 1; x--, y++) {
                    if (user != 0 && user == cell[x - 1][y + 1]) {
                        t++;
                        if (t == 5) {
                            return user;
                        }
                    }
                    else {
                        break;
                    }
                }
            }
        }
        return 3;//行、列、对角线都没有四个棋子相同,返回循环条件3
    }//寻找相同的棋子

    //移动函数
    private void sendMove(DataOutputStream out, int row, int col) throws IOException
    {
        out.writeInt(row);
        out.writeInt(col);
    }

    //判断棋盘是否已满
    private boolean isFull() {
        for (int i = 0; i < cell.length; i++) {
            for (int j = 0; j < cell[0].length; j++) {
                if (cell[i][j] == 0) {
                    return false;
                }
            }
        }
        //已满
        return true;
    }
    
    /**
	 * 用于关闭流
	 */
	private void release()
	{
		exit = true;
		UtilsConnet.close(user1, user2, toUser1, toUser2);
	}
	
	/**
	 * 用户信息交互
	 * @author 久拥-
	 *
	 */
	class ChatWith implements Runnable
	{
		// 判断数据的类型
		private int x;
		// 获取聊天内容
		private String str1 = "";
		
		private Socket user1;
		private Socket user2;

		private boolean exit;

		private DataInputStream fromUser1;
		private DataOutputStream toUser2;

		public ChatWith(Socket user1, Socket user2)
		{
			this.user1 = user1;
			this.user2 = user2;
			try
			{
				fromUser1 = new DataInputStream(this.user1.getInputStream());
				toUser2 = new DataOutputStream(this.user2.getOutputStream());
			} catch (IOException e)
			{
				release();
			}
		}

		@Override
		public void run()
		{
			while (!exit)
			{
				try
				{
					x = fromUser1.readInt();
					if (x == 2)
					{
						str1 = fromUser1.readUTF();
						toUser2.writeInt(2);
						toUser2.writeUTF(str1);
					} else if (x == 1)
					{
						row = fromUser1.readInt();
						col = fromUser1.readInt();
						waiting = false;
					}
					// 悔棋
					else if (x == 3)
					{
						chessBack = true;
						toUser2.writeInt(3);
					}
					// 是否允许悔棋确认
					else if (x == 4)
					{
						Boolean bl = fromUser1.readBoolean();
						// 是否允许悔棋标志
						toUser2.writeInt(4);
						toUser2.writeBoolean(bl);
					}
				} catch (Exception e)
				{
					// 玩家异常退出或者逃跑
					all.remove(user1);
					waiting = false;
					
					try
					{
						for (Socket socket : all)
						{
							if (socket == user2)
							    toUser2.writeInt(20);
						}

					} catch (IOException e1)
					{
						e1.printStackTrace();
					}
					// 释放资源
					release();
				}
			}
		}
		
		/**
		 * 用于关闭流
		 */
		private void release()
		{
			exit = true;
			UtilsConnet.close(user1, user2, fromUser1, toUser2);
		}

		public int getRow()
		{
			return row;
		}

		public int getCol()
		{
			return col;
		}

		public boolean isChessBack()
		{
			return chessBack;
		}

	}
}

棋盘界面代码:

package zhou.pane;

import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Line;

/**
 * 棋盘类
 */
public class LinePane extends Pane
{
    private final static LinePane linePane = new LinePane();

    private int[][] chessXY = new int[225][2];

    private LinePane()
    {
        this.display();
    }

    public static LinePane getInstance()
    {
        return linePane;
    }

    public void display()
    {
        //棋子横坐标
        int chessX = 20;
        for(int i =0; i < 15 ; i++){
            //棋子纵坐标
            int chessY = 20;
            for(int j =0; j < 15; j++){
                //存储各个棋子的坐标
                chessXY[i * 15 + j][0] = chessX;
                chessXY[i * 15 + j][1] = chessY;
                chessY += 50;
            }
            chessX += 50;
        }

        //横
        Line[] line = new Line[15];
        //竖
        Line[] line1 = new Line[15];
        //getChildren().add(new ImageView("棋盘素材/棋盘背景.jpg"));

        //棋盘
        int startX = 20, startY = 20, endX = 720, endY = 20;
        int startX1= 20, startY1 = 20, endX1 = 20, endY1 = 720;
        for(int i = 0; i < 15; i++) {
            line[i] = new Line(startX, startY,endX, endY);
            line[i].setStroke(Color.BLACK);
            getChildren().add(line[i]);
            startY += 50;
            endY +=50;

            line1[i] = new Line(startX1, startY1, endX1, endY1);
            line1[i].setStroke(Color.BLACK);
            getChildren().add(line1[i]);
            startX1 +=50;
            endX1 +=50;
        }
        //棋盘上的五个定位点
        Circle[] circle = new Circle[5];
        for(int i = 0; i < 5; i++){
            if(i == 0){
                circle[i] = new Circle(5);
                circle[i].setCenterX(370);
                circle[i].setCenterY(370);
                circle[i].setFill(Color.BLACK);
                getChildren().addAll(circle[i]);
            }
            else if(i == 1){
                circle[i] = new Circle(5);
                circle[i].setCenterX(220);
                circle[i].setCenterY(220);
                circle[i].setFill(Color.BLACK);
                getChildren().addAll(circle[i]);
            }
            else if(i == 2){
                circle[i] = new Circle(5);
                circle[i].setCenterX(520);
                circle[i].setCenterY(220);
                circle[i].setFill(Color.BLACK);
                getChildren().addAll(circle[i]);
            }
            else if(i == 3){
                circle[i] = new Circle(5);
                circle[i].setCenterX(220);
                circle[i].setCenterY(520);
                circle[i].setFill(Color.BLACK);
                getChildren().addAll(circle[i]);
            }
            else{
                circle[i] = new Circle(5);
                circle[i].setCenterX(520);
                circle[i].setCenterY(520);
                circle[i].setFill(Color.BLACK);
                getChildren().addAll(circle[i]);
            }
        }
    }

    public int getChessX(int row, int col)
    {
        return chessXY[row * 15 + col][0];
    }

    public int getChessY(int row, int col)
    {
        return chessXY[row * 15 + col][1];
    }


}

代码有点多,这里就不放了,我放在百度网盘,需要的自取:

链接: https://pan.baidu.com/s/1JFSClXIN4ReQoMH2Ms-q7g 提取码: 4ptx

写在最后:

       希望对大家有所帮助!

  • 28
    点赞
  • 137
    收藏
    觉得还不错? 一键收藏
  • 33
    评论
下面是一个简单的双人对战五子棋Java 代码示例: ```java import java.util.Scanner; public class Gobang { // 定义棋盘大小 public static final int BOARD_SIZE = 15; // 定义棋盘数组 private String[][] board = new String[BOARD_SIZE][BOARD_SIZE]; // 定义当前玩家和对手的棋子颜色 private String currentPlayer; private String opponent; public Gobang() { // 初始化棋盘 for (int i = 0; i < BOARD_SIZE; i++) { for (int j = 0; j < BOARD_SIZE; j++) { board[i][j] = "+"; } } // 随机选择先手 if (Math.random() > 0.5) { currentPlayer = "X"; opponent = "O"; } else { currentPlayer = "O"; opponent = "X"; } } // 输出棋盘 public void printBoard() { System.out.println(" 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15"); for (int i = 0; i < BOARD_SIZE; i++) { System.out.print((i + 1) + " "); for (int j = 0; j < BOARD_SIZE; j++) { System.out.print(board[i][j] + " "); } System.out.println(); } } // 判断游戏是否结束 public boolean isGameOver(int x, int y) { // 判断横向是否有五个棋子相连 int count = 1; for (int i = y + 1; i < BOARD_SIZE && board[x][i].equals(currentPlayer); i++) { count++; } for (int i = y - 1; i >= 0 && board[x][i].equals(currentPlayer); i--) { count++; } if (count >= 5) { return true; } // 判断纵向是否有五个棋子相连 count = 1; for (int i = x + 1; i < BOARD_SIZE && board[i][y].equals(currentPlayer); i++) { count++; } for (int i = x - 1; i >= 0 && board[i][y].equals(currentPlayer); i--) { count++; } if (count >= 5) { return true; } // 判断右斜向是否有五个棋子相连 count = 1; for (int i = x + 1, j = y + 1; i < BOARD_SIZE && j < BOARD_SIZE && board[i][j].equals(currentPlayer); i++, j++) { count++; } for (int i = x - 1, j = y - 1; i >= 0 && j >= 0 && board[i][j].equals(currentPlayer); i--, j--) { count++; } if (count >= 5) { return true; } // 判断左斜向是否有五个棋子相连 count = 1; for (int i = x + 1, j = y - 1; i < BOARD_SIZE && j >= 0 && board[i][j].equals(currentPlayer); i++, j--) { count++; } for (int i = x - 1, j = y + 1; i >= 0 && j < BOARD_SIZE && board[i][j].equals(currentPlayer); i--, j++) { count++; } if (count >= 5) { return true; } return false; } // 开始游戏 public void start() { Scanner scanner = new Scanner(System.in); int x, y; while (true) { // 输出当前棋盘和玩家提示 printBoard(); System.out.println("轮到 " + currentPlayer + " 玩家落子,请输入坐标(如:3,4):"); // 获取玩家输入的坐标 String input = scanner.next(); String[] inputArray = input.split(","); x = Integer.parseInt(inputArray[0]) - 1; y = Integer.parseInt(inputArray[1]) - 1; // 判断坐标是否合法 if (x < 0 || x >= BOARD_SIZE || y < 0 || y >= BOARD_SIZE || !board[x][y].equals("+")) { System.out.println("坐标不合法,请重新输入!"); continue; } // 在棋盘上落子 board[x][y] = currentPlayer; // 判断游戏是否结束 if (isGameOver(x, y)) { System.out.println(currentPlayer + " 玩家获胜!"); break; } // 切换玩家 String temp = currentPlayer; currentPlayer = opponent; opponent = temp; } scanner.close(); } public static void main(String[] args) { Gobang game = new Gobang(); game.start(); } } ``` 这段代码实现了一个简单的双人对战五子棋游戏,玩家可以通过输入坐标来落子,程序会自动判断是否有玩家获胜。注意,这段代码还没有实现悔棋、保存游戏等功能,你可以根据需要进行扩展。
评论 33
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值