java 三子棋案例添加人机对战

2024-01-16 00:59
文章标签 java 案例 人机 三子 对战

本文主要是介绍java 三子棋案例添加人机对战,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

实验目的:

为基础案例添加人机对战,我给这份源代码做了一个函数的思维导图,让我看的时候对每个函数清楚一点。其中我也总结了一些运行时发现的规律。

源码server:

import java.io.IOException;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Arrays;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;/*** A server for a multi-player tic tac toe game. Loosely based on an example in* Deitel and Deitel��s ��Java How to Program�� book. For this project I created a* new application-level protocol called TTTP (for Tic Tac Toe Protocol), which* is entirely plain text. The messages of TTTP are:** Client -> Server MOVE <n> QUIT** Server -> Client WELCOME <char> VALID_MOVE OTHER_PLAYER_MOVED <n>* OTHER_PLAYER_LEFT VICTORY DEFEAT TIE MESSAGE <text>*/
public class TicTacToeServer {public static void main(String[] args) throws Exception {try (ServerSocket listener = new ServerSocket(58901)) {System.out.println("Tic Tac Toe Server is Running...");ExecutorService pool = Executors.newFixedThreadPool(200);while (true) {Game game = new Game();pool.execute(game.new Player(listener.accept(), 'X'));pool.execute(game.new Player(listener.accept(), 'O'));}}}
}class Game {// Board cells numbered 0-8, top to bottom, left to right; null if emptyprivate Player[] board = new Player[9];Player currentPlayer;public boolean hasWinner() {return (board[0] != null && board[0] == board[1] && board[0] == board[2])|| (board[3] != null && board[3] == board[4] && board[3] == board[5])|| (board[6] != null && board[6] == board[7] && board[6] == board[8])|| (board[0] != null && board[0] == board[3] && board[0] == board[6])|| (board[1] != null && board[1] == board[4] && board[1] == board[7])|| (board[2] != null && board[2] == board[5] && board[2] == board[8])|| (board[0] != null && board[0] == board[4] && board[0] == board[8])|| (board[2] != null && board[2] == board[4] && board[2] == board[6]);}public boolean boardFilledUp() {for(int i=0;i<9;i++){if(board[i]==null) return false;}return true;}public synchronized void move(int location, Player player) {if (player != currentPlayer) {throw new IllegalStateException("Not your turn");} else if (player.opponent == null) {throw new IllegalStateException("You don't have an opponent yet");} else if (board[location] != null) {throw new IllegalStateException("Cell already occupied");}board[location] = currentPlayer;currentPlayer = currentPlayer.opponent;}/*** A Player is identified by a character mark which is either 'X' or 'O'. For* communication with the client the player has a socket and associated Scanner* and PrintWriter.*/class Player implements Runnable {char mark;Player opponent;Socket socket;Scanner input;PrintWriter output;public Player(Socket socket, char mark) {this.socket = socket;this.mark = mark;}public void run() {try {setup();processCommands();} catch (Exception e) {e.printStackTrace();} finally {if (opponent != null && opponent.output != null) {opponent.output.println("OTHER_PLAYER_LEFT");}try {socket.close();} catch (IOException e) {}}}private void setup() throws IOException {input = new Scanner(socket.getInputStream());output = new PrintWriter(socket.getOutputStream(), true);output.println("WELCOME " + mark);//char mark = response.charAt(8);�ͻ��˴���if (mark == 'X') {currentPlayer = this;output.println("MESSAGE Waiting for opponent to connect");} else {opponent = currentPlayer;opponent.opponent = this;opponent.output.println("MESSAGE Your move");}}private void processCommands() {String command="";while (input.hasNextLine()) {command = input.nextLine();if (command.startsWith("QUIT")) {return;} else if (command.startsWith("MOVE")) {//out.println("MOVE " + j);�ͻ��˴���processMoveCommand(Integer.parseInt(command.substring(5)));}}}private void processMoveCommand(int location) {try {move(location, this);output.println("VALID_MOVE");opponent.output.println("OPPONENT_MOVED " + location);if (hasWinner()) {output.println("VICTORY");opponent.output.println("DEFEAT");} else if (boardFilledUp()) {output.println("TIE");opponent.output.println("TIE");}} catch (IllegalStateException e) {output.println("MESSAGE " + e.getMessage());}}}
}

源码client: 

import java.awt.Font;
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.GridBagLayout;
import java.awt.BorderLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Scanner;
import java.io.PrintWriter;
import java.net.Socket;import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;/*** A client for a multi-player tic tac toe game. Loosely based on an example in* Deitel and Deitel��s ��Java How to Program�� book. For this project I created a* new application-level protocol called TTTP (for Tic Tac Toe Protocol), which* is entirely plain text. The messages of TTTP are:** Client -> Server MOVE <n> QUIT** Server -> Client WELCOME <char> VALID_MOVE OTHER_PLAYER_MOVED <n>* OTHER_PLAYER_LEFT VICTORY DEFEAT TIE MESSAGE <text>*/
public class TicTacToeClient {private JFrame frame = new JFrame("Tic Tac Toe");private JLabel messageLabel = new JLabel("...");private Square[] board = new Square[9];private Square currentSquare;private Socket socket;private Scanner in;private PrintWriter out;public TicTacToeClient(String serverAddress) throws Exception {socket = new Socket(serverAddress, 58901);in = new Scanner(socket.getInputStream());out = new PrintWriter(socket.getOutputStream(), true);messageLabel.setBackground(Color.lightGray);frame.getContentPane().add(messageLabel, BorderLayout.SOUTH);JPanel boardPanel = new JPanel();boardPanel.setBackground(Color.black);boardPanel.setLayout(new GridLayout(3, 3, 2, 2));for (int i = 0; i < board.length; i++) {final int j = i;board[i] = new Square();board[i].addMouseListener(new MouseAdapter() {public void mousePressed(MouseEvent e) {currentSquare = board[j];out.println("MOVE " + j);}});boardPanel.add(board[i]);}frame.getContentPane().add(boardPanel, BorderLayout.CENTER);}/*** The main thread of the client will listen for messages from the server. The* first message will be a "WELCOME" message in which we receive our mark. Then* we go into a loop listening for any of the other messages, and handling each* message appropriately. The "VICTORY", "DEFEAT", "TIE", and* "OTHER_PLAYER_LEFT" messages will ask the user whether or not to play another* game. If the answer is no, the loop is exited and the server is sent a "QUIT"* message.*/public void play() throws Exception {try {String response = in.nextLine();char mark = response.charAt(8);char opponentMark = mark == 'X' ? 'O' : 'X';frame.setTitle("Tic Tac Toe: Player " + mark);while (in.hasNextLine()) {response = in.nextLine();if (response.startsWith("VALID_MOVE")) {messageLabel.setText("Valid move, please wait");currentSquare.setText(mark);currentSquare.repaint();} else if (response.startsWith("OPPONENT_MOVED")) {int loc = Integer.parseInt(response.substring(15));board[loc].setText(opponentMark);board[loc].repaint();messageLabel.setText("Opponent moved, your turn");} else if (response.startsWith("MESSAGE")) {messageLabel.setText(response.substring(8));} else if (response.startsWith("VICTORY")) {JOptionPane.showMessageDialog(frame, "Winner Winner");break;} else if (response.startsWith("DEFEAT")) {JOptionPane.showMessageDialog(frame, "Sorry you lost");break;} else if (response.startsWith("TIE")) {JOptionPane.showMessageDialog(frame, "Tie");break;} else if (response.startsWith("OTHER_PLAYER_LEFT")) {JOptionPane.showMessageDialog(frame, "Other player left");break;}}out.println("QUIT");} catch (Exception e) {e.printStackTrace();} finally {socket.close();frame.dispose();}}static class Square extends JPanel {/*** */private static final long serialVersionUID = 1L;JLabel label = new JLabel();public Square() {setBackground(Color.white);setLayout(new GridBagLayout());label.setFont(new Font("Arial", Font.BOLD, 40));add(label);}public void setText(char text) {label.setForeground(text == 'X' ? Color.BLUE : Color.RED);label.setText(text + "");}}public static void main(String[] args) throws Exception {if (args.length != 1) {System.err.println("Pass the server IP as the sole command line argument");return;}TicTacToeClient client = new TicTacToeClient(args[0]);client.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);client.frame.setSize(320, 320);client.frame.setVisible(true);client.frame.setResizable(false);client.play();}
}

实验步骤:

1.client端中添加消息响应框,并且提前建立数据流,根据数据流的返回值判别是否人机对战

2.在server端直接新建一个socket,再通过accept接收,这样做的目的就可以将原本一号玩家走完棋子后发送给人机的消息接收并在server端做出反应。其中我重构了player类的构造函数,加上了服务端的socket和bool类型的人机辨别flag。然后在后面的run函数中根据flag来执行不同的操作,使得无需太多的改动完成应有的效果。

 

3.接受到信号后,我采用alpha-beta剪枝来使人机做出决策,效果是可以的,虽然原理大概懂,但是代码还是不太会写,参考了一位大哥的python代码,我认为应该是比dfs要好。具体参考链接都放在最后了

做的过程中遇到的问题(其实多半是因为没有搞清楚原理,稍微看看运行结果就以为是那样):

1.server端中,因为player会在run函数中的processcommands通过input.HasNextLine()阻塞,想通过更改此判断实现人机对战,但是每次有信息传入时,getInputStream()只能读取一次信息,电脑读取时会产生缓存溢出的错误,也就是没东西给他读。于是我想的有两种方式:

        a.不使用该函数阻塞,而使用输入流读取后的信息存储到某个变量里,然后再进行判断

        感觉这个方法一般般,效率不高,逻辑较为复杂,只是稍微试了一下可行性

        我的方法就是将command变为一个player的属性,然后传给computer试一试

        

        ​​​​​        

        b.将输入流实现两次(没实现),只是觉得可以

        c.使用本来应该在client端的socket

尝试实现人机交互的过程:

其实不懂原理做尝试是挺痛苦的,因为我连scanner一开始都不知道怎么用。。

一开始直接使用对方的输入流

        

        然后发现输入流一条信息只能读取一次,想了想,直接构造一个使用对方的socket的getinputstream(),结果什么都读取不到,调试了确实是用了对方的socket获得的输入流,不知道为什么得不到消息。

当时我猜测原因应该是即使都是相同的socket,但是输入流只有一个,被一个player读取了之后流就消失了。(但是其实是因为没搞懂socket的原理)

        其实搞懂原理再做尝试就非常的简单了,因为new一个socket,与server端accept接受到的socket是不同(serversocket会接受socket并且虚拟化一个新的socket与其对接),但是互相联系的,我只需要在完成移动操作后,本来要给client端的消息发送给电脑类即可。(哎,还是搞懂原理好改,就稍微改动一点就好了,还不会报错)

 

 

实现效果:

1.如果我下了边角,人机会自动的下中间,如果我下中间也会找机会拉平。根据reference中果壳这篇文章的原理来说,如果我下了边角,人机不下中间他就必输。

 

 最后也给大家看看我的源码吧

server:

import java.io.IOException;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Arrays;
import java.util.Random;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;/*** A server for a multi-player tic tac toe game. Loosely based on an example in* Deitel and Deitel’s “Java How to Program” book. For this project I created a* new application-level protocol called TTTP (for Tic Tac Toe Protocol), which* is entirely plain text. The messages of TTTP are:* 发送的都是纯文本* Client -> Server MOVE <n> QUIT** Server -> Client WELCOME <char> VALID_MOVE OTHER_PLAYER_MOVED <n>* OTHER_PLAYER_LEFT VICTORY DEFEAT TIE MESSAGE <text>*/
public class TicTacToeServer {public static void main(String[] args) throws Exception {// create a listener 来监听这个端口的所有东西try (ServerSocket listener = new ServerSocket(58901)) {System.out.println("Tic Tac Toe Server is Running...");// 维护一个线程池ExecutorService pool = Executors.newFixedThreadPool(200);while (true) {// 一直循环构造新的game类Game game = new Game();Socket socket_x = listener.accept();//构造一个scanner,来监听是否需要人机对战Scanner mode_listen = new Scanner(socket_x.getInputStream());// 在得到socket的时间点处理一个线程,在new一个player后结束这个语句,也就是等待一个新的playerpool.execute(game.new Player(socket_x, 'X',false));System.out.println("处理完 X player");String mode = mode_listen.nextLine();if(mode.startsWith("0")) {//人人对战pool.execute(game.new Player(listener.accept(), 'O',false));//当有人时,就get他System.out.println("处理完 O player");} else if (mode.startsWith("1")) {//人机对战Socket socket_O_client = new Socket("127.0.0.1", 58901);Socket socket_O = listener.accept();pool.execute(game.new Player(socket_O, socket_O_client ,'O',true));//当有人时,就get他System.out.println("处理完 O player");}}}}
}class Game {// Board cells numbered 0-8, top to bottom, left to right; null if empty编号为0-8的板单元格,从上到下,从左到右;null如果空private Player[] board = new Player[9];Player currentPlayer;public boolean hasWinner() {// 判断是否有winner,一共八个条件return (board[0] != null && board[0] == board[1] && board[0] == board[2])|| (board[3] != null && board[3] == board[4] && board[3] == board[5])|| (board[6] != null && board[6] == board[7] && board[6] == board[8])|| (board[0] != null && board[0] == board[3] && board[0] == board[6])|| (board[1] != null && board[1] == board[4] && board[1] == board[7])|| (board[2] != null && board[2] == board[5] && board[2] == board[8])|| (board[0] != null && board[0] == board[4] && board[0] == board[8])|| (board[2] != null && board[2] == board[4] && board[2] == board[6]);}public int hasWinner(Player currentPlayer) {// 判断是否有winner,一共八个条件boolean computerwin = (board[0] != null && board[0] == board[1] && board[0] == board[2] && board[0] == currentPlayer )|| (board[3] != null && board[3] == board[4] && board[3] == board[5] && board[3] == currentPlayer)|| (board[6] != null && board[6] == board[7] && board[6] == board[8] && board[6] == currentPlayer)|| (board[0] != null && board[0] == board[3] && board[0] == board[6] && board[0] == currentPlayer)|| (board[1] != null && board[1] == board[4] && board[1] == board[7] && board[1] == currentPlayer)|| (board[2] != null && board[2] == board[5] && board[2] == board[8] && board[2] == currentPlayer)|| (board[0] != null && board[0] == board[4] && board[0] == board[8] && board[0] == currentPlayer)|| (board[2] != null && board[2] == board[4] && board[2] == board[6] && board[2] == currentPlayer);boolean peoplewin = (board[0] != null && board[0] == board[1] && board[0] == board[2] && board[0] == currentPlayer.opponent )|| (board[3] != null && board[3] == board[4] && board[3] == board[5] && board[3] ==  currentPlayer.opponent)|| (board[6] != null && board[6] == board[7] && board[6] == board[8] && board[6] ==  currentPlayer.opponent)|| (board[0] != null && board[0] == board[3] && board[0] == board[6] && board[0] ==  currentPlayer.opponent)|| (board[1] != null && board[1] == board[4] && board[1] == board[7] && board[1] ==  currentPlayer.opponent)|| (board[2] != null && board[2] == board[5] && board[2] == board[8] && board[2] ==  currentPlayer.opponent)|| (board[0] != null && board[0] == board[4] && board[0] == board[8] && board[0] ==  currentPlayer.opponent)|| (board[2] != null && board[2] == board[4] && board[2] == board[6] && board[2] ==  currentPlayer.opponent);if(computerwin){return 1;}if(peoplewin){return -1;}return 0;}public boolean boardFilledUp() {// 判断是否全都填充满for(int i=0;i<9;i++){if(board[i]==null) return false;}return true;}public synchronized void move(int location, Player player) {// synchronized使得方法只能有一个线程访问if (player != currentPlayer) {throw new IllegalStateException("Not your turn");} else if (player.opponent == null) {throw new IllegalStateException("You don't have an opponent yet");} else if (board[location] != null) {throw new IllegalStateException("Cell already occupied");}board[location] = currentPlayer;currentPlayer = currentPlayer.opponent;}public int alpha_beta(Player now_player,Player next_player,int alpha,int beta){if(hasWinner(currentPlayer)!=0){return hasWinner(currentPlayer);}else if (boardFilledUp()) {return 0;}for(int i=0;i<9;i++){if(board[i]==null){board[i] = now_player;int test = alpha_beta(next_player,now_player,alpha,beta);board[i] = null;if (now_player == currentPlayer){if (test>alpha){alpha = test;}if (alpha>=beta){return alpha;}}else {if (test<beta){beta = test;}if (alpha>=beta){return beta;}}}}if (now_player == currentPlayer){return alpha;}else {return beta;}}public int compute_move() {// 判断是否全都填充满,val到底是什么先?应该是随便取得一个值,保证后面的值完整int val = -2;if(hasWinner()){return -1;}String move_ = "";Random rand = new Random();for(int i=0;i<9;i++){if(board[i]==null){board[i] = currentPlayer;// computer moveif(hasWinner()){board[i] =null;return i;}int test = alpha_beta(currentPlayer.opponent,currentPlayer,-2,2);board[i] = null;if (test>val){val = test;move_= String.valueOf((char)(i + '0'));} else if (test==val) {move_+=(char)(i + '0');}}}//字符串存储一个position数组,随机抽取其中一个作为值System.out.println(move_.length());int position =(int) (move_.charAt(rand.nextInt(move_.length()))-'0');return position;}/*** A Player is identified by a character mark which is either 'X' or 'O'. For* communication with the client the player has a socket and associated Scanner* and PrintWriter.*/class Player implements Runnable {//  每个playchar mark;Player opponent;Socket socket;Scanner input;PrintWriter output;boolean computer;Socket socket_client;Scanner input_client;PrintWriter output_client;public Player(Socket socket, char mark, boolean computer) {//  每个player由mark和socket初始化System.out.println("构造player");this.socket = socket;this.mark = mark;this.computer = computer;}public Player(Socket socket, Socket socket_client ,char mark, boolean computer) {//  每个player由mark和socket初始化System.out.println("构造player");this.socket = socket;this.socket_client = socket_client;this.mark = mark;this.computer = computer;}public void run() {try {setup();processCommands();} catch (Exception e) {e.printStackTrace();} finally {if (opponent != null && opponent.output != null) {opponent.output.println("OTHER_PLAYER_LEFT");}try {socket.close();} catch (IOException e) {}}}private void setup() throws IOException {//每次创建一个player类时都会运行下面的结果input = new Scanner(socket.getInputStream());output = new PrintWriter(socket.getOutputStream(), true);if (computer){input_client = new Scanner(socket_client.getInputStream());output_client = new PrintWriter(socket_client.getOutputStream(), true);}output.println("WELCOME " + mark);//char mark = response.charAt(8);客户端代码if (mark == 'X') {//强制对手为O,并且如果还没有创建下一个对手,那么就会发送此消息,如果有下一个对手,那就发送 你的回合currentPlayer = this;output.println("MESSAGE Waiting for opponent to connect");} else {opponent = currentPlayer;opponent.opponent = this;opponent.output.println("MESSAGE Your move");}}private void processCommands() {System.out.println("processCommands");String command="";if (computer){while (input_client.hasNextLine()) {command = input_client.nextLine();if (command.startsWith("QUIT")) {return;} else if (command.startsWith("OPPONENT_MOVED")) {//out.println("MOVE " + j);客户端代码// 判断对面走了哪一步,然后下没走的地方,这里只需要返回一个坐标就够了int space = compute_move();if(space!=-1){System.out.println(space);processMoveCommand(space);}}}} else {while (input.hasNextLine()) {command = input.nextLine();if (command.startsWith("QUIT")) {return;} else if (command.startsWith("MOVE")) {//out.println("MOVE " + j);客户端代码opponent.output.println("MOVE");processMoveCommand(Integer.parseInt(command.substring(5)));}}System.out.println("结束while,也就是一个player线程的生命周期");}}private void processMoveCommand(int location) {try {move(location, this);// 全局变量来定义player和对手,移动后显示多个结果output.println("VALID_MOVE");opponent.output.println("OPPONENT_MOVED " + location);if (hasWinner()) {output.println("VICTORY");opponent.output.println("DEFEAT");} else if (boardFilledUp()) {output.println("TIE");opponent.output.println("TIE");}} catch (IllegalStateException e) {output.println("MESSAGE " + e.getMessage());}}}
}

 client:

import java.awt.Font;
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.GridBagLayout;
import java.awt.BorderLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Scanner;
import java.io.PrintWriter;
import java.net.Socket;import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;/*** A client for a multi-player tic tac toe game. Loosely based on an example in* Deitel and Deitel’s “Java How to Program” book. For this project I created a* new application-level protocol called TTTP (for Tic Tac Toe Protocol), which* is entirely plain text. The messages of TTTP are:** Client -> Server MOVE <n> QUIT** Server -> Client WELCOME <char> VALID_MOVE OTHER_PLAYER_MOVED <n>* OTHER_PLAYER_LEFT VICTORY DEFEAT TIE MESSAGE <text>*/
public class TicTacToeClient {//bool 标志是否人机对战public int flag;private JFrame frame = new JFrame("Tic Tac Toe");private JLabel messageLabel = new JLabel("...");private Square[] board = new Square[9];//private Square currentSquare;private Socket socket;private Scanner in;private PrintWriter out;public int GetFlag() {Object[] flags = {"人人对战","人机对战"};Object choose ;choose = JOptionPane.showInputDialog(frame, "Choose a way:", "对战方式",JOptionPane.QUESTION_MESSAGE,null,flags,flags[0]);if (choose == flags[0]) {return 0;} else if (choose == flags[1]) {return 1;}return 0;}public TicTacToeClient(String serverAddress) throws Exception {//初始化时连接对应接口socket = new Socket(serverAddress, 58901);in = new Scanner(socket.getInputStream());out = new PrintWriter(socket.getOutputStream(), true);// 设置消息框messageLabel.setBackground(Color.lightGray);frame.getContentPane().add(messageLabel, BorderLayout.SOUTH);// 面板JPanel boardPanel = new JPanel();boardPanel.setBackground(Color.black);boardPanel.setLayout(new GridLayout(3, 3, 2, 2));// 这里的board就是9个方块for (int i = 0; i < board.length; i++) {final int j = i;board[i] = new Square();// 设置鼠标点击事件,如果点击了,就将全局变量currentSquare改变board[i].addMouseListener(new MouseAdapter() {public void mousePressed(MouseEvent e) {currentSquare = board[j];out.println("MOVE " + j);}});boardPanel.add(board[i]);}//加入boardframe.getContentPane().add(boardPanel, BorderLayout.CENTER);flag = GetFlag();out.println(flag);}/*** The main thread of the client will listen for messages from the server. The* first message will be a "WELCOME" message in which we receive our mark. Then* we go into a loop listening for any of the other messages, and handling each* message appropriately. The "VICTORY", "DEFEAT", "TIE", and* "OTHER_PLAYER_LEFT" messages will ask the user whether or not to play another* game. If the answer is no, the loop is exited and the server is sent a "QUIT"* message.*/public void play() throws Exception {try {// 将response 设置为 in里面的输入流,然后等待返回结果:WELCOME OString response = in.nextLine();char mark = response.charAt(8); //这里只取其中最后一个字符char opponentMark = mark == 'X' ? 'O' : 'X';frame.setTitle("Tic Tac Toe: Player " + mark);//设置标题while (in.hasNextLine()) { //当有新的信息传入时,反正每个窗口就是一直等待response = in.nextLine();if (response.startsWith("VALID_MOVE")) {// 当对手下棋时,return OPPONENT_MOVED 0messageLabel.setText("Valid move, please wait");currentSquare.setText(mark);currentSquare.repaint();} else if (response.startsWith("OPPONENT_MOVED")) {//System.out.println("opponent moved");int loc = Integer.parseInt(response.substring(15));board[loc].setText(opponentMark);board[loc].repaint();   //当对方下棋后,就将这些显示到自己的上面,并且显示文字messageLabel.setText("Opponent moved, your turn");} else if (response.startsWith("MESSAGE")) {messageLabel.setText(response.substring(8));} else if (response.startsWith("VICTORY")) {JOptionPane.showMessageDialog(frame, "Winner Winner");break;} else if (response.startsWith("DEFEAT")) {JOptionPane.showMessageDialog(frame, "Sorry you lost");break;} else if (response.startsWith("TIE")) {JOptionPane.showMessageDialog(frame, "Tie");break;} else if (response.startsWith("OTHER_PLAYER_LEFT")) {JOptionPane.showMessageDialog(frame, "Other player left");break;}}out.println("QUIT");} catch (Exception e) {e.printStackTrace();} finally {socket.close();frame.dispose();}}static class Square extends JPanel {/*** */private static final long serialVersionUID = 1L;JLabel label = new JLabel();public Square() {setBackground(Color.white);setLayout(new GridBagLayout());label.setFont(new Font("Arial", Font.BOLD, 40));add(label);}public void setText(char text) {label.setForeground(text == 'X' ? Color.BLUE : Color.RED);label.setText(text + "");}}public static void main(String[] args) throws Exception {if (args.length != 1) {System.err.println("Pass the server IP as the sole command line argument");return;}// 创建一个客户类,初始化时TicTacToeClient client = new TicTacToeClient(args[0]);client.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);client.frame.setSize(320, 320);client.frame.setVisible(true);client.frame.setResizable(false);//play就是展示五子棋client.play();}
}

reference:

井字棋的最优策略竟是先占角!| 果壳 科技有意思 (guokr.com)

 查阅java scanner类Java Scanner 类 | 菜鸟教程 (runoob.com)

查阅java getinputstreamJava.lang.Process.getInputStream() 方法 (w3schools.cn)

查阅网络编程动物书

查阅博客园关于Socket和ServerSocket类详解 - 一天一夜 - 博客园

查询alpha-beta剪枝【AI】对抗搜索:Alpha-Beta剪枝搜索图解及井字棋应用的python实现_风巽·剑染春水的博客-CSDN博客_alpha剪枝图解

这篇关于java 三子棋案例添加人机对战的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/610812

相关文章

Java五子棋之坐标校正

上篇针对了Java项目中的解构思维,在这篇内容中我们不妨从整体项目中拆解拿出一个非常重要的五子棋逻辑实现:坐标校正,我们如何使漫无目的鼠标点击变得有序化和可控化呢? 目录 一、从鼠标监听到获取坐标 1.MouseListener和MouseAdapter 2.mousePressed方法 二、坐标校正的具体实现方法 1.关于fillOval方法 2.坐标获取 3.坐标转换 4.坐

Spring Cloud:构建分布式系统的利器

引言 在当今的云计算和微服务架构时代,构建高效、可靠的分布式系统成为软件开发的重要任务。Spring Cloud 提供了一套完整的解决方案,帮助开发者快速构建分布式系统中的一些常见模式(例如配置管理、服务发现、断路器等)。本文将探讨 Spring Cloud 的定义、核心组件、应用场景以及未来的发展趋势。 什么是 Spring Cloud Spring Cloud 是一个基于 Spring

Javascript高级程序设计(第四版)--学习记录之变量、内存

原始值与引用值 原始值:简单的数据即基础数据类型,按值访问。 引用值:由多个值构成的对象即复杂数据类型,按引用访问。 动态属性 对于引用值而言,可以随时添加、修改和删除其属性和方法。 let person = new Object();person.name = 'Jason';person.age = 42;console.log(person.name,person.age);//'J

java8的新特性之一(Java Lambda表达式)

1:Java8的新特性 Lambda 表达式: 允许以更简洁的方式表示匿名函数(或称为闭包)。可以将Lambda表达式作为参数传递给方法或赋值给函数式接口类型的变量。 Stream API: 提供了一种处理集合数据的流式处理方式,支持函数式编程风格。 允许以声明性方式处理数据集合(如List、Set等)。提供了一系列操作,如map、filter、reduce等,以支持复杂的查询和转

Java面试八股之怎么通过Java程序判断JVM是32位还是64位

怎么通过Java程序判断JVM是32位还是64位 可以通过Java程序内部检查系统属性来判断当前运行的JVM是32位还是64位。以下是一个简单的方法: public class JvmBitCheck {public static void main(String[] args) {String arch = System.getProperty("os.arch");String dataM

详细分析Springmvc中的@ModelAttribute基本知识(附Demo)

目录 前言1. 注解用法1.1 方法参数1.2 方法1.3 类 2. 注解场景2.1 表单参数2.2 AJAX请求2.3 文件上传 3. 实战4. 总结 前言 将请求参数绑定到模型对象上,或者在请求处理之前添加模型属性 可以在方法参数、方法或者类上使用 一般适用这几种场景: 表单处理:通过 @ModelAttribute 将表单数据绑定到模型对象上预处理逻辑:在请求处理之前

eclipse运行springboot项目,找不到主类

解决办法尝试了很多种,下载sts压缩包行不通。最后解决办法如图: help--->Eclipse Marketplace--->Popular--->找到Spring Tools 3---->Installed。

JAVA读取MongoDB中的二进制图片并显示在页面上

1:Jsp页面: <td><img src="${ctx}/mongoImg/show"></td> 2:xml配置: <?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001

Java面试题:通过实例说明内连接、左外连接和右外连接的区别

在 SQL 中,连接(JOIN)用于在多个表之间组合行。最常用的连接类型是内连接(INNER JOIN)、左外连接(LEFT OUTER JOIN)和右外连接(RIGHT OUTER JOIN)。它们的主要区别在于它们如何处理表之间的匹配和不匹配行。下面是每种连接的详细说明和示例。 表示例 假设有两个表:Customers 和 Orders。 Customers CustomerIDCus

22.手绘Spring DI运行时序图

1.依赖注入发生的时间 当Spring loC容器完成了 Bean定义资源的定位、载入和解析注册以后,loC容器中已经管理类Bean 定义的相关数据,但是此时loC容器还没有对所管理的Bean进行依赖注入,依赖注入在以下两种情况 发生: 、用户第一次调用getBean()方法时,loC容器触发依赖注入。 、当用户在配置文件中将<bean>元素配置了 lazy-init二false属性,即让