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();
}
}
