I have been building a Connect Four game in a procedural way. Could somebody make some recommendations on how I could transform this code into an object oriented state? This will be the first time I have attempted object oriented, so would appreciate any advice/tips.

I know that i need to split the code into different classes to make it OO, so I was thinking of creating a Board and Main class. Would this be sufficient or are there more classes that I should be thinking about?

I have been reading about interfaces and was also thinking of using one for the players of the game (Human player and Computer player), but I am unsure the best way to do this.

ConnectFourGame.java

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Random;

public class ConnectFourGame {

int totalPlayed;
int[][] gameBoard;
final int widthOfBoard=7;
final int heightOfBoard=7;

public ConnectFourGame(){
    gameBoard = new int[widthOfBoard][widthOfBoard];
    totalPlayed=0;
}

public static void main(String args[])throws IOException{

    ConnectFourGame Connect4 = new ConnectFourGame();
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

    System.out.println("Welcome to Connect 4");
    System.out.println("There are 2 players red and yellow");
    System.out.println("Player 1 is Red, Player 2 is Yellow");
    System.out.println("To play the game type in the number of the boardColumn you want to drop you counter in");
    System.out.println("A player wins by connecting 4 counters in a row - vertically, horizontally or diagonally");
    System.out.println("");
    Connect4.printBoard();
    outer:

    while(true){

        int boardColumn = 0;

        //Player One Logic
        while(true){
        System.out.println("");
        System.out.println("Player 1, please select your column:");
        boardColumn = Integer.parseInt(br.readLine());
            if(Connect4.canMakeMove(boardColumn)){
                if(Connect4.placeCounter(boardColumn, 1)){
                    Connect4.printBoard();
                    System.out.println("\n\nPlayer 1 wins!!!");
                    break outer;
                }
                break;
            }
            else
                System.out.println("Column "+boardColumn+" is already full!!");
        }
        Connect4.printBoard();

        //PLAYER 2.    
        while(true){
        System.out.println("");
        System.out.println("Player 2, please select your column");

        Random r = new Random();
        int num = r.nextInt(7);

        boardColumn=num;


            if(Connect4.canMakeMove(boardColumn)){
                if(Connect4.placeCounter(boardColumn, 2)){
                    Connect4.printBoard();
                    System.out.println("\n\nPlayer 2 wins!!!");
                    break outer;
                }
                break;
            }
            else
                System.out.println("Column "+boardColumn+" is already full!!");
        }
        Connect4.printBoard();

        if(Connect4.gameTied()){
            System.out.print("The game has ended in a draw. Please start the game again.");
            break;
        }
    }
}

public void printBoard(){
    for(int i=0;i<gameBoard.length;i++){
        for(int j=0;j<gameBoard[0].length;j++){
            if(gameBoard[i][j] == 0)
                System.out.print(".  ");
            else
                System.out.print(gameBoard[i][j]+"  ");
        }
        System.out.println("");
    }
    System.out.println("*  *  *  *  *  *  *");
    System.out.println("0  1  2  3  4  5  6");
}

public boolean placeCounter(int boardColumn, int playerNum){
    int i=0;
    for(i=0;i<widthOfBoard;i++){
        if(gameBoard[i][boardColumn] == 1 || gameBoard[i][boardColumn] == 2){
            gameBoard[i-1][boardColumn]=playerNum;
            break;
        }
    }
    if(i == widthOfBoard)
        gameBoard[i-1][boardColumn]=playerNum;

    totalPlayed++;
    return isConnected(i-1,boardColumn);
}

public boolean canMakeMove(int boardColumn){
    return gameBoard[0][boardColumn] == 0; 
}

public boolean gameTied(){
    return totalPlayed == widthOfBoard*widthOfBoard;
}

public void isHorizontal() {

}

public boolean isConnected(int x, int y){
    int num=gameBoard[x][y];
    int count=0;
    int i=y;

    //HORIZONTAL.
    while(i<widthOfBoard && gameBoard[x][i] == num){
        count++;
        i++;
    }
    i=y-1;
    while(i>=0 && gameBoard[x][i] == num){
        count++;
        i--;
    }
    if(count == 4)
        return true;

    //VERTICAL.
    count=0;
    int j=x;
    while(j<widthOfBoard && gameBoard[j][y] == num){
        count++;
        j++;
    }
    if(count == 4)
        return true;

    //SECONDARY DIAGONAL.
    count=0;
    i=x;
    j=y;
    while(i<widthOfBoard && j<widthOfBoard && gameBoard[i][j] == num){
        count++;
        i++;
        j++;
    }

    if(count == 4)
        return true;

    //LEADING DIAGONAL.
    count=0;
    i=x;
    j=y;
    while(i<widthOfBoard && j>=0 && gameBoard[i][j] == num){
        count++;
        i++;
        j--;
    }

    if(count == 4)
        return true;

    return false;
}
}

2 Answers

0
john16384 On

A Board class would be a pretty good start. It could have methods for placing a disc into a column with a certain color.

A Player class could keep track of the player name and color.

A Color enum for the two colors.

A Game class could keep track of which Players and who's turn it is, and can examine the board whether there is a win or draw.

Game

private Board board;
private Player[] players;
private Player currentPlayer;

void reset();  // Resets game
Player getCurrentPlayer();
Player isGameWon();  // Returns player that won, or null if nobody won
boolean isGameOver();  // Returns true if no more moves can be made

// Places a disc, throws exception if it is not players turn.
// This delegates to the Board class, and advances the turn.
void placeDisc(Player player, int column);        

Board

private Color[][] squares;

void clear();
void placeDisc(Color color, int column);  // Place a disc, throws exception if column full
boolean isColumnFull(int column);  // Could come in handy...
Color getDiscAt(int x, int y);  // Returns coloe of disc at location, or null if none

Color

An enum (RED, YELLOW) ?

public enum Color {RED, YELLOW}

Player

private String name;
private Color color;

String getName();
Color getColor();
0
Roman C On

You should be thinking about OOD in the initial phase of the process. After the code is written the remaining process is refactoring. I didn't see the code is written OO since you tried to remove static modifier from the methods. If you don't create additional methods then consider to aggregate common properties to the class from the methods that will belong too. First you create objects, then call methods.