Connect 4 Game
<< LizardSplat | OtherProjectsTrailIndex | Gift Interface >>
A working copy is at http://www.mathorama.com/Connect4.html Here is the starter code
Connect4GameApplet.java
package connect4; import java.applet.Applet; import java.awt.Color; import java.awt.Graphics; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; @SuppressWarnings("serial") public class Connect4GameApplet extends Applet implements MouseListener { Board board; Player[] player; String message="Turn No. 1 Red's Move"; String comment="No Comment"; String score="New Game"; int turn=1; private final int left=20; private final int top=80; private final int boxSize=60; public void init() { player = new Player[2]; player[0]=new Player("Red", Color.RED); player[0].setRobot(false); player[1]= new Player("Black", Color.BLACK); player[1].setRobot(false); board= new Board(); board.setCellSize(boxSize); addMouseListener(this); } public void paint(Graphics g) { g.setColor(Color.white); g.fillRect(0, 0, 500, 500); g.setColor(Color.black); g.drawString("Connect 4 Game", 20, 20); g.setColor(Color.blue); g.drawString("click to see next turn", 20, 40); g.drawString(message , left, 65); g.drawString(comment , left, 490); g.drawString(score , left, 470); board.draw(g, left, top); } public boolean gameOver(){ return (board.legalMoves().size()==0 || board.hMax()>3 || board.vMax()>3 || board.dMax()>3); } public void mouseClicked(MouseEvent e) {} public void mouseEntered(MouseEvent e) {} public void mouseExited(MouseEvent e) {} public void mousePressed(MouseEvent e) { } public void mouseReleased(MouseEvent e) { int click=e.getX(); click-=left; int selectedCol=click/boxSize; if (selectedCol>6) selectedCol=6; if (!gameOver()){ turn++; message="Turn No. "+turn+" "; Color c=player[turn%2].getColor(); if (player[turn%2].isRobot()){ selectedCol=player[turn%2].getMove(board.legalMoves()); board.add(new Piece(c, board.columnTop(selectedCol) ,selectedCol)); }else{ if(board.legalMoves().contains(selectedCol)){ board.add(new Piece(c, board.columnTop(selectedCol) ,selectedCol)); }else{ message+="Illegal move - still "; turn--; } } if (gameOver()) message=player[turn%2].getName()+" WON!"; else message+=player[(turn-1)%2].getName()+"'s move"; } else{ message="Game Over"; } comment="Last Selected Column: "+selectedCol+" (top is "+board.columnTop(selectedCol); comment+= ") legal Moves: "+board.legalMoves(); score="horiz Max="+board.hMax()+" vert max="+board.vMax()+" diag max="+board.dMax(); repaint(); } }
Player.java
package connect4; import java.awt.Color; import java.util.ArrayList; public class Player { private String name; private boolean robot; private Color color; public Player(){ setName("Player Name"); setRobot(true); setColor(Color.RED); } public Player(String theName){ this(); setName(theName); } public Player(boolean isRobot){ this(); setRobot(isRobot); } public Player(String theName, boolean isRobot){ this(); setName(theName); setRobot(isRobot); } public Player(String theName, Color c){ this(); setName(theName); setColor(c); } /** * @param name the name to set */ public void setName(String name) { this.name = name; } /** * @return the name */ public String getName() { return name; } /** * @param robot define whether the player is a robot or not */ public void setRobot(boolean robot) { this.robot = robot; } /** * @return is the player is a robot or not. */ public boolean isRobot() { return robot; } public int getMove(ArrayList<Integer> legalMoves){ if (robot){ int choice=randomInt(0,legalMoves.size()); return legalMoves.get(choice); } return -1; } private int randomInt(int min, int max) { return min+(int)((max-min)*Math.random()); } /** * @param color the color to set */ public void setColor(Color color) { this.color = color; } /** * @return the color */ public Color getColor() { return color; } }
Piece.java
package connect4; import java.awt.Color; public class Piece { private Color color; private int row; private int col; public Piece(){ setColor(Color.RED); setRow(-1); setCol(-1); } public Piece(Color color, int r, int c){ this(); setColor(color); setRow(r); setCol(c); } /** * @param color the color to set */ public void setColor(Color color) { this.color = color; } /** * @return the color */ public Color getColor() { return color; } /** * @param row the row to set */ public void setRow(int row) { this.row = row; } /** * @return the row */ public int getRow() { return row; } /** * @param col the col to set */ public void setCol(int col) { this.col = col; } /** * @return the col */ public int getCol() { return col; } public void setLocation(int r, int c){ setRow(r); setCol(c); } public String toString(){ String theColor="Black"; if (color.equals(Color.RED)) theColor=" Red "; return "Piece[row = "+row+" col = "+col+" ("+theColor+")]"; } public boolean equals(Piece p){ return p.getColor().equals(color); } }
Board.java
package connect4; import java.awt.Color; import java.awt.Graphics; import java.util.ArrayList; public class Board { private static final int rows=6; private static final int cols=7; private int cellSize; private Piece [][] grid; public Board(){ grid = new Piece[rows][cols]; setCellSize(100); } public static int getRows() { return rows; } public static int getCols() { return cols; } public Piece [][] getGrid() { return grid; } /** * columnTop returns the index of the row of the * next available cell of the column * or -1 if the column is full * @param c the column to check * @return the row index of the columnTop */ public int columnTop(int c){ if (grid[0][c]!=null) return -1; int result=rows-1; //start at the bottom index while(grid [result][c]!=null && result>0) result--; return result; } /** * legalMoves * @return ArrayList<Integer> of open columns */ public ArrayList<Integer> legalMoves(){ ArrayList<Integer> moves = new ArrayList<Integer>(); for(int i=0;i<cols; i++) if(columnTop(i)>-1) moves.add(i); return moves; } /** * added a peice to the board * @param p the Peice * @return if sucessful */ public boolean add(Piece p){ int r=p.getRow(); int c=p.getCol(); if (r<0 || c<0 ) return false; if (grid[r][c]!=null) return false; grid[r][c]=p; return true; } public void draw(Graphics g, int left, int top){ g.setColor(Color.BLACK); for (int r=0; r<rows; r++) for (int c=0; c<cols; c++){ g.setColor(Color.BLACK); g.drawRect(left+c*cellSize, top+r*cellSize, cellSize, cellSize); if (grid[r][c]!=null){ Piece p=grid[r][c]; g.setColor(p.getColor()); g.fillOval(left+c*cellSize, top+r*cellSize, cellSize, cellSize); } } } public void setCellSize(int cellSize) { this.cellSize = cellSize; } public int getCellSize() { return cellSize; } public int hMax(){ int result=0; for (int row=0;row<rows;row++){ int count=1; for (int col=1;col<cols;col++){ Piece left=grid[row][col-1]; Piece right=grid[row][col]; if (left !=null && right!=null && left.equals(right)){ count++; }else{ if (count>result) result=count; count=1; } } if (count>result) result=count; } return result; } public int vMax(){ int result=0; for (int col=0;col<cols;col++){ int count=1; for (int row=1;row<rows;row++){ Piece top=grid[row-1][col]; Piece bottom=grid[row][col]; if (top !=null && bottom!=null && top.equals(bottom)){ count++; }else{ if (count>result) result=count; count=1; } } if (count>result) result=count; } return result; } public Piece getGrid(int hash){ int r=hash/7; int c=hash%7; return grid[r][c]; } public int dMax(){ int result=0; for (int n=1;n<6;n++){ int count=1; for (int i=n;i<n*7;i+=6){ Piece left=getGrid(i); Piece right=getGrid(i+6); if (left !=null && right!=null && left.equals(right)){ count++; }else{ if (count>result) result=count; count=1; } } if (count>result) result=count; } for (int n=36;n<41;n++){ int count=1; for (int i=n;i>(n-35)*7;i-=6){ Piece left=getGrid(i); Piece right=getGrid(i-6); if (left !=null && right!=null && left.equals(right)){ count++; }else{ if (count>result) result=count; count=1; } } if (count>result) result=count; } for (int n=1;n<6;n++){ int count=1; for (int i=n;i<48-n*7;i+=8){ Piece left=getGrid(i); Piece right=getGrid(i+8); if (left !=null && right!=null && left.equals(right)){ count++; }else{ if (count>result) result=count; count=1; } } if (count>result) result=count; } for (int n=36;n<40;n++){ int count=1; for (int i=n;i>(40-n)*7;i-=8){ Piece left=getGrid(i); Piece right=getGrid(i-8); if (left !=null && right!=null && left.equals(right)){ count++; }else{ if (count>result) result=count; count=1; } } if (count>result) result=count; } return result; } }
Connect4App.java
This is an application version that uses key presses rather than mouse clicks:
import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import javax.swing.JFrame; import javax.swing.JPanel; public class Connect4App extends JPanel implements KeyListener { public static final int WIDTH=500; public static final int HEIGHT=600; private static final int LEFT=40; private static final int TOP=80; private static final int BOX_SIZE=60; private Font titleFont, regularFont; private Board board; private Player[] player; private String message; private String comment; private String score; int turn=1; public Connect4App() { //initialize variables here... titleFont = new Font("Roman", Font.BOLD, 18); regularFont = new Font("Helvetica", Font.PLAIN, 12); // newGame(); } public void newGame() { player = new Player[2]; player[0]=new Player("Red", Color.RED); player[0].setRobot(false); player[1]= new Player("Black", Color.BLACK); player[1].setRobot(true); board= new Board(); board.setCellSize(BOX_SIZE); message="Turn No. 1 Red's Move"; comment="No Comment"; score="New Game"; } public boolean gameOver(){ return (board.legalMoves().size()==0 || board.hMax()>3 || board.vMax()>3 || board.dMax()>3); } public static void main(String[] args) { Connect4App app= new Connect4App(); JFrame window = new JFrame("My Generic Application"); window.setSize(WIDTH, HEIGHT); window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); window.getContentPane().add(app); window.addKeyListener(app); //window.pack(); window.setVisible(true); } public void paintComponent(Graphics g){ super.paintComponent(g); g.setColor(Color.WHITE); g.fillRect(0, 0, getWidth(),getHeight()); g.setColor(Color.BLUE); g.setFont(titleFont); g.drawString("Connect 4", 20, 20); g.setColor(Color.BLACK); g.setFont(regularFont); g.drawString("Type a column number from 0 to 6", 20, 65); g.drawString(message , LEFT, 40); g.drawString(comment , LEFT, 490); g.drawString(score , LEFT, 470); if (board!=null) board.draw(g, LEFT, TOP); } // update is a workaround to cure Windows screen flicker problem public void update(Graphics g){ paint(g); } // These 3 methods need to be declares to implement the KeyListener Interface @Override public void keyTyped(KeyEvent e) {} @Override public void keyPressed(KeyEvent e) {} @Override public void keyReleased(KeyEvent e) { String key = ""+e.getKeyChar(); comment = key +" pressed"; int selectedCol=-1; try{ selectedCol = Integer.parseInt(key); } catch(NumberFormatException formatException) { comment = key +" pressed-- try 0-6 silly "; } if (selectedCol>6) selectedCol=6; if (!gameOver()){ turn++; message="Turn No. "+turn+" "; Color c=player[turn%2].getColor(); if (player[turn%2].isRobot()){ selectedCol=player[turn%2].getMove(board.legalMoves()); board.add(new Piece(c, board.columnTop(selectedCol) ,selectedCol)); }else{ if(board.legalMoves().contains(selectedCol)){ board.add(new Piece(c, board.columnTop(selectedCol) ,selectedCol)); }else{ message+="Illegal move - still "; turn--; } } if (gameOver()) message=player[turn%2].getName()+" WON!"; else message+=player[(turn-1)%2].getName()+"'s move"; } else{ message="Game Over"; } comment="Last Selected Column: "+selectedCol+" (top is "+board.columnTop(selectedCol); comment+= ") legal Moves: "+board.legalMoves(); score="horiz Max="+board.hMax()+" vert max="+board.vMax()+" diag max="+board.dMax(); repaint(); } }