我已经开发了一个使用极小化-极大化和 Alpha-Beta 剪枝的可工作的国际象棋引擎,但是我想通过让算法自我对弈来测试它,即电脑对电脑。我尝试了各种方法但都没有成功。不知道该如何实现这个功能?
public class Main { static JTextArea textField; public static void main(String[] args) { while ( 'K' != ABChess.board[ABChess.kingLocationUU/8][ABChess.kingLocationUU%8]) {ABChess.kingLocationUU++;} while ( 'k' != ABChess.board[ABChess.kingLocationLL/8][ABChess.kingLocationLL%8]) {ABChess.kingLocationLL++;} Asset.init("/images/ChessPiecess.png"); ABChess.updateKingLocations(); //print(); JPanel depthPanel = depthPanel(); JPanel optionPanel = optionPanel(); JPanel logPanel = logPanel(); JPanel menuPanel = new JPanel(); menuPanel.setPreferredSize(new Dimension(140, 100)); menuPanel.setLayout(new BoxLayout(menuPanel, BoxLayout.Y_AXIS)); menuPanel.add(depthPanel); menuPanel.add(optionPanel); menuPanel.add(logPanel); GUInterface gui = new GUInterface(); JPanel panel = new JPanel(new BorderLayout()); panel.add(gui); panel.add(menuPanel, BorderLayout.EAST); JFrame frame = new JFrame(ABChess.title); frame.setSize(ABChess.width, ABChess.height); frame.add(panel); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setResizable(true); frame.setLocationRelativeTo(null); frame.setVisible(true); System.out.println(ABChess.possibleMoves()); ABChess.playerChoice = JOptionPane.showOptionDialog(null, "Who wants to make the first move?", "Who moves first?", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, ABChess.options, ABChess.options[0]); if (ABChess.playerChoice == 0){ ABChess.flipBoard(); long startTime=System.currentTimeMillis(); Move autoMove = AlphaBeta.alphaBeta(ABChess.gameDepth, 1000000, -1000000, new Move(), 0); long endTime=System.currentTimeMillis(); ABChess.makeMove(autoMove); ABChess.flipBoard(); System.out.println("COMPUTER'S MOVE TOOK "+((endTime-startTime)/1000.0)+" SECONDS"); ABChess.printBoard(); frame.repaint(); displayMessage("Took "+((endTime-startTime)/1000.0)+" seconds"); } }
这是运行文件时对算法的初始调用。
public void mousePressed(MouseEvent event) { if ( event.getX() < 8*sizeOfSquare && event.getY() < 8*sizeOfSquare) { mouseX = event.getX(); mouseY = event.getY(); repaint(); } } public void mouseReleased(MouseEvent event) { if (event.getX() < 8*sizeOfSquare && event.getY() < 8*sizeOfSquare) { newMouseX = event.getX(); newMouseY = event.getY(); if (event.getButton() == MouseEvent.BUTTON1) { // Regular move Move legalMovesMove = new Move(mouseY/sizeOfSquare, mouseX/sizeOfSquare, newMouseY/sizeOfSquare, newMouseX/sizeOfSquare, Test6.board[newMouseY/sizeOfSquare][newMouseX/sizeOfSquare]); java.util.List<Move> legalMoves = ABChess.possibleMoves(); for(Move m : legalMoves) { if (m.equals(legalMovesMove)) { ABChess.makeMove(legalMovesMove); ABChess.flipBoard(); long startTime=System.currentTimeMillis(); Move autoMove = AlphaBeta.alphaBeta(ABChess.gameDepth, 1000000, -1000000, new Move(), 0); long endTime=System.currentTimeMillis(); ABChess.makeMove(autoMove); ABChess.flipBoard(); System.out.println("COMPUTER'S MOVE TOOK "+((endTime-startTime)/1000.0)+" SECONDS"); ABChess.printBoard(); repaint(); } } checkMate = ABChess.kingSafe(); if(checkMate == false){ int yes = JOptionPane.showOptionDialog(null, "Do you want to make the first move?", "Who moves first?", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, null, JOptionPane.YES_OPTION); if (yes == JOptionPane.YES_OPTION){ ABChess.resetGame(); repaint(); } else if (yes == JOptionPane.NO_OPTION){ System.exit(0); } } legalMoves = ABChess.possibleMoves(); if (legalMoves.size() == 0) { ABChess.playAgain = JOptionPane.showOptionDialog(null, "Stalemate! Wanna play again?", "Draw!", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, ABChess.choice, ABChess.choice[1]); if (ABChess.playAgain == 0) { System.out.println("Yes I will"); ABChess.resetGame(); repaint(); } else { System.exit(0); } } } } }
这是每次释放鼠标时调用算法的地方。不确定如何编写代码让它使用白棋自我对弈而不是我来操作。
回答:
通常我会将玩家和游戏分开,游戏会向玩家对象请求交互。玩家对象可以是人类(因此所需的输入会委托给某个用户界面),也可以是AI(因此会委托给某个实现来决定最佳移动)。
我建议使用对象来表示ABChess游戏,而不是使用静态方法。
因此,通过一些重构和将UI与逻辑分离,代码可能会像这样:
interface Player { Move decide(List<Move> legalMoves);}class ChessGame { ABChess game; Player player1; Player player2; UIInterface ui; ChessGame(Player player1, Player player2, UIInterface ui) { this.player1 = player1; this.player2 = player2; this.ui = ui; game = ... } public void simulate() { // ... initial ui ... boolean player1Turn = true; do { Move move = null; if (player1Turn) { move = player1.decide(game.possibleMoves()); } else { move = player2.decide(game.possibleMoves()); } game.makeMove(move); // ... update ui ... player1Turn = !player1Turn; // check if somebody has won ... } while (game.isRunning()); // ... update ui with the game result ... }}
一旦完成这些,模拟游戏就变得简单了。你只需要用适当的玩家初始化ChessGame
并调用simulate方法。此时,你也可以决定完全跳过UI展示(这样学习速度会更快)。