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

相关文章

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

Spring Security--Architecture Overview

1 核心组件 这一节主要介绍一些在Spring Security中常见且核心的Java类,它们之间的依赖,构建起了整个框架。想要理解整个架构,最起码得对这些类眼熟。 1.1 SecurityContextHolder SecurityContextHolder用于存储安全上下文(security context)的信息。当前操作的用户是谁,该用户是否已经被认证,他拥有哪些角色权限…这些都被保

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

Java架构师知识体认识

源码分析 常用设计模式 Proxy代理模式Factory工厂模式Singleton单例模式Delegate委派模式Strategy策略模式Prototype原型模式Template模板模式 Spring5 beans 接口实例化代理Bean操作 Context Ioc容器设计原理及高级特性Aop设计原理Factorybean与Beanfactory Transaction 声明式事物

Hadoop企业开发案例调优场景

需求 (1)需求:从1G数据中,统计每个单词出现次数。服务器3台,每台配置4G内存,4核CPU,4线程。 (2)需求分析: 1G / 128m = 8个MapTask;1个ReduceTask;1个mrAppMaster 平均每个节点运行10个 / 3台 ≈ 3个任务(4    3    3) HDFS参数调优 (1)修改:hadoop-env.sh export HDFS_NAMENOD

Java进阶13讲__第12讲_1/2

多线程、线程池 1.  线程概念 1.1  什么是线程 1.2  线程的好处 2.   创建线程的三种方式 注意事项 2.1  继承Thread类 2.1.1 认识  2.1.2  编码实现  package cn.hdc.oop10.Thread;import org.slf4j.Logger;import org.slf4j.LoggerFactory

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置