// Connect4WithMinimax2.java // Created on Thu Aug 7 // In this version, added minimax search. See line 182. // In the previous version, a slightly better (than random) heuristic evaluation function // was added. See evaluateBoard(). // We started with PreTetrisConnect4.java and made as few changes as // possible to get a simple version of minimax running. import javax.swing.Timer; import java.util.*; import javax.swing.*; import java.awt.*; import java.awt.event.*; public class Connect4WithMinimax2 { public static void main(String[] args) { JFrame frame = new JFrame("PreTetris"); MyComponent c = new MyComponent(); frame.getContentPane().add(c); frame.setSize(420,360); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } } class MyComponent extends JComponent implements MouseListener, KeyListener, ActionListener { // instance variables private int pageMargin = 5; private int rows = 6; private int cols = 7; private Color player1 = Color.red; private Color player2 = Color.black; private Color empty = Color.white; private Color background = Color.blue; private Color gameStatusColor = Color.green; private Color[][] boardArray = new Color[rows][cols]; private boolean player1turn = true; private int gameStatus; private static final int GAME_IN_PROGRESS = -1; private static final int TIE_GAME = 0; private static final int COMPUTER_WINS = 1; private static final int HUMAN_WINS = 2; // constructor public MyComponent() { initBoard(); setFocusable(true); addKeyListener(this); addMouseListener(this); int delay = 100; //milliseconds Timer timer = new Timer(delay, null); timer.addActionListener(this); timer.start(); } private void initBoard() { gameStatus = GAME_IN_PROGRESS; player1turn = true; for (int row=0; row bestMove.score))) bestMove = nextMove; } return bestMove; } private ScoredMove doMove(Board b, Move move, boolean player1turn, int depth) { // Make new board Color[][] oldBoardArray = b.getBoardArray(); Color[][] boardArray = new Color[rows][cols]; for (int row=0; row= rows) || (c < 0) || (c >= cols)) return counter; if (boardArray[r][c] != color) return counter; } return 4; } private int eval(Color[][] boardArray, boolean player1turn) { Color c = (player1turn ? player1 : player2); int value = 0; for (int row=0; row= rows) || (c < 0) || (c >= cols)) return false; if (boardArray[r][c] != color) return false; } return true; } private boolean didWin(Color[][] boardArray, Color c) { for (int row=0; row=0; row--) if (boardArray[row][col] == empty) return row; return -1; } ///////////////////////// // ActionListener methods (used for timer) ///////////////////////// public void doTimer() { } public void actionPerformed(ActionEvent e) { doTimer(); repaint(); } ///////////////////////// // KeyListener methods ///////////////////////// public void doUp() { } public void doDown() { } public void doLeft() { } public void doRight() { } public void doSpace() { } public void keyPressed(KeyEvent ke) { switch (ke.getKeyCode()) { case KeyEvent.VK_UP: doUp(); break; case KeyEvent.VK_DOWN: doDown(); break; case KeyEvent.VK_LEFT: doLeft(); break; case KeyEvent.VK_RIGHT: doRight(); break; // default: beep(); } repaint(); } public void keyReleased(KeyEvent ke) { } public void keyTyped(KeyEvent ke) { switch (ke.getKeyChar()) { case ' ': doSpace(); break; default: beep(); } repaint(); } ///////////////////////// // MouseListener methods ///////////////////////// public void mouseClicked(MouseEvent e) { } public void mouseEntered(MouseEvent e) { } public void mouseExited(MouseEvent e) { } public void mousePressed(MouseEvent e) { if (gameStatus != GAME_IN_PROGRESS) { initBoard(); } else { int x = e.getX(); int y = e.getY(); int col = getColumn(x); if (col >= 0) doMove(col); } repaint(); } public void mouseReleased(MouseEvent e) { } private void beep() { Toolkit.getDefaultToolkit().beep(); } private void paintCell(Graphics page, int row, int col) { int width = getWidth(); int height = getHeight(); int innerWidth = width - 2*this.pageMargin; int innerHeight = height - 2*this.pageMargin; int cellWidth = innerWidth/this.cols; int cellHeight = innerHeight/this.rows; int cellLeft = this.pageMargin + cellWidth*col; int cellTop = this.pageMargin + cellHeight*row; int cellMargin = 5; page.setColor(this.boardArray[row][col]); page.fillOval(cellLeft+cellMargin, cellTop+cellMargin, cellWidth-2*cellMargin, cellHeight-2*cellMargin); } private void paintBoard(Graphics page) { for (int row=0; row