Added alpha-beta pruning threshold to the AI and a configuration dialog
This commit is contained in:
		| @@ -25,14 +25,16 @@ public class AIPlayer extends Player { | ||||
|  | ||||
| 	private int	availableProcessors; | ||||
| 	private int	maxDepth; | ||||
| 	private int	alphaBetaThreshold; | ||||
|  | ||||
| 	private volatile boolean exitRequested; | ||||
| 	private volatile ExecutorService	executor; | ||||
|  | ||||
| 	public AIPlayer(Board board, Color color, int maxDepth) { | ||||
| 	public AIPlayer(Board board, Color color, int maxDepth, int alphaBetaThreshold) { | ||||
| 		super(board, color); | ||||
| 		availableProcessors	= Runtime.getRuntime().availableProcessors(); | ||||
| 		this.maxDepth		= maxDepth; | ||||
| 		this.alphaBetaThreshold	= alphaBetaThreshold; | ||||
| 		exitRequested		= false; | ||||
| 	} | ||||
|  | ||||
| @@ -62,7 +64,8 @@ public class AIPlayer extends Player { | ||||
| 				if (rem-- > 0) ++endIndex; | ||||
| 				endIndex += step; | ||||
| 				processors.add( | ||||
| 						new MoveProcessor((Board) board.clone(), moves.subList(beginIndex, endIndex), color, maxDepth)); | ||||
| 						new MoveProcessor((Board) board.clone(), moves.subList(beginIndex, endIndex), color, maxDepth, | ||||
| 								alphaBetaThreshold)); | ||||
| 				beginIndex = endIndex; | ||||
| 			} | ||||
|  | ||||
|   | ||||
| @@ -16,17 +16,19 @@ import dev.kske.chess.board.Piece.Color; | ||||
| public class MoveProcessor implements Callable<ProcessingResult> { | ||||
|  | ||||
| 	private final Board			board; | ||||
| 	private final List<Move>	rootMoves;; | ||||
| 	private final List<Move>	rootMoves; | ||||
| 	private final Color			color; | ||||
| 	private final int			maxDepth; | ||||
| 	private final int			alphaBetaThreshold; | ||||
|  | ||||
| 	private Move bestMove; | ||||
|  | ||||
| 	public MoveProcessor(Board board, List<Move> rootMoves, Color color, int maxDepth) { | ||||
| 	public MoveProcessor(Board board, List<Move> rootMoves, Color color, int maxDepth, int alphaBetaThreshold) { | ||||
| 		this.board		= board; | ||||
| 		this.rootMoves	= rootMoves; | ||||
| 		this.color		= color; | ||||
| 		this.maxDepth	= maxDepth; | ||||
| 		this.alphaBetaThreshold	= alphaBetaThreshold; | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| @@ -43,7 +45,7 @@ public class MoveProcessor implements Callable<ProcessingResult> { | ||||
| 			int		enemyValue		= board.evaluate(color.opposite()); | ||||
| 			int		valueChange		= teamValue - enemyValue; | ||||
|  | ||||
| 			if (depth < maxDepth && valueChange >= 0) | ||||
| 			if (depth < maxDepth && valueChange >= alphaBetaThreshold) | ||||
| 				valueChange -= miniMax(board, board.getMoves(color.opposite()), color.opposite(), depth + 1); | ||||
|  | ||||
| 			if (valueChange > bestValue) { | ||||
|   | ||||
							
								
								
									
										82
									
								
								src/dev/kske/chess/ui/AIConfigDialog.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								src/dev/kske/chess/ui/AIConfigDialog.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,82 @@ | ||||
| package dev.kske.chess.ui; | ||||
|  | ||||
| import java.awt.Dimension; | ||||
|  | ||||
| import javax.swing.JButton; | ||||
| import javax.swing.JDialog; | ||||
| import javax.swing.JLabel; | ||||
| import javax.swing.JSpinner; | ||||
| import javax.swing.SpinnerNumberModel; | ||||
|  | ||||
| /** | ||||
|  * Project: <strong>Chess</strong><br> | ||||
|  * File: <strong>AIConfigDialog.java</strong><br> | ||||
|  * Created: <strong>16.07.2019</strong><br> | ||||
|  * Author: <strong>Kai S. K. Engelbart</strong> | ||||
|  */ | ||||
| public class AIConfigDialog extends JDialog { | ||||
|  | ||||
| 	private static final long serialVersionUID = -8047984368152479992L; | ||||
|  | ||||
| 	private int		maxDepth; | ||||
| 	private int		alphaBetaThreshold; | ||||
| 	private boolean	startGame	= false; | ||||
|  | ||||
| 	public AIConfigDialog() { | ||||
| 		setSize(new Dimension(293, 212)); | ||||
| 		setModal(true); | ||||
| 		setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); | ||||
| 		setTitle("AI Configuration"); | ||||
| 		getContentPane().setLayout(null); | ||||
|  | ||||
| 		JSpinner spAlphaBetaThreshold = new JSpinner(); | ||||
| 		spAlphaBetaThreshold.setBounds(170, 0, 95, 28); | ||||
| 		getContentPane().add(spAlphaBetaThreshold); | ||||
| 		spAlphaBetaThreshold.setModel(new SpinnerNumberModel(-10, -100, 100, 5)); | ||||
|  | ||||
| 		JSpinner spMaxDepth = new JSpinner(); | ||||
| 		spMaxDepth.setBounds(170, 68, 95, 28); | ||||
| 		getContentPane().add(spMaxDepth); | ||||
| 		spMaxDepth.setModel(new SpinnerNumberModel(4, 1, 10, 1)); | ||||
|  | ||||
| 		JLabel lblAlphabetaThreshold = new JLabel("Alpha-Beta Threshold:"); | ||||
| 		lblAlphabetaThreshold.setBounds(16, 68, 119, 28); | ||||
| 		getContentPane().add(lblAlphabetaThreshold); | ||||
|  | ||||
| 		JButton btnOk = new JButton("OK"); | ||||
| 		btnOk.setBounds(16, 137, 84, 28); | ||||
| 		getContentPane().add(btnOk); | ||||
| 		btnOk.addActionListener((evt) -> { | ||||
| 			maxDepth			= ((Integer) spMaxDepth.getValue()).intValue(); | ||||
| 			alphaBetaThreshold	= ((Integer) spAlphaBetaThreshold.getValue()).intValue(); | ||||
| 			startGame			= true; | ||||
| 			dispose(); | ||||
| 		}); | ||||
| 		btnOk.setToolTipText("Start the game"); | ||||
|  | ||||
| 		JButton btnCancel = new JButton("Cancel"); | ||||
| 		btnCancel.setBounds(170, 137, 95, 28); | ||||
| 		getContentPane().add(btnCancel); | ||||
| 		btnCancel.addActionListener((evt) -> dispose()); | ||||
| 		btnCancel.setToolTipText("Cancel the game start"); | ||||
|  | ||||
| 		JLabel lblMaximalRecursionDepth = new JLabel("Maximal Recursion Depth:"); | ||||
| 		lblMaximalRecursionDepth.setBounds(16, 6, 141, 16); | ||||
| 		getContentPane().add(lblMaximalRecursionDepth); | ||||
|  | ||||
| 		setLocationRelativeTo(null); | ||||
| 	} | ||||
|  | ||||
| 	public int getMaxDepth() { return maxDepth; } | ||||
|  | ||||
| 	public void setMaxDepth(int maxDepth) { this.maxDepth = maxDepth; } | ||||
|  | ||||
| 	public int getAlphaBetaThreshold() { return alphaBetaThreshold; } | ||||
|  | ||||
| 	public void setAlphaBetaThreshold(int alphaBetaThreshold) { this.alphaBetaThreshold = alphaBetaThreshold; } | ||||
|  | ||||
| 	public boolean isStartGame() { return startGame; } | ||||
|  | ||||
| 	public void setStartGame(boolean startGame) { this.startGame = startGame; } | ||||
|  | ||||
| } | ||||
| @@ -54,14 +54,19 @@ public class MenuBar extends JMenuBar { | ||||
| 		}); | ||||
|  | ||||
| 		aiMenuItem.addActionListener((evt) -> { | ||||
| 			players.put(Color.WHITE, new NaturalPlayer(board, Color.WHITE, overlayComponent)); | ||||
| 			players.put(Color.BLACK, new AIPlayer(board, Color.BLACK, 5)); | ||||
| 			startGame(); | ||||
| 			AIConfigDialog dialog = new AIConfigDialog(); | ||||
| 			dialog.setVisible(true); | ||||
| 			if (dialog.isStartGame()) { | ||||
| 				players.put(Color.WHITE, new NaturalPlayer(board, Color.WHITE, overlayComponent)); | ||||
| 				players.put(Color.BLACK, | ||||
| 						new AIPlayer(board, Color.BLACK, dialog.getMaxDepth(), dialog.getAlphaBetaThreshold())); | ||||
| 				startGame(); | ||||
| 			} | ||||
| 		}); | ||||
|  | ||||
| 		aiVsAiMenuItem.addActionListener((evt) -> { | ||||
| 			players.put(Color.WHITE, new AIPlayer(board, Color.WHITE, 5)); | ||||
| 			players.put(Color.BLACK, new AIPlayer(board, Color.BLACK, 4)); | ||||
| 			players.put(Color.WHITE, new AIPlayer(board, Color.WHITE, 4, -10)); | ||||
| 			players.put(Color.BLACK, new AIPlayer(board, Color.BLACK, 3, 0)); | ||||
| 			startGame(); | ||||
| 		}); | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user