您好,登錄后才能下訂單哦!
這篇文章主要介紹“java如何實現聯機五子棋”的相關知識,小編通過實際案例向大家展示操作過程,操作方法簡單快捷,實用性強,希望這篇“java如何實現聯機五子棋”文章能幫助大家解決問題。
下面是客戶端運行的效果:
這里是代碼包的結構:
接著我來依次說下這些類所完成的功能
Media包
Media包:主要是放了五子棋的背景圖片和播放音樂的類以及音樂內容
播放音樂這個類是我從室友那拿的,所以我也不是很懂,瞄了一眼是用Applet完成的,只能處理.wav后綴的音樂
Net包
Net包:包含兩個類,細心的小伙伴應該注意到客戶端是沒有主方法的。客戶端中其實是包含與服務端進行通信的socket的,其中包含一些讀和寫的方法。服務端我采用的是線程池的方法來處理客戶端的請求(線程池這部分我也不是特別了解,用起來和多線程感覺差不多)。
View包
View包:包含四個類,分別是ChessBoard,ChessPanel,Pieces和WhoWin 類
ChessBoard是一個包含Main方法的JFrame,命令面板和棋盤面板都是添加到這個JFrame中的。
ChessPanel是一個棋盤面板,里面完成了如:畫19*19的棋盤線條,加載背景圖片,不停的接收來自服務端的消息并處理(把棋子加到面板),處理每次點擊后添加棋子到面板并發送棋子到服務器,判斷勝負并且給出提示消息。
Pieces是一個棋子,其中有包含如顏色,棋子半徑,棋子位置和命令(和前面的命令面板配合使用,默認是發送)等屬性。
WhoWin就是五子棋中判斷誰輸誰贏的部分。每下一步就需要判斷。
播放音樂的類:
package Media.Music; import java.io.File; import java.io.IOException; import javax.sound.sampled.AudioInputStream; import javax.sound.sampled.AudioSystem; import javax.sound.sampled.Clip; import javax.sound.sampled.LineUnavailableException; import javax.sound.sampled.UnsupportedAudioFileException; public class PlayMusic { private Clip clip; public PlayMusic(String filePath) throws LineUnavailableException, UnsupportedAudioFileException, IOException { File file = new File(filePath); AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(file); clip = AudioSystem.getClip(); clip.open(audioInputStream); } public void play() { clip.setFramePosition(1); clip.start(); } public void loop() { clip.loop(Clip.LOOP_CONTINUOUSLY); } public void stop() { clip.stop(); } }
TcpClient:
package net; import view.Pieces; import java.io.*; import java.net.Socket; public class TcpClient{ private Socket socket; private ObjectInputStream ois; private ObjectOutputStream oos; public TcpClient(Socket socket,ObjectInputStream ois,ObjectOutputStream oos){ this.socket= socket; this.ois = ois; this.oos = oos; } public Socket getSocket() { return socket; } public void setSocket(Socket socket) { this.socket = socket; } public ObjectInputStream getOis() { return ois; } public void setOis(ObjectInputStream ois) { this.ois = ois; } public ObjectOutputStream getOos() { return oos; } public void setOos(ObjectOutputStream oos) { this.oos = oos; } public void send(Pieces pieces) throws IOException { oos.writeObject(pieces); System.out.println(socket+"向服務器發送消息"); } public Pieces accept() throws IOException, ClassNotFoundException { Pieces pieces = (Pieces) ois.readObject(); System.out.println(socket+"從服務器讀取消息"); return pieces; } public void close(){ ; } }
TcpServer:
package net; import view.Pieces; import java.io.*; import java.net.ServerSocket; import java.net.Socket; import java.net.SocketException; import java.util.ArrayList; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class TcpServer { public static void main(String[] args) { // 保存客戶端處理的線程 ArrayList<UserThread> userList = new ArrayList<>(); // 固定大小的線程池只支持兩個線程,用來處理客戶端 ExecutorService es = Executors.newFixedThreadPool(2); try { ServerSocket server = new ServerSocket(10086); System.out.println("服務器已經啟動,正在等待客戶端連接......"); while (true) { //接收客戶端的Socket,如果沒有客戶端連接就一直卡在這里 Socket socket = server.accept(); // 每來一個用戶就創建一個線程 UserThread user = new UserThread(socket, userList); // 開啟線程 es.execute(user); } } catch (IOException e) { e.printStackTrace(); } } } class UserThread implements Runnable { private Socket socket = null; private static ArrayList<UserThread> list; // 客戶端線程集合 private ObjectOutputStream oos; private ObjectInputStream ois; private boolean flag = true;// 標記 public UserThread(Socket socket, ArrayList<UserThread> list) { this.socket = socket; this.list = list; list.add(this); // 把當前線程加入list中 } @Override public void run() { UserThread user = null; try { System.out.println("客戶端:" + socket.getInetAddress().getHostAddress() + "已經連接"); ois = new ObjectInputStream(socket.getInputStream()); oos = new ObjectOutputStream(socket.getOutputStream()); while(true){ Pieces pieces = (Pieces) ois.readObject(); // 客戶端發給服務端的消息,把他寫到其它套接字中去 int size = list.size(); for (int i = 0; i < size; i++) { user = list.get(i); if (user.socket != socket) { user.oos.writeObject(pieces); System.out.println("從"+socket+"向"+user.socket+"發送消息"); } } } } catch(SocketException e){ // todo 客戶端掉線后,移除客戶端。沒想好{1.從客戶端列表移除當前元素,關閉當前:socket,通知另一方:這一方已經掉線,然后關閉這一方的socket} try { int i = list.size(); if (i ==2){ list.remove(user); System.out.println("已經刪除了一個客戶端"); list.get(0).oos.writeObject(new Pieces("對方掉線")); }else if (i==1){ list.remove(0); System.out.println("又移除了另一個客戶端"); } } catch (IOException ex) { ex.printStackTrace(); } } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } }
ChessBoard:
/* * 1.變量值不變的問題 * 2.輸入輸出流先后順序的問題(socket阻塞) * 3.socket 短連接不關閉輸入輸出流,為何看起來就像長連接一樣(長短連接的區別是什么) * */ // todo 一個提示框 package view; import Media.Music.PlayMusic; import javax.sound.sampled.LineUnavailableException; import javax.sound.sampled.UnsupportedAudioFileException; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.IOException; public class ChessBoard extends JFrame implements ActionListener { private JButton PlayMusic = new JButton("播放音樂"); private ChessPanel chessPanel; private Panel CommandPanel = new Panel(); private JButton reStart = new JButton("重新開始"); private JButton fail = new JButton("認輸"); private JButton Regret = new JButton("悔棋"); private String command=null; // 觸發按鈕后發送的命令 private PlayMusic music = null; private int count = 1; // todo 靜態語句塊 { try { music = new PlayMusic("./src/Media/Music/bg3.wav"); } catch (LineUnavailableException e) { e.printStackTrace(); } catch (UnsupportedAudioFileException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } public ChessBoard() { this.setTitle("歡樂五子棋"); chessPanel = new ChessPanel(); this.add(chessPanel,BorderLayout.CENTER); reStart.addActionListener(this); fail .addActionListener(this); Regret.addActionListener(this); PlayMusic.addActionListener(this); CommandPanel.add(reStart); CommandPanel.add(fail); CommandPanel.add(Regret); CommandPanel.add(PlayMusic); this.add(CommandPanel,BorderLayout.SOUTH); this.setBounds(10, 10, 800, 800); this.setVisible(true); this.setResizable(false); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } public static void main(String[] args) { ChessBoard Board = new ChessBoard(); } @Override public void actionPerformed(ActionEvent e) { if(e.getSource()==reStart){ command ="重新開始"; chessPanel.canPlay = true; }else if(e.getSource()==fail){ command ="認輸"; JOptionPane.showMessageDialog(chessPanel,"It's a pity,you have fail the game!"); chessPanel.canPlay = false; }else if (e.getSource()==Regret){ command ="悔棋"; }else if (e.getSource()==PlayMusic){ // todo 播放音樂,單數次播放; if (count%2==1){ music.play(); }else { music.stop(); } count++; command = null; } if(command!=null){ Pieces pieces = new Pieces(command); try { this.chessPanel.client.send(pieces); } catch (IOException ex) { ex.printStackTrace(); } } } }
ChessPanel:
package view; // 五子棋面板,就是在這里面畫圖。 // todo 背景圖片 ,也許一個背景音樂 import net.TcpClient; import javax.swing.*; import java.awt.*; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.net.ConnectException; import java.net.Socket; import java.util.ArrayList; import java.util.Iterator; public class ChessPanel extends JPanel implements MouseListener{ // TODO 從服務器接收來的棋子 ,值不變有問題 // Pieces accept_pieces = new Pieces(); // Pieces send_pieces = new Pieces(); whoWin ifWin =new whoWin() ; // 是否勝利 TcpClient client = null; // 客戶端 boolean canPlay = true; // 是否能繼續玩 boolean isBlack = true; // 是否黑子,黑1,白2 ArrayList<Pieces> allPieces = new ArrayList<>(); // 存儲棋子對象,就是通過這個畫圖的 int [][] allChess = new int[19][19]; int PanelWidth; int PanelHeight; int width = 600; int height = 600; int temp = width / 18; int xbase,ybase; Image image = Toolkit.getDefaultToolkit().getImage("./src/Media/bg.jpeg"); // "./"表示當前項目下 public ChessPanel(){ this.addMouseListener(this); try { Socket socket = new Socket("172.27.29.190", 10086); //TODO 構建輸出輸入流,輸入輸出流問題,先輸出后輸入 ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream()); ObjectInputStream ois = new ObjectInputStream(socket.getInputStream()); client = new TcpClient(socket,ois,oos); new Thread(new getMessage()).start(); // 開啟讀取的線程 } catch (ConnectException e){ System.out.println("服務器拒絕連接!"); } catch (IOException e) { e.printStackTrace(); }catch(Exception e ){ e.printStackTrace(); } } // 畫圖部分 public void paintComponent(Graphics g) { super.paintComponent(g); PanelWidth = this.getSize().width; // 這兩步驟 PanelHeight = this.getSize().height; xbase = (PanelWidth - width) / 2; ybase = (PanelHeight - height) / 2; Graphics2D g2d = (Graphics2D) g; // this.setBackground(new Color(246, 186, 114)); g2d.drawImage(image,0,0,this.getWidth(),this.getHeight(),this); int x1, y1, x2, y2; // 畫線 for (int i = 0; i < 19; i++) { if (i == 0 || i == 18) { g2d.setStroke(new BasicStroke(3.0f)); } else g2d.setStroke(new BasicStroke(1.0f)); x1 = xbase + temp * i; y1 = ybase; y2 = ybase + 18 * temp; g2d.drawLine(x1, y1, x1, y2); x1 = xbase; y1 = ybase + temp * i; x2 = xbase + temp * 18; g2d.drawLine(x1, y1, x2, y1); } // 開始畫棋子 int radius ; int xPos,yPos; Iterator it = allPieces.iterator(); // 迭代器遍歷arraylist while(it.hasNext()){ Pieces pieces = (Pieces) it.next(); radius = pieces.getRadius(); xPos = pieces.getxPos(); yPos = pieces.getyPos(); System.out.println(pieces.getColor()+","+pieces.getxPos()+","+pieces.getyPos()); if (pieces.getColor() == 1){ g2d.setColor(Color.black); g2d.fillOval(xPos*temp+xbase-radius/2,yPos*temp+ybase-radius/2,radius,radius); } else if (pieces.getColor() == 2) { g2d.setColor(Color.white); g2d.fillOval(xPos * temp + xbase - radius / 2, yPos * temp + ybase - radius / 2, radius, radius); } } } @Override public void mousePressed(MouseEvent e) { int x ,y ; if (canPlay) { x = e.getX(); y = e.getY(); // 判斷鼠標點擊位置 if (x >= xbase & x <= (xbase + 18 * temp) & y >= ybase & y < (ybase + 18 * temp)) { // 判斷是不是下在空的位置 int tempX = (x - xbase) / temp, tempY = (y - ybase) / temp; // todo 這里是關鍵判斷這點坐標的數組下標是什么 if ((x - xbase) % temp > temp / 2) { x = tempX + 1; } else x = tempX; if ((y - ybase) % temp > temp / 2) y = tempY + 1; else y = tempY; // 先判斷有沒有棋子,處理沒有棋子的情況 if (allChess[x][y] != 0) { JOptionPane.showMessageDialog(this, "這里有棋子了"); } else { Pieces send_pieces = new Pieces(); send_pieces.setxPos(x); send_pieces.setyPos(y); if (isBlack){ send_pieces.setColor(1); allChess[x][y] = 1; isBlack = false; } else{ send_pieces.setColor(2); allChess[x][y]=2; isBlack = true; } allPieces.add(send_pieces); // 向棋子隊列加入當前棋子 canPlay = false;// canPlay在true情況下, 點擊一次后不能點擊了 this.repaint(); ifWin = new whoWin(allChess,x,y); // 如果贏了,就不能玩了,并且給出提示消息,你贏了; if(ifWin.isWin()){ canPlay = false; JOptionPane.showMessageDialog(this,"Congratulations you have won tha game !"); } try { if (client!=null){ client.send(send_pieces); } } catch (IOException ex) { ex.printStackTrace(); } } } } } // 讀取來自服務器端的信息 class getMessage implements Runnable{ private boolean flag = true; public void setFlag(boolean flag) { this.flag = flag; } @Override public void run() { // 循環讀 while(flag){ if(client!=null){ try { Pieces accept_pieces = client.accept(); String command = accept_pieces.getCommand(); int color = accept_pieces.getColor(); switch (command){ case "發送":{ canPlay = true; if (color == 1){ isBlack = false;//對方為黑我為白 }else{ isBlack = true; } allPieces.add(accept_pieces); allChess[accept_pieces.getxPos()][accept_pieces.getyPos()]= accept_pieces.getColor(); ChessPanel.this.repaint(); ifWin.setY(accept_pieces.getyPos()); ifWin.setX(accept_pieces.getxPos()); ifWin.setAllChess(allChess); if(ifWin.isWin()){ canPlay = false; JOptionPane.showMessageDialog(ChessPanel.this,"It's a pity you have fail the game!"); } break; } case "悔棋":{ int i = JOptionPane.showConfirmDialog(ChessPanel.this,"對方請求悔棋,是否同意!"); // yes 0,no 1,cancel 2,closed -1 Pieces pieces = new Pieces(); if (i == 0){ // 同意悔棋:1.同意對方悔棋 pieces.setCommand("同意悔棋"); // arraylist 去除末尾的兩個值,對應allChess置0 int size = allPieces.size(); for (int j = 1;j<=2;j++){ allChess[allPieces.get(size-j).getxPos()][allPieces.get(size-j).getyPos()]=0; allPieces.remove(size-j); } ChessPanel.this.repaint(); }else if(i==1){ pieces.setCommand("不同意悔棋"); } client.send(pieces); break; } case "認輸":{ // 不能繼續玩下去,你已經勝利 JOptionPane.showMessageDialog(ChessPanel.this,"對方認輸"); canPlay = false; JOptionPane.showMessageDialog(ChessPanel.this,"Congratulations you have won tha game !"); break; } case "重新開始":{ // 是否同意重新開始 int i = JOptionPane.showConfirmDialog(ChessPanel.this,"對方請求重新開始,是否同意"); Pieces pieces = new Pieces(); if(i == 0){// allChess 和 allPieces全部置0; pieces.setCommand("同意重新開始"); int size = allPieces.size(); System.out.println("arraylist 長度:"+size); for (int j = 0;j<size;j++){// 移除隊首元素 allChess[allPieces.get(0).getxPos()][allPieces.get(0).getyPos()] = 0; allPieces.remove(0); } canPlay = true; ChessPanel.this.repaint(); }else if (i ==1){ pieces.setCommand("不同意重新開始"); } client.send(pieces); break; } case "同意悔棋":{// allpieces 和 allchess 回退 JOptionPane.showMessageDialog(ChessPanel.this,"對方同意悔棋"); int size = allPieces.size(); for (int j = 1;j<=2;j++){ allChess[allPieces.get(size-j).getxPos()][allPieces.get(size-j).getyPos()]=0; allPieces.remove(size-j); } ChessPanel.this.repaint(); break; } case "不同意悔棋":{ JOptionPane.showMessageDialog(ChessPanel.this,"對方不同意悔棋"); break; } case "同意重新開始":{ // 全部置0,調用repaint 方法 JOptionPane.showMessageDialog(ChessPanel.this,"對方同意重新開始"); int size = allPieces.size(); for (int j = 0;j<size;j++){ // todo 移除隊首元素arraylist 長度改變;序列也發生改變 allChess[allPieces.get(0).getxPos()][allPieces.get(0).getyPos()] = 0; allPieces.remove(0); } canPlay = true; ChessPanel.this.repaint(); break; } case "不同意重新開始":{ JOptionPane.showMessageDialog(ChessPanel.this,"對方不同意重新開始"); break; } case "對方掉線":{ // 對方已經掉線 JOptionPane.showMessageDialog(ChessPanel.this,"不好意思,對方已經掉線!"); canPlay = false; break; } } } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } } } } @Override public void mouseClicked(MouseEvent e) { } @Override public void mouseReleased(MouseEvent e) { } @Override public void mouseEntered(MouseEvent e) { } @Override public void mouseExited(MouseEvent e) { } }
Pieces:
package view; import java.io.Serializable; // 存儲棋子的相關信息 public class Pieces implements Serializable { private int radius = 16; private int color = 0; private int xPos ; private int yPos; private String command = "發送"; public String getCommand() { return command; } public void setCommand(String command) { this.command = command; } public Pieces(int color, int xPos, int yPos){ this.color = color; this.xPos = xPos; this.yPos = yPos; } public Pieces(){ } public Pieces(String command){ this.command = command; } public int getRadius() { return radius; } public void setRadius(int radius) { this.radius = radius; } public int getColor() { return color; } public void setColor(int color) { this.color = color; } public int getxPos() { return xPos; } public void setxPos(int xPos) { this.xPos = xPos; } public int getyPos() { return yPos; } public void setyPos(int yPos) { this.yPos = yPos; } }
WhoWin:
package view; public class whoWin { // 判斷是誰贏了 private int allChess[][] = new int[19][19]; private int x = 0; private int y = 0; public whoWin(){ } public whoWin(int allChess[][],int x,int y){ this.allChess = allChess; this.x = x; this.y = y; } public void setAllChess(int allChess[][]){ this.allChess = allChess; } public void setX(int x){ this.x = x; } public void setY(int y ){ this.y = y; } public boolean isWin() { int color = allChess[x][y]; int count; count = this.Count(1, 0, color); // 對橫方向的判斷 if (count >= 5) { return true; } else { count = this.Count(0, 1, color); // 對豎方向的判斷 if (count >= 5) { return true; } else { count = this.Count(1, 1, color); // 對左上方向的判斷 if (count >= 5) return true; else { count = this.Count(1, -1, color); // 對右上方向的判斷 if (count >= 5) return true; } } } return false; } private int Count(int xChange, int yChange, int color) { int count = 1; int tempX = xChange, tempY = yChange; while (color == allChess[x + xChange][y + yChange]) { count++; if (xChange != 0) { xChange++; } if (yChange != 0) { if (yChange > 0) yChange++; else yChange--; } } xChange = tempX; yChange = tempY; while (color == allChess[x - xChange][y - yChange]) { count++; if (xChange != 0) xChange++; if (yChange != 0) { if (yChange > 0) yChange++; else yChange--; } } return count; } }
關于“java如何實現聯機五子棋”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識,可以關注億速云行業資訊頻道,小編每天都會為大家更新不同的知識點。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。