Skip to main content
deleted 1603 characters in body; edited tags; edited title
Source Link
200_success
  • 144k
  • 22
  • 188
  • 472

Optimizing a Connect Four Gamegame with minimax AI

    package connect4;

    import java.util.Arrays;
    import java.util.Scanner;
    import java.util.stream.Collectors;
    import java.util.stream.IntStream;

    import javax.swing.*;
    import java.awt.*;
    import java.awt.event.*;
    import java.io.*;
    import java.util.*;

enum Piece
{
   enum Red,
    Blue,
    None
}
class Board extends JButton
{
    public int i, j;
    public Piece piece = Piece.None;
    
    public Board(int i, int j)
    {
        Red,this.i = i;
        Blue,this.j = j;
        NonesetOpaque(true);
        setColor();
    }
    classpublic Boardvoid extendssetPiece(Piece JButtonpiece)
    {
        public int i, j;
        public Piece piece = Piece.None;
        
        public Board(int i, int j)
        {
            this.i = i;
            this.jpiece = j;
            setOpaque(true);piece;
            setColor();
        }
        public void setPiece(Piece piece)
        {
            this.piece = piece;
            setColor();
        }{
        public void setColorswitch(piece)
        {
            switch(piece)
            {
                case Red:
                    setBackground(Color.red);
                    break;
                case Blue:
                    setBackground(Color.blue);
                    break;
                case None:
                    setBackground(Color.white);
                    break;
            }
        }
    }
}

    class Tree  // this is the minmax algorithm
{
    public int value;
    Board[][] Boards; // this is the board
    private ArrayList<Integer> bestMoves;
    Board prev = null;
    int depth;
    static int maxDepth = 4;  // this is the max depth im going down
    
    public Tree(Board[][] Boards, int depth)
    {
        publicthis.Boards int= value;Boards;
        Board[][] Boards; // this is the board
      .bestMoves = privatenew ArrayList<Integer> bestMoves;();
        Board prevthis.depth = null;
        int depth;
        static int maxDepth = 4;  // this is the max depth im.value going= downgetValue();
        
        public Treeif(Board[][]depth Boards,< intmaxDepth depth&& this.value < 100 && this.value > -100 )
        {
            this.BoardsArrayList<Integer> possibilities = Boards;new ArrayList<Integer>();
            this.bestMovesfor(int i = new0; ArrayList<Integer>(i < 7; i++);
            this    if(Boards[i][0].depthpiece === depth;Piece.None)
            this.value = getValue      possibilities.add(i);
            
            iffor(depthint <i maxDepth= &&0; this.valuei < 100 && thispossibilities.value > -100size(); i++)
            {
                ArrayList<Integer> possibilities = new ArrayList<Integer>insertTo(Boards[possibilities.get(i)][0]);
                for(intTree ichild = 0; i <new 7;Tree(Boards, i++depth+1);
                    if(Boards[i][0]prev.piece == setPiece(Piece.None)
                        possibilities.add(i);
                
                forif(int i = 0; i < possibilities.size();== i++0)
                {
                    insertTobestMoves.add(Boards[possibilitiespossibilities.get(i)][0]);
                    Treevalue = child.value;
 = new Tree(Boards, depth+1);
            }
        prev.setPiece        else if(Piece.None);
depth % 2 == 0)
                {
                    if(ivalue ==< 0child.value)
                    {
                        bestMoves.clear();
                        bestMoves.add(possibilities.get(i));
                        value = child.value;
                    }
                    else if(depth % 2 == 0)
                    {
                        if(value < child.value)
                        {
                            bestMoves.clear();
                            bestMoves.add(possibilities.get(i));
                            this.value = child.value;
                        }
                        else if(value == child.value)
                            bestMoves.add(possibilities.get(i));
                    }
                    else if(value == child.value)
                        bestMoves.add(possibilities.get(i));
                }
                else if(depth % 2 == 1)
                {
                    if(value > child.value)
                    {
                        if(value > child.value)
                        {
                            bestMoves.clear();
                            bestMoves.add(possibilities.get(i));
                            this.value = child.value;
                        }
                        else if(value == child.value)
                            bestMoves.add(possibilities.get(i));
                    }
                    else if(value == child.value)
                        bestMoves.add(possibilities.get(i));
                }
            }
            else
            {
                this.value = getValue();
            }
        }
        
        void printBoards() //printboardelse
        {
            this.value = getValue();
        }
    }
    
    void printBoards() //printboard
    {
        for(int j = 0; j < 6; j++)
        {
            for(int i = 0; i < 7; i++)
            {
                forswitch(int i = 0; i < 7; i++Boards[i][j].piece)
                {
                    switch(Boards[i][j].piece)
                    {
                        case Blue: System.out.print("B"); break;
                        case Red: System.out.print("R"); break;
                        default: System.out.print("-"); break;
                    }
                }
                System.out.println();
            }
            System.out.println();
        }
    }
    
    void insertTo(Board Board)  // insert into board
    {
        if(Board.piece != Piece.None)
            return;
        
        void insertTo(Board Board)  // insert into board
        {
            if(Board.piece != Piece.None)
                return;
            
            int i = Board.i;
            int j = Board.j;
            
            while(j < Boards[0].length-1 && Boards[i][j+1].piece == Piece.None)
                j++;
            
            if(depth % 2 == 0)
                Boards[i][j].setPiece(Piece.Red);
            else
                Boards[i][j].setPiece(Piece.Blue);
            prev = Boards[i][j];
        }
        
        public int getXwhile()  // get the player move 
        {
            int randomj =< (int)(MathBoards[0].random()length-1 *&& 100)Boards[i][j+1].piece %== bestMovesPiece.size(None);
            return bestMoves.get(random);
        }j++;
        
        if(depth % 2 == 0)
            Boards[i][j].setPiece(Piece.Red);
        else
            Boards[i][j].setPiece(Piece.Blue);
        prev = Boards[i][j];
    }
    
    public int getX()  // get the player move 
    {
        int random = (int)(Math.random() * 100) % bestMoves.size();
        return bestMoves.get(random);
    }
    
    public int getValue() // get the value of each move
    {
        int value = 0;
        for(int j = 0; j < 6; j++)
        {
            int value = 0;
            for(int ji = 0; ji < 6;7; j++i++)
            {
                forif(int iBoards[i][j].piece != 0; i < 7; i++Piece.None)
                {
                    if(Boards[i][j].piece !=== Piece.NoneRed)
                    {
                        if(Boards[i][j].piece == Piece.Red)
                        {
                            value += possibleConnections(i, j) * (maxDepth - this.depth);
                        }
                        else
                        {
                            value -= possibleConnections(i, j) * (maxDepth - this.depth);
                        }
                    }
                }
            }
            return value;
        }
        return value;
    }
    
    public int possibleConnections(int i, int j)
    {
        int value = 0;
        value += lineOfFour(i, j, -1, -1);
        value += lineOfFour(i, j, -1, 0);
        value += lineOfFour(i, j, -1, 1);
        value += lineOfFour(i, j, 0, -1);
        value += lineOfFour(i, j, 0, 1);
        value += lineOfFour(i, j, 1, -1);
        value += lineOfFour(i, j, 1, 0);
        value += lineOfFour(i, j, 1, 1);
        
        public int possibleConnections(int i, int j)
        {
            int value =return 0;value;
            value += lineOfFour(i, j, -1, -1);}
            value += lineOfFour(i, j, -1, 0);
            valuepublic +=int lineOfFour(i, j, -1, 1);
            value +=int lineOfFour(ix, j,int 0y, -1);
            value +=int lineOfFour(i, j, 0, 1);
            value += lineOfFour(i,int j, 1, -1);
            value += lineOfFour(i, j, 1, 0);{
           int value += lineOfFour(i, j, 1, 1);
           = 1;
            return value;
     Piece color = }Boards[x][y].piece;
        
        public int lineOfFourfor(int x,k int= y,1; intk i,< int4; jk++)
        {
            intif(x+i*k value< =0 1;|| y+j*k < 0 || x+i*k >= Boards.length || y+j*k >= Boards[0].length)
            Piece color = Boards[x][y] return 0;
            if(Boards[x+i*k][y+j*k].piece;piece == color)
                value++;
            for(intelse kif (Boards[x+i*k][y+j*k].piece != 1;Piece.None)
 k < 4; k++)            return 0;
            else
            {
                if(x+i*k < 0 || y+j*k < 0 || x+i*k >= Boards.length || y+j*k >= Boards[0].length)
                    return 0;
                if(Boards[x+i*k][y+j*k].piece == color)
                    value++;
                else if (Boards[x+i*k][y+j*k].piece != Piece.None)
                    return 0;
                else
                {
                    for(int l = y+j*k; l >= 0; l--)
                        if(Boards[x+i*k][l].piece == Piece.None)
                            value--;
                }
            }
            
            if(value == 4) return 100;
            if(value < 0) return 0;
            return value;
        }
        
        if(value == 4) return 100;
        if(value < 0) return 0;
        return value;
    }
}

    public class ConnectFour extends JFrame implements ActionListener
{
    JLabel lblPlayer = new JLabel("Player: ");
    JLabel lblCurrentPlayer = new JLabel("Blue");
    JPanel pnlMenu = new JPanel();
    JPanel pnlBoards = new JPanel();
    JButton btnNewGame2 = new JButton("New Game");
    
    Board[][] Boards = new Board[7][6];
    
    boolean winnerExists = false;
    int currentPlayer = 1;
    boolean AI;
    
    public ConnectFour(boolean AI)
    {
        JLabel lblPlayer = new JLabel("Player: ");
        JLabel lblCurrentPlayer = new JLabel("Blue");
        JPanel pnlMenu = new JPanelsuper();
        JPanel pnlBoards"Four =In newA JPanel(Line");
        JButton btnNewGame2 = new JButtonsetDefaultCloseOperation("New Game"JFrame.EXIT_ON_CLOSE);
        
        Board[][] Boards = new Board[7][6];
        
        boolean winnerExistscurrentPlayer = false;
        (int currentPlayer)(Math.random()*2) =+ 1; 

        booleanthis.AI = AI;
        
        public ConnectFourbtnNewGame2.addActionListener(booleanthis);
 AI       switch(currentPlayer)
        {
            super("Fourcase In1:
 A Line"              lblCurrentPlayer.setForeground(Color.blue);
            setDefaultCloseOperation(JFrame    lblCurrentPlayer.EXIT_ON_CLOSEsetText("Blue");
                break;
            currentPlayercase =2:
                lblCurrentPlayer.setForeground(intColor.red)(Math;
                lblCurrentPlayer.randomsetText()*2"Red");
 + 1;
              break;
        }
    this.AI = AI;  pnlMenu.add(btnNewGame2);
        pnlMenu.add(lblPlayer);
        pnlMenu.add(lblCurrentPlayer);
         
    btnNewGame2    pnlBoards.addActionListenersetLayout(thisnew GridLayout(6, 7));
         
     switch   for(currentPlayerint j = 0; j < 6; j++)
            for(int i = 0; i < 7; i++)
            {
                case 1:
                 Boards[i][j] = new lblCurrentPlayer.setForegroundBoard(Color.blue);
                   i, lblCurrentPlayer.setText("Blue"j);
                    break;
                case 2:
                    lblCurrentPlayerBoards[i][j].setForegroundaddActionListener(Color.redthis);
                    lblCurrentPlayerpnlBoards.setTextadd("Red"Boards[i][j]);
                    break;
            }
            pnlMenu.add(btnNewGame2);
            pnlMenu.add(lblPlayer);
            pnlMenu.add(lblCurrentPlayer);
            
            pnlBoards.setLayout(new GridLayout(6, 7));
            
            for(int j = 0; j < 6; j++)
                for(int i = 0; i < 7; i++)
                {
                    Boards[i][j] = new Board(i, j);
                    Boards[i][j].addActionListener(this);
                    pnlBoards.add(Boards[i][j]);
                }
                
            add(pnlMenu, BorderLayout.NORTH);
            add(pnlBoards, BorderLayout.CENTER);    
            setSize(500, 500);
            setVisible(true);
            
            if(currentPlayer == 2 && AI) insertTo(minimax());
        }
        
        if(currentPlayer == 2 && AI) insertTo(minimax());
    }
    
    public void actionPerformed(ActionEvent ae)
    {
        
        if(ae.getSource() == btnNewGame2)
        {
            
            if(ae.getSource() == btnNewGame2)
            {
                if(JOptionPane.showConfirmDialog(this, "Are you sure you want to quit?", "Confirmation", JOptionPane.YES_NO_OPTION) == 0)
                {
                    dispose();
                    new ConnectFour(true);
                    return;
                }
            }
            else if(!winnerExists)
            {
                Board Board = (Board)ae.getSourcedispose();
                insertTonew ConnectFour(Boardtrue);
                return;
            }
        }
        
        voidelse insertToif(Board Board!winnerExists)
        {
            Board Board = (Board)ae.getSource();
            insertTo(Board);
        }
    }
    
    void insertTo(Board Board)
    {
        if(Board.piece != Piece.None)
            return;
    return;
      
       
  int i = Board.i;
        int ij = Board.i;j;
         
    int    while(j =< BoardBoards[0].j;length-1 && Boards[i][j+1].piece == Piece.None)
            j++;
            
        switch(currentPlayer)
    while(j < Boards[0].length-  {
            case 1:
 && Boards[i][j+1]              Boards[i][j].piecesetPiece(Piece.Blue);
 ==               break;
            case 2:
                Boards[i][j].setPiece(Piece.NoneRed);
                j++;break;
        }
        
        currentPlayer = (currentPlayer % 2) + 1;
        
        if(thereIsAWinner())
        {
            lblPlayer.setText("Winner: ");
            winnerExists = true;
        }
        else
        {
            switch(currentPlayer)
            {
                case 1:
                    Boards[i][j]lblCurrentPlayer.setPiecesetForeground(PieceColor.Blueblue);
                    lblCurrentPlayer.setText("Blue");
                    break;
                case 2:
                    Boards[i][j]lblCurrentPlayer.setPiecesetForeground(PieceColor.Redred);
                    lblCurrentPlayer.setText("Red");
                    break;
            }
            
            currentPlayer = (currentPlayer % 2) + 1;
            
            if(thereIsAWinner())
            {
             currentPlayer == 2 lblPlayer.setText("Winner:&& "AI);
                winnerExists = true;
            }
            else
            {
                switch(currentPlayer)
                {
                    case 1:
                        lblCurrentPlayer.setForeground(Color.blue);
                        lblCurrentPlayer.setText("Blue");
                        break;
                    case 2:
                        lblCurrentPlayer.setForeground(Color.red);
                        lblCurrentPlayer.setText("Red");
                        break;
                }
                
                if(currentPlayer == 2 && AI)
                {
                    insertTo(minimax());
                }
            }
        }
    }
    
    public boolean thereIsAWinner()
  public boolean thereIsAWinner{
        for(int j = 0; j < 6; j++)
        {
            for(int ji = 0; ji < 6;7; j++i++)
            {
                for(int i = 0; i < 7; i++)
                {
                    if(Boards[i][j].piece != Piece.None && connectsToFour(i, j))
                        return true;
                }
            }
            return false;
        }
        
        public boolean connectsToFour(int i, int j)
        {
            if(lineOfFour(i, j, -1, -1))
                return true;false;
            if(lineOfFour(i, j, -1, 0))}
                return true;
          public boolean if(lineOfFourconnectsToFour(i, j, -1, 1))
                return true;
           int if(lineOfFour(i, j, 0, -1))
                return true;
            if(lineOfFour(i,int j, 0, 1))
                return true;{
            if(lineOfFour(i, j, 1, -1))
                return true;
            if(lineOfFour(i, j, 1, 0))
                return true;
            if(lineOfFour(i, j, 1, -1))
                return true;
            return false;
        }
        
        public boolean lineOfFour(int x, int y, int i, int j)
        {
            Piece color = Boards[x][y].piece;
            
            for(int k = 1; k < 4; k++)
            {
                if(x+i*k < 0 || y+j*k < 0 || x+i*k >= Boards.length || y+j*k >= Boards[0].length)
                    return false;
                if(Boards[x+i*k][y+j*k].piece != color)
                    return false;
            }
            return true;
        }if(lineOfFour(i, j, -1, 0))
            return true;
        publicif(lineOfFour(i, Boardj, minimax-1, 1))
            return true;
        if(lineOfFour(i, j, 0, -1))
        {    return true;
        if(lineOfFour(i, j, 0, 1))
  Tree tree = new Tree      return true;
        if(BoardslineOfFour(i, j, 1, -1))
            return true;
        if(lineOfFour(i, j, 1, 0);)
            return Boards[tree.getXtrue;
        if(lineOfFour(i, j, 1, 1)][0];)
            return true;
        return false;
    }
    
    public boolean lineOfFour(int x, int y, int i, int j)
    {
        Piece color = Boards[x][y].piece;
        
        publicfor(int statick void= main(String[]1; argsk < 4; k++)
        {
            newif(x+i*k ConnectFour< 0 || y+j*k < 0 || x+i*k >= Boards.length || y+j*k >= Boards[0].length)
                return false;
            if(falseBoards[x+i*k][y+j*k].piece != color);
                return false;
        }
        return true;
    }
    
    public Board minimax()
    {
        Tree tree = new Tree(Boards, 0);
        return Boards[tree.getX()][0];
    }
    
    public static void main(String[] args)
    {
        new ConnectFour(false);
    }
}

Optimizing a Connect Four Game

    package connect4;

    import java.util.Arrays;
    import java.util.Scanner;
    import java.util.stream.Collectors;
    import java.util.stream.IntStream;

    import javax.swing.*;
    import java.awt.*;
    import java.awt.event.*;
    import java.io.*;
    import java.util.*;

    enum Piece
    {
        Red,
        Blue,
        None
    }
    class Board extends JButton
    {
        public int i, j;
        public Piece piece = Piece.None;
        
        public Board(int i, int j)
        {
            this.i = i;
            this.j = j;
            setOpaque(true);
            setColor();
        }
        public void setPiece(Piece piece)
        {
            this.piece = piece;
            setColor();
        }
        public void setColor()
        {
            switch(piece)
            {
                case Red:
                    setBackground(Color.red);
                    break;
                case Blue:
                    setBackground(Color.blue);
                    break;
                case None:
                    setBackground(Color.white);
                    break;
            }
        }
    }

    class Tree  // this is the minmax algorithm
    {
        public int value;
        Board[][] Boards; // this is the board
        private ArrayList<Integer> bestMoves;
        Board prev = null;
        int depth;
        static int maxDepth = 4;  // this is the max depth im going down
        
        public Tree(Board[][] Boards, int depth)
        {
            this.Boards = Boards;
            this.bestMoves = new ArrayList<Integer>();
            this.depth = depth;
            this.value = getValue();
            
            if(depth < maxDepth && this.value < 100 && this.value > -100 )
            {
                ArrayList<Integer> possibilities = new ArrayList<Integer>();
                for(int i = 0; i < 7; i++)
                    if(Boards[i][0].piece == Piece.None)
                        possibilities.add(i);
                
                for(int i = 0; i < possibilities.size(); i++)
                {
                    insertTo(Boards[possibilities.get(i)][0]);
                    Tree child = new Tree(Boards, depth+1);
                    prev.setPiece(Piece.None);
                    
                    if(i == 0)
                    {
                        bestMoves.add(possibilities.get(i));
                        value = child.value;
                    }
                    else if(depth % 2 == 0)
                    {
                        if(value < child.value)
                        {
                            bestMoves.clear();
                            bestMoves.add(possibilities.get(i));
                            this.value = child.value;
                        }
                        else if(value == child.value)
                            bestMoves.add(possibilities.get(i));
                    }
                    else if(depth % 2 == 1)
                    {
                        if(value > child.value)
                        {
                            bestMoves.clear();
                            bestMoves.add(possibilities.get(i));
                            this.value = child.value;
                        }
                        else if(value == child.value)
                            bestMoves.add(possibilities.get(i));
                    }
                }
            }
            else
            {
                this.value = getValue();
            }
        }
        
        void printBoards() //printboard
        {
            for(int j = 0; j < 6; j++)
            {
                for(int i = 0; i < 7; i++)
                {
                    switch(Boards[i][j].piece)
                    {
                        case Blue: System.out.print("B"); break;
                        case Red: System.out.print("R"); break;
                        default: System.out.print("-"); break;
                    }
                }
                System.out.println();
            }
        }
        
        void insertTo(Board Board)  // insert into board
        {
            if(Board.piece != Piece.None)
                return;
            
            int i = Board.i;
            int j = Board.j;
            
            while(j < Boards[0].length-1 && Boards[i][j+1].piece == Piece.None)
                j++;
            
            if(depth % 2 == 0)
                Boards[i][j].setPiece(Piece.Red);
            else
                Boards[i][j].setPiece(Piece.Blue);
            prev = Boards[i][j];
        }
        
        public int getX()  // get the player move 
        {
            int random = (int)(Math.random() * 100) % bestMoves.size();
            return bestMoves.get(random);
        }
        
        public int getValue() // get the value of each move
        {
            int value = 0;
            for(int j = 0; j < 6; j++)
            {
                for(int i = 0; i < 7; i++)
                {
                    if(Boards[i][j].piece != Piece.None)
                    {
                        if(Boards[i][j].piece == Piece.Red)
                        {
                            value += possibleConnections(i, j) * (maxDepth - this.depth);
                        }
                        else
                        {
                            value -= possibleConnections(i, j) * (maxDepth - this.depth);
                        }
                    }
                }
            }
            return value;
        }
        
        public int possibleConnections(int i, int j)
        {
            int value = 0;
            value += lineOfFour(i, j, -1, -1);
            value += lineOfFour(i, j, -1, 0);
            value += lineOfFour(i, j, -1, 1);
            value += lineOfFour(i, j, 0, -1);
            value += lineOfFour(i, j, 0, 1);
            value += lineOfFour(i, j, 1, -1);
            value += lineOfFour(i, j, 1, 0);
            value += lineOfFour(i, j, 1, 1);
            
            return value;
        }
        
        public int lineOfFour(int x, int y, int i, int j)
        {
            int value = 1;
            Piece color = Boards[x][y].piece;
            
            for(int k = 1; k < 4; k++)
            {
                if(x+i*k < 0 || y+j*k < 0 || x+i*k >= Boards.length || y+j*k >= Boards[0].length)
                    return 0;
                if(Boards[x+i*k][y+j*k].piece == color)
                    value++;
                else if (Boards[x+i*k][y+j*k].piece != Piece.None)
                    return 0;
                else
                {
                    for(int l = y+j*k; l >= 0; l--)
                        if(Boards[x+i*k][l].piece == Piece.None)
                            value--;
                }
            }
            
            if(value == 4) return 100;
            if(value < 0) return 0;
            return value;
        }
    }

    public class ConnectFour extends JFrame implements ActionListener
    {
        JLabel lblPlayer = new JLabel("Player: ");
        JLabel lblCurrentPlayer = new JLabel("Blue");
        JPanel pnlMenu = new JPanel();
        JPanel pnlBoards = new JPanel();
        JButton btnNewGame2 = new JButton("New Game");
        
        Board[][] Boards = new Board[7][6];
        
        boolean winnerExists = false;
        int currentPlayer = 1;
        boolean AI;
        
        public ConnectFour(boolean AI)
        {
            super("Four In A Line");
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            
            currentPlayer = (int)(Math.random()*2) + 1;

            this.AI = AI;
            
            btnNewGame2.addActionListener(this);
            switch(currentPlayer)
            {
                case 1:
                    lblCurrentPlayer.setForeground(Color.blue);
                    lblCurrentPlayer.setText("Blue");
                    break;
                case 2:
                    lblCurrentPlayer.setForeground(Color.red);
                    lblCurrentPlayer.setText("Red");
                    break;
            }
            pnlMenu.add(btnNewGame2);
            pnlMenu.add(lblPlayer);
            pnlMenu.add(lblCurrentPlayer);
            
            pnlBoards.setLayout(new GridLayout(6, 7));
            
            for(int j = 0; j < 6; j++)
                for(int i = 0; i < 7; i++)
                {
                    Boards[i][j] = new Board(i, j);
                    Boards[i][j].addActionListener(this);
                    pnlBoards.add(Boards[i][j]);
                }
                
            add(pnlMenu, BorderLayout.NORTH);
            add(pnlBoards, BorderLayout.CENTER);    
            setSize(500, 500);
            setVisible(true);
            
            if(currentPlayer == 2 && AI) insertTo(minimax());
        }
        
        public void actionPerformed(ActionEvent ae)
        {
            
            if(ae.getSource() == btnNewGame2)
            {
                if(JOptionPane.showConfirmDialog(this, "Are you sure you want to quit?", "Confirmation", JOptionPane.YES_NO_OPTION) == 0)
                {
                    dispose();
                    new ConnectFour(true);
                    return;
                }
            }
            else if(!winnerExists)
            {
                Board Board = (Board)ae.getSource();
                insertTo(Board);
            }
        }
        
        void insertTo(Board Board)
        {
            if(Board.piece != Piece.None)
                return;
            
             int i = Board.i;
            int j = Board.j;
            
            while(j < Boards[0].length-1 && Boards[i][j+1].piece == Piece.None)
                j++;
                
            switch(currentPlayer)
            {
                case 1:
                    Boards[i][j].setPiece(Piece.Blue);
                    break;
                case 2:
                    Boards[i][j].setPiece(Piece.Red);
                    break;
            }
            
            currentPlayer = (currentPlayer % 2) + 1;
            
            if(thereIsAWinner())
            {
                lblPlayer.setText("Winner: ");
                winnerExists = true;
            }
            else
            {
                switch(currentPlayer)
                {
                    case 1:
                        lblCurrentPlayer.setForeground(Color.blue);
                        lblCurrentPlayer.setText("Blue");
                        break;
                    case 2:
                        lblCurrentPlayer.setForeground(Color.red);
                        lblCurrentPlayer.setText("Red");
                        break;
                }
                
                if(currentPlayer == 2 && AI)
                {
                    insertTo(minimax());
                }
            }
        }
        
        public boolean thereIsAWinner()
        {
            for(int j = 0; j < 6; j++)
            {
                for(int i = 0; i < 7; i++)
                {
                    if(Boards[i][j].piece != Piece.None && connectsToFour(i, j))
                        return true;
                }
            }
            return false;
        }
        
        public boolean connectsToFour(int i, int j)
        {
            if(lineOfFour(i, j, -1, -1))
                return true;
            if(lineOfFour(i, j, -1, 0))
                return true;
            if(lineOfFour(i, j, -1, 1))
                return true;
            if(lineOfFour(i, j, 0, -1))
                return true;
            if(lineOfFour(i, j, 0, 1))
                return true;
            if(lineOfFour(i, j, 1, -1))
                return true;
            if(lineOfFour(i, j, 1, 0))
                return true;
            if(lineOfFour(i, j, 1, 1))
                return true;
            return false;
        }
        
        public boolean lineOfFour(int x, int y, int i, int j)
        {
            Piece color = Boards[x][y].piece;
            
            for(int k = 1; k < 4; k++)
            {
                if(x+i*k < 0 || y+j*k < 0 || x+i*k >= Boards.length || y+j*k >= Boards[0].length)
                    return false;
                if(Boards[x+i*k][y+j*k].piece != color)
                    return false;
            }
            return true;
        }
        
        public Board minimax()
        {
            Tree tree = new Tree(Boards, 0);
            return Boards[tree.getX()][0];
        }
        
        public static void main(String[] args)
        {
            new ConnectFour(false);
        }
    }

Connect Four game with minimax AI

package connect4;

import java.util.Arrays;
import java.util.Scanner;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.*;

enum Piece
{
    Red,
    Blue,
    None
}
class Board extends JButton
{
    public int i, j;
    public Piece piece = Piece.None;
    
    public Board(int i, int j)
    {
        this.i = i;
        this.j = j;
        setOpaque(true);
        setColor();
    }
    public void setPiece(Piece piece)
    {
        this.piece = piece;
        setColor();
    }
    public void setColor()
    {
        switch(piece)
        {
            case Red:
                setBackground(Color.red);
                break;
            case Blue:
                setBackground(Color.blue);
                break;
            case None:
                setBackground(Color.white);
                break;
        }
    }
}

class Tree  // this is the minmax algorithm
{
    public int value;
    Board[][] Boards; // this is the board
    private ArrayList<Integer> bestMoves;
    Board prev = null;
    int depth;
    static int maxDepth = 4;  // this is the max depth im going down
    
    public Tree(Board[][] Boards, int depth)
    {
        this.Boards = Boards;
        this.bestMoves = new ArrayList<Integer>();
        this.depth = depth;
        this.value = getValue();
        
        if(depth < maxDepth && this.value < 100 && this.value > -100 )
        {
            ArrayList<Integer> possibilities = new ArrayList<Integer>();
            for(int i = 0; i < 7; i++)
                if(Boards[i][0].piece == Piece.None)
                    possibilities.add(i);
            
            for(int i = 0; i < possibilities.size(); i++)
            {
                insertTo(Boards[possibilities.get(i)][0]);
                Tree child = new Tree(Boards, depth+1);
                prev.setPiece(Piece.None);
                
                if(i == 0)
                {
                    bestMoves.add(possibilities.get(i));
                    value = child.value;
                }
                else if(depth % 2 == 0)
                {
                    if(value < child.value)
                    {
                        bestMoves.clear();
                        bestMoves.add(possibilities.get(i));
                        this.value = child.value;
                    }
                    else if(value == child.value)
                        bestMoves.add(possibilities.get(i));
                }
                else if(depth % 2 == 1)
                {
                    if(value > child.value)
                    {
                        bestMoves.clear();
                        bestMoves.add(possibilities.get(i));
                        this.value = child.value;
                    }
                    else if(value == child.value)
                        bestMoves.add(possibilities.get(i));
                }
            }
        }
        else
        {
            this.value = getValue();
        }
    }
    
    void printBoards() //printboard
    {
        for(int j = 0; j < 6; j++)
        {
            for(int i = 0; i < 7; i++)
            {
                switch(Boards[i][j].piece)
                {
                    case Blue: System.out.print("B"); break;
                    case Red: System.out.print("R"); break;
                    default: System.out.print("-"); break;
                }
            }
            System.out.println();
        }
    }
    
    void insertTo(Board Board)  // insert into board
    {
        if(Board.piece != Piece.None)
            return;
        
        int i = Board.i;
        int j = Board.j;
        
        while(j < Boards[0].length-1 && Boards[i][j+1].piece == Piece.None)
            j++;
        
        if(depth % 2 == 0)
            Boards[i][j].setPiece(Piece.Red);
        else
            Boards[i][j].setPiece(Piece.Blue);
        prev = Boards[i][j];
    }
    
    public int getX()  // get the player move 
    {
        int random = (int)(Math.random() * 100) % bestMoves.size();
        return bestMoves.get(random);
    }
    
    public int getValue() // get the value of each move
    {
        int value = 0;
        for(int j = 0; j < 6; j++)
        {
            for(int i = 0; i < 7; i++)
            {
                if(Boards[i][j].piece != Piece.None)
                {
                    if(Boards[i][j].piece == Piece.Red)
                    {
                        value += possibleConnections(i, j) * (maxDepth - this.depth);
                    }
                    else
                    {
                        value -= possibleConnections(i, j) * (maxDepth - this.depth);
                    }
                }
            }
        }
        return value;
    }
    
    public int possibleConnections(int i, int j)
    {
        int value = 0;
        value += lineOfFour(i, j, -1, -1);
        value += lineOfFour(i, j, -1, 0);
        value += lineOfFour(i, j, -1, 1);
        value += lineOfFour(i, j, 0, -1);
        value += lineOfFour(i, j, 0, 1);
        value += lineOfFour(i, j, 1, -1);
        value += lineOfFour(i, j, 1, 0);
        value += lineOfFour(i, j, 1, 1);
        
        return value;
    }
    
    public int lineOfFour(int x, int y, int i, int j)
    {
        int value = 1;
        Piece color = Boards[x][y].piece;
        
        for(int k = 1; k < 4; k++)
        {
            if(x+i*k < 0 || y+j*k < 0 || x+i*k >= Boards.length || y+j*k >= Boards[0].length)
                return 0;
            if(Boards[x+i*k][y+j*k].piece == color)
                value++;
            else if (Boards[x+i*k][y+j*k].piece != Piece.None)
                return 0;
            else
            {
                for(int l = y+j*k; l >= 0; l--)
                    if(Boards[x+i*k][l].piece == Piece.None)
                        value--;
            }
        }
        
        if(value == 4) return 100;
        if(value < 0) return 0;
        return value;
    }
}

public class ConnectFour extends JFrame implements ActionListener
{
    JLabel lblPlayer = new JLabel("Player: ");
    JLabel lblCurrentPlayer = new JLabel("Blue");
    JPanel pnlMenu = new JPanel();
    JPanel pnlBoards = new JPanel();
    JButton btnNewGame2 = new JButton("New Game");
    
    Board[][] Boards = new Board[7][6];
    
    boolean winnerExists = false;
    int currentPlayer = 1;
    boolean AI;
    
    public ConnectFour(boolean AI)
    {
        super("Four In A Line");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        currentPlayer = (int)(Math.random()*2) + 1; 

        this.AI = AI;
        
        btnNewGame2.addActionListener(this);
        switch(currentPlayer)
        {
            case 1:
                lblCurrentPlayer.setForeground(Color.blue);
                lblCurrentPlayer.setText("Blue");
                break;
            case 2:
                lblCurrentPlayer.setForeground(Color.red);
                lblCurrentPlayer.setText("Red");
                break;
        }
        pnlMenu.add(btnNewGame2);
        pnlMenu.add(lblPlayer);
        pnlMenu.add(lblCurrentPlayer);
         
        pnlBoards.setLayout(new GridLayout(6, 7));
         
        for(int j = 0; j < 6; j++)
            for(int i = 0; i < 7; i++)
            {
                Boards[i][j] = new Board(i, j);
                Boards[i][j].addActionListener(this);
                pnlBoards.add(Boards[i][j]);
            }
            
        add(pnlMenu, BorderLayout.NORTH);
        add(pnlBoards, BorderLayout.CENTER);    
        setSize(500, 500);
        setVisible(true);
        
        if(currentPlayer == 2 && AI) insertTo(minimax());
    }
    
    public void actionPerformed(ActionEvent ae)
    {
        
        if(ae.getSource() == btnNewGame2)
        {
            if(JOptionPane.showConfirmDialog(this, "Are you sure you want to quit?", "Confirmation", JOptionPane.YES_NO_OPTION) == 0)
            {
                dispose();
                new ConnectFour(true);
                return;
            }
        }
        else if(!winnerExists)
        {
            Board Board = (Board)ae.getSource();
            insertTo(Board);
        }
    }
    
    void insertTo(Board Board)
    {
        if(Board.piece != Piece.None)
            return;
         
        int i = Board.i;
        int j = Board.j;
         
        while(j < Boards[0].length-1 && Boards[i][j+1].piece == Piece.None)
            j++;
            
        switch(currentPlayer)
        {
            case 1:
                Boards[i][j].setPiece(Piece.Blue);
                break;
            case 2:
                Boards[i][j].setPiece(Piece.Red);
                break;
        }
        
        currentPlayer = (currentPlayer % 2) + 1;
        
        if(thereIsAWinner())
        {
            lblPlayer.setText("Winner: ");
            winnerExists = true;
        }
        else
        {
            switch(currentPlayer)
            {
                case 1:
                    lblCurrentPlayer.setForeground(Color.blue);
                    lblCurrentPlayer.setText("Blue");
                    break;
                case 2:
                    lblCurrentPlayer.setForeground(Color.red);
                    lblCurrentPlayer.setText("Red");
                    break;
            }
            
            if(currentPlayer == 2 && AI)
            {
                insertTo(minimax());
            }
        }
    }
    
    public boolean thereIsAWinner()
    {
        for(int j = 0; j < 6; j++)
        {
            for(int i = 0; i < 7; i++)
            {
                if(Boards[i][j].piece != Piece.None && connectsToFour(i, j))
                    return true;
            }
        }
        return false;
    }
    
    public boolean connectsToFour(int i, int j)
    {
        if(lineOfFour(i, j, -1, -1))
            return true;
        if(lineOfFour(i, j, -1, 0))
            return true;
        if(lineOfFour(i, j, -1, 1))
            return true;
        if(lineOfFour(i, j, 0, -1))
            return true;
        if(lineOfFour(i, j, 0, 1))
            return true;
        if(lineOfFour(i, j, 1, -1))
            return true;
        if(lineOfFour(i, j, 1, 0))
            return true;
        if(lineOfFour(i, j, 1, 1))
            return true;
        return false;
    }
    
    public boolean lineOfFour(int x, int y, int i, int j)
    {
        Piece color = Boards[x][y].piece;
        
        for(int k = 1; k < 4; k++)
        {
            if(x+i*k < 0 || y+j*k < 0 || x+i*k >= Boards.length || y+j*k >= Boards[0].length)
                return false;
            if(Boards[x+i*k][y+j*k].piece != color)
                return false;
        }
        return true;
    }
    
    public Board minimax()
    {
        Tree tree = new Tree(Boards, 0);
        return Boards[tree.getX()][0];
    }
    
    public static void main(String[] args)
    {
        new ConnectFour(false);
    }
}
Typos
Source Link
forsvarir
  • 11.7k
  • 6
  • 38
  • 71

I have created a connect four game between a bot and a player. It was quite a bit of a challenge since iI wasn't too fond of the minmax algorithm until now. I know theresthere's always room for imporvementimprovement and iI am wondering if someone can tell me if my code is up to standards, i.e. better solutions etc. Please feel free to scrutinize my code.

I have created a connect four game between a bot and a player. It was quite a bit of a challenge since i wasn't too fond of the minmax algorithm until now. I know theres always room for imporvement and i am wondering if someone can tell me if my code is up to standards, i.e. better solutions etc. Please feel free to scrutinize my code.

I have created a connect four game between a bot and a player. It was quite a bit of a challenge since I wasn't too fond of the minmax algorithm until now. I know there's always room for improvement and I am wondering if someone can tell me if my code is up to standards, i.e. better solutions etc. Please feel free to scrutinize my code.

Source Link

Optimizing a Connect Four Game

I have created a connect four game between a bot and a player. It was quite a bit of a challenge since i wasn't too fond of the minmax algorithm until now. I know theres always room for imporvement and i am wondering if someone can tell me if my code is up to standards, i.e. better solutions etc. Please feel free to scrutinize my code.

    package connect4;

    import java.util.Arrays;
    import java.util.Scanner;
    import java.util.stream.Collectors;
    import java.util.stream.IntStream;

    import javax.swing.*;
    import java.awt.*;
    import java.awt.event.*;
    import java.io.*;
    import java.util.*;

    enum Piece
    {
        Red,
        Blue,
        None
    }
    class Board extends JButton
    {
        public int i, j;
        public Piece piece = Piece.None;
        
        public Board(int i, int j)
        {
            this.i = i;
            this.j = j;
            setOpaque(true);
            setColor();
        }
        public void setPiece(Piece piece)
        {
            this.piece = piece;
            setColor();
        }
        public void setColor()
        {
            switch(piece)
            {
                case Red:
                    setBackground(Color.red);
                    break;
                case Blue:
                    setBackground(Color.blue);
                    break;
                case None:
                    setBackground(Color.white);
                    break;
            }
        }
    }

    class Tree  // this is the minmax algorithm
    {
        public int value;
        Board[][] Boards; // this is the board
        private ArrayList<Integer> bestMoves;
        Board prev = null;
        int depth;
        static int maxDepth = 4;  // this is the max depth im going down
        
        public Tree(Board[][] Boards, int depth)
        {
            this.Boards = Boards;
            this.bestMoves = new ArrayList<Integer>();
            this.depth = depth;
            this.value = getValue();
            
            if(depth < maxDepth && this.value < 100 && this.value > -100 )
            {
                ArrayList<Integer> possibilities = new ArrayList<Integer>();
                for(int i = 0; i < 7; i++)
                    if(Boards[i][0].piece == Piece.None)
                        possibilities.add(i);
                
                for(int i = 0; i < possibilities.size(); i++)
                {
                    insertTo(Boards[possibilities.get(i)][0]);
                    Tree child = new Tree(Boards, depth+1);
                    prev.setPiece(Piece.None);
                    
                    if(i == 0)
                    {
                        bestMoves.add(possibilities.get(i));
                        value = child.value;
                    }
                    else if(depth % 2 == 0)
                    {
                        if(value < child.value)
                        {
                            bestMoves.clear();
                            bestMoves.add(possibilities.get(i));
                            this.value = child.value;
                        }
                        else if(value == child.value)
                            bestMoves.add(possibilities.get(i));
                    }
                    else if(depth % 2 == 1)
                    {
                        if(value > child.value)
                        {
                            bestMoves.clear();
                            bestMoves.add(possibilities.get(i));
                            this.value = child.value;
                        }
                        else if(value == child.value)
                            bestMoves.add(possibilities.get(i));
                    }
                }
            }
            else
            {
                this.value = getValue();
            }
        }
        
        void printBoards() //printboard
        {
            for(int j = 0; j < 6; j++)
            {
                for(int i = 0; i < 7; i++)
                {
                    switch(Boards[i][j].piece)
                    {
                        case Blue: System.out.print("B"); break;
                        case Red: System.out.print("R"); break;
                        default: System.out.print("-"); break;
                    }
                }
                System.out.println();
            }
        }
        
        void insertTo(Board Board)  // insert into board
        {
            if(Board.piece != Piece.None)
                return;
            
            int i = Board.i;
            int j = Board.j;
            
            while(j < Boards[0].length-1 && Boards[i][j+1].piece == Piece.None)
                j++;
            
            if(depth % 2 == 0)
                Boards[i][j].setPiece(Piece.Red);
            else
                Boards[i][j].setPiece(Piece.Blue);
            prev = Boards[i][j];
        }
        
        public int getX()  // get the player move 
        {
            int random = (int)(Math.random() * 100) % bestMoves.size();
            return bestMoves.get(random);
        }
        
        public int getValue() // get the value of each move
        {
            int value = 0;
            for(int j = 0; j < 6; j++)
            {
                for(int i = 0; i < 7; i++)
                {
                    if(Boards[i][j].piece != Piece.None)
                    {
                        if(Boards[i][j].piece == Piece.Red)
                        {
                            value += possibleConnections(i, j) * (maxDepth - this.depth);
                        }
                        else
                        {
                            value -= possibleConnections(i, j) * (maxDepth - this.depth);
                        }
                    }
                }
            }
            return value;
        }
        
        public int possibleConnections(int i, int j)
        {
            int value = 0;
            value += lineOfFour(i, j, -1, -1);
            value += lineOfFour(i, j, -1, 0);
            value += lineOfFour(i, j, -1, 1);
            value += lineOfFour(i, j, 0, -1);
            value += lineOfFour(i, j, 0, 1);
            value += lineOfFour(i, j, 1, -1);
            value += lineOfFour(i, j, 1, 0);
            value += lineOfFour(i, j, 1, 1);
            
            return value;
        }
        
        public int lineOfFour(int x, int y, int i, int j)
        {
            int value = 1;
            Piece color = Boards[x][y].piece;
            
            for(int k = 1; k < 4; k++)
            {
                if(x+i*k < 0 || y+j*k < 0 || x+i*k >= Boards.length || y+j*k >= Boards[0].length)
                    return 0;
                if(Boards[x+i*k][y+j*k].piece == color)
                    value++;
                else if (Boards[x+i*k][y+j*k].piece != Piece.None)
                    return 0;
                else
                {
                    for(int l = y+j*k; l >= 0; l--)
                        if(Boards[x+i*k][l].piece == Piece.None)
                            value--;
                }
            }
            
            if(value == 4) return 100;
            if(value < 0) return 0;
            return value;
        }
    }

    public class ConnectFour extends JFrame implements ActionListener
    {
        JLabel lblPlayer = new JLabel("Player: ");
        JLabel lblCurrentPlayer = new JLabel("Blue");
        JPanel pnlMenu = new JPanel();
        JPanel pnlBoards = new JPanel();
        JButton btnNewGame2 = new JButton("New Game");
        
        Board[][] Boards = new Board[7][6];
        
        boolean winnerExists = false;
        int currentPlayer = 1;
        boolean AI;
        
        public ConnectFour(boolean AI)
        {
            super("Four In A Line");
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            
            currentPlayer = (int)(Math.random()*2) + 1;

            this.AI = AI;
            
            btnNewGame2.addActionListener(this);
            switch(currentPlayer)
            {
                case 1:
                    lblCurrentPlayer.setForeground(Color.blue);
                    lblCurrentPlayer.setText("Blue");
                    break;
                case 2:
                    lblCurrentPlayer.setForeground(Color.red);
                    lblCurrentPlayer.setText("Red");
                    break;
            }
            pnlMenu.add(btnNewGame2);
            pnlMenu.add(lblPlayer);
            pnlMenu.add(lblCurrentPlayer);
            
            pnlBoards.setLayout(new GridLayout(6, 7));
            
            for(int j = 0; j < 6; j++)
                for(int i = 0; i < 7; i++)
                {
                    Boards[i][j] = new Board(i, j);
                    Boards[i][j].addActionListener(this);
                    pnlBoards.add(Boards[i][j]);
                }
                
            add(pnlMenu, BorderLayout.NORTH);
            add(pnlBoards, BorderLayout.CENTER);    
            setSize(500, 500);
            setVisible(true);
            
            if(currentPlayer == 2 && AI) insertTo(minimax());
        }
        
        public void actionPerformed(ActionEvent ae)
        {
            
            if(ae.getSource() == btnNewGame2)
            {
                if(JOptionPane.showConfirmDialog(this, "Are you sure you want to quit?", "Confirmation", JOptionPane.YES_NO_OPTION) == 0)
                {
                    dispose();
                    new ConnectFour(true);
                    return;
                }
            }
            else if(!winnerExists)
            {
                Board Board = (Board)ae.getSource();
                insertTo(Board);
            }
        }
        
        void insertTo(Board Board)
        {
            if(Board.piece != Piece.None)
                return;
            
            int i = Board.i;
            int j = Board.j;
            
            while(j < Boards[0].length-1 && Boards[i][j+1].piece == Piece.None)
                j++;
                
            switch(currentPlayer)
            {
                case 1:
                    Boards[i][j].setPiece(Piece.Blue);
                    break;
                case 2:
                    Boards[i][j].setPiece(Piece.Red);
                    break;
            }
            
            currentPlayer = (currentPlayer % 2) + 1;
            
            if(thereIsAWinner())
            {
                lblPlayer.setText("Winner: ");
                winnerExists = true;
            }
            else
            {
                switch(currentPlayer)
                {
                    case 1:
                        lblCurrentPlayer.setForeground(Color.blue);
                        lblCurrentPlayer.setText("Blue");
                        break;
                    case 2:
                        lblCurrentPlayer.setForeground(Color.red);
                        lblCurrentPlayer.setText("Red");
                        break;
                }
                
                if(currentPlayer == 2 && AI)
                {
                    insertTo(minimax());
                }
            }
        }
        
        public boolean thereIsAWinner()
        {
            for(int j = 0; j < 6; j++)
            {
                for(int i = 0; i < 7; i++)
                {
                    if(Boards[i][j].piece != Piece.None && connectsToFour(i, j))
                        return true;
                }
            }
            return false;
        }
        
        public boolean connectsToFour(int i, int j)
        {
            if(lineOfFour(i, j, -1, -1))
                return true;
            if(lineOfFour(i, j, -1, 0))
                return true;
            if(lineOfFour(i, j, -1, 1))
                return true;
            if(lineOfFour(i, j, 0, -1))
                return true;
            if(lineOfFour(i, j, 0, 1))
                return true;
            if(lineOfFour(i, j, 1, -1))
                return true;
            if(lineOfFour(i, j, 1, 0))
                return true;
            if(lineOfFour(i, j, 1, 1))
                return true;
            return false;
        }
        
        public boolean lineOfFour(int x, int y, int i, int j)
        {
            Piece color = Boards[x][y].piece;
            
            for(int k = 1; k < 4; k++)
            {
                if(x+i*k < 0 || y+j*k < 0 || x+i*k >= Boards.length || y+j*k >= Boards[0].length)
                    return false;
                if(Boards[x+i*k][y+j*k].piece != color)
                    return false;
            }
            return true;
        }
        
        public Board minimax()
        {
            Tree tree = new Tree(Boards, 0);
            return Boards[tree.getX()][0];
        }
        
        public static void main(String[] args)
        {
            new ConnectFour(false);
        }
    }