1
\$\begingroup\$

I've written my first project which is Tic Tac Toe. Everything is working correctly. I'm here to get some advice about my code. I want to be this code as much object oriented as it can be. I divided every method into new class to keep it clear.

The only thing which is "probably" un-object oriented is "static" board. I don't know how to get rid of it.

Main Class

package TicTacToeGame;

public class Main {

public static void main(String[] args) {
    Game allGame = new Game();
    allGame.StartGame();
}    
}

Game Class

package TicTacToeGame;

import java.util.Scanner;

class Game {
PrintBoard map = new PrintBoard();
private FullPlace fullPlace = new FullPlace();
ChangePlayer playerChanger = new ChangePlayer();
WinnerConditions winner = new WinnerConditions();
Scanner input = new Scanner(System.in);
char[][] board = PrintBoard.board;
NoPlace noPlace = new NoPlace();
private int row, col;


void StartGame() {


    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            board[i][j] = '_';
        }
    }


    map.printBoard();
    while (winner.Winner()) {

        row = input.nextInt();
        col = input.nextInt();
        if (row > 3 || col > 3) {
            System.out.println("You've inputed place, which is out of the board!\nTry again!");

        } else {
            if (fullPlace.isFull(row, col)) {
                System.err.println("The place is taken");

            } else {
                board[row - 1][col - 1] = playerChanger.getTurn();
                map.printBoard();
                playerChanger.whichPlayer();
            }

        }


    }
    playerChanger.whichPlayer();
    System.out.println("the winner is " + playerChanger.getTurn());
}
}

Winner Condition Class

package TicTacToeGame;

public class WinnerConditions {
char[][] board = PrintBoard.board;

public boolean Winner() {

    if (board[0][0] != '_' && board[0][0] == board[0][1] && board[0][0] == board[0][2])
        return false;
    if (board[1][0] != '_' && board[1][0] == board[1][1] && board[1][0] == board[1][2])
        return false;
    if (board[2][0] != '_' && board[2][0] == board[2][1] && board[2][0] == board[2][2])
        return false;
    if (board[0][0] != '_' && board[0][0] == board[1][0] && board[0][0] == board[2][0])
        return false;
    if (board[0][1] != '_' && board[0][1] == board[1][1] && board[0][1] == board[2][1])
        return false;
    if (board[0][2] != '_' && board[0][2] == board[1][2] && board[0][2] == board[2][2])
        return false;
    if (board[0][0] != '_' && board[0][0] == board[1][1] && board[0][0] == board[2][2])
        return false;
    if (board[0][2] != '_' && board[0][2] == board[1][1] && board[0][2] == board[2][0])
        return false;

    return true;
}

}

No Place Class

package TicTacToeGame;

public class NoPlace {
char[][] board = PrintBoard.board;

public boolean OutOfBoard(int row, int col) {
    if (row > 3 || col > 3) {
        System.err.println("There is no row or column");
        return true;

    }
    return false;

}
}

Print Board Class

package TicTacToeGame;

public class PrintBoard {
public static char[][] board = new char[3][3];


public void printBoard() {

    System.out.println("-------------");
    for (int i = 0; i < 3; i++) {
        System.out.print("| ");
        for (int j = 0; j < 3; j++) {

            System.out.print(board[i][j] + " | ");

        }
        System.out.println();

    }
    System.out.println("-------------");

}
}

Change Player Class

package TicTacToeGame;

public class ChangePlayer {
public char turn = 'X';

public void whichPlayer() {
    if (turn == 'X') {
        turn = 'O';
    } else {
        turn = 'X';

    }
}

public char getTurn() {
    return turn;
}


}

Full Place Class

package TicTacToeGame;

public class FullPlace {
char[][] board = PrintBoard.board;

public boolean isFull(int row, int col) {
    if (board[row - 1][col - 1] == 'X' ||
        board[row - 1][col - 1] == 'O') {
        return true;
    }
    return false;
}


}
\$\endgroup\$
  • 2
    \$\begingroup\$ Your class modeling is strange, not object-oriented. Where you introduce separate classes like FullPlace, I'd create methods on the Game class instead. A helpful start for modeling is describing your task in English, and representing nouns as classes and verbs as methods. \$\endgroup\$ – Ralf Kleberhoff Dec 24 '17 at 21:22
  • \$\begingroup\$ @RalfKleberhoff If I understand rigthly, I should remove classes with one method and create in Game Class? What do you mean about "a helpful start for modeling is describing your task in English"? I just wanted to create Tic Tac Toe Game :D There isn't any task. \$\endgroup\$ – must Dec 24 '17 at 23:11
  • 1
    \$\begingroup\$ Most of your objects are stateless. There are reasons to create such things, but not in your program. An object to represent the contents of the board is legitimate, but it shouldn't be called PrintBoard, since that's hardly the sole purpose of representing the board. You can avoid the static member by passing the board to any method that needs it. An object to keep track of which player is playing is OK too, and an object to hold both of those. With just console input and output, there really isn't much else in this game to use objects for. \$\endgroup\$ – David K Dec 25 '17 at 3:41
  • \$\begingroup\$ Actually, it is also possible to turn each individual cell in the board into an object. Perhaps a little bit of overkill for a program like this but it at least makes some kind of sense with regard to the model. \$\endgroup\$ – David K Dec 25 '17 at 3:52
  • \$\begingroup\$ You should consider what the purpose of each class is. Does it represent some object in your problem domain, such as a tic-tac-toe grid? Is it part of a design pattern that employs this class along with some others? You can have a one-method class, but there should be a reason. For example, if you had ten different ways to draw an X or O on the grid, it might make sense to have a one-function class to implement each way--there's a pattern for such things. \$\endgroup\$ – David K Dec 25 '17 at 13:46
3
\$\begingroup\$

Thanks for sharing your code.

OOP

OOP doesn't mean to "split up" code into random classes.

The ultimate goal of OOP is to reduce code duplication, improve readability and support reuse as well as extending the code.

Doing OOP means that you follow certain principles which are (among others):

  • information hiding / encapsulation
  • single responsibility
  • separation of concerns
  • KISS (Keep it simple (and) stupid.)
  • DRY (Don't repeat yourself.)
  • "Tell! Don't ask."
  • Law of demeter ("Don't talk to strangers!")

E.g.: in your class TicTacToeGame you access a field in the class PrintBoard. This is a violation of the information hiding / encapsulation principle. The cause why you "can't get rid" of that static access is that you should not access this field from outside at all. The method in you FullPlace class schould be in class PrintBoard (which should not be named with the prefix "print"). In turn the classFullPlace should't exist at all.

Naming

Finding good names is the hardest part in programming, so always take your time to think about the names of your identifiers.

Naming Conventions

Please read (and follow) the Java Naming Conventions

misleading naming

Some of your identifiers have somewhat misleading names, eg. ChangePlayer and PrintBoard which look like method names since they start with a verb but they are classes. But classes don't do something. They are something which is able to do something.

Magic numbers

Your code has some magic numbers. This are literal values with a special meaning like here:

    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) 

You should either use constants with meaningful names like

private static final int GAME_FIELD_SIZE =3;
// ...
for (int i = 0; i < GAME_FIELD_SIZE; i++) {
    for (int j = 0; j < GAME_FIELD_SIZE; j++) {

or use existing constraints like so:

for (int i = 0; i < board.length; i++) {
    for (int j = 0; j < board[0].length; j++) {
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.