I have these classes for my Tic-Tac-Toe game project. I am very new to object oriented analysis and design. Can anyone help determine if SOLID principles are preserved in this code or if it is violating some of them?
public class InputReader {
private BufferedReader inputReader;
public InputReader() {
inputReader = new BufferedReader(new InputStreamReader(System.in));
}
public String getUserInput(String messagePrompt) {
String userInput = null;
System.out.println(messagePrompt);
try {
userInput = inputReader.readLine();
} catch (IOException e) {
e.printStackTrace();
}
return userInput;
}
public void close() {
try {
inputReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class Board {
private static final int SIZE = 3;
private int occupiedCells = 0;
private char[][] board = new char[SIZE][SIZE];
private Set<String> validCells;
public Board() {
validCells = new HashSet<String>();
for (int row = 0; row < SIZE; row++) {
for (int column = 0; column < SIZE; column++) {
board[row][column] = ' ';
validCells.add(row+""+column);
}
}
}
public void print() {
int column, row;
for (row = SIZE - 1; row >= 0; row--) {
System.out.print(row + " ");
for (column = 0; column < SIZE; column++) {
System.out.print("|" + board[row][column]);
}
System.out.println("|");
}
System.out.print(" ");
for (column = 0; column < SIZE; column++) {
System.out.print(column + " ");
}
System.out.println();
}
public void markCell(char playerMark, int row, int column) {
if (board[row][column] != ' ') {
throw new CellOccupiedException("Error..!!! Cell already occupied.");
} else {
board[row][column] = playerMark;
occupiedCells++;
}
}
public boolean hasWinner() {
return (checkRowsForWinner() || checkColumnsForWinner() || checkDiagonalsForWinner());
}
public boolean checkRowsForWinner() {
for (int row = 0; row < SIZE; row++) {
if (checkRow(row)) {
return true;
}
}
return false;
}
public boolean checkColumnsForWinner() {
for (int column = 0; column < SIZE; column++) {
if (checkColumn(column)) {
return true;
}
}
return false;
}
public boolean checkDiagonalsForWinner() {
return checkFirstDiagonal() || checkSecondDiagonal();
}
private boolean checkRow(int row) {
char cell1 = board[row][0];
int column = 1;
while (column < SIZE) {
if (cell1 == ' ' || cell1 != board[row][column]) {
return false;
}
column++;
}
return true;
}
private boolean checkColumn(int column) {
char cell1 = board[0][column];
int row = 1;
while (row < SIZE) {
if (cell1 == ' ' || cell1 != board[row][column]) {
return false;
}
row++;
}
return true;
}
private boolean checkFirstDiagonal() {
char cell1 = board[0][0];
int rowColumn = 1;
while (rowColumn < SIZE) {
if (cell1 == ' ' || cell1 != board[rowColumn][rowColumn]) {
return false;
}
rowColumn++;
}
return true;
}
private boolean checkSecondDiagonal() {
char cell1 = board[0][2];
int row = 1;
int column = 1;
while (row < SIZE) {
if (cell1 == ' ' || cell1 != board[row][column]) {
return false;
}
row++;
column--;
}
return true;
}
public boolean isBoardFull() {
return SIZE*SIZE == occupiedCells;
}
public void checkForValidCell(String inputCell) {
if(validCells.contains(inputCell)){
return;
}else{
throw new InvalidInputException("Error..!!! Invalid Input");
}
}
}
public class Player {
private String name;
private char mark;
public Player(String name, char mark) {
this.name = name;
this.mark = mark;
}
public String getName() {
return name;
}
public char getMark() {
return mark;
}
}
public class GameRunner {
Board board;
Player player1;
Player player2;
InputReader inputReader;
public GameRunner() {
inputReader = new InputReader();
player1 = new Player(inputReader.getUserInput("Enter Player Name 1"), 'O');
player2 = new Player(inputReader.getUserInput("Enter Player Name 2"), 'X');
board = new Board();
}
public void play() {
String playerInput = null;
int turnCount = 1;
String winnerOrDraw = "Game Drawn..!!";
boolean keepPlaying = true;
Player currentPlayer;
while (keepPlaying) {
currentPlayer = turnCount % 2 == 1 ? player1 : player2;
while (playerInput == null) {
board.print();
playerInput = readAndValidateUserInput(currentPlayer.getName(),
currentPlayer.getMark());
}
if (board.hasWinner()) {
winnerOrDraw = currentPlayer.getName() + " wins..!!";
keepPlaying = false;
} else if (board.isBoardFull()) {
keepPlaying = false;
}
playerInput = null;
turnCount++;
}
printResult(winnerOrDraw);
}
private String readAndValidateUserInput(String userName, char userMark) {
String playerInput = null;
try {
playerInput = inputReader.getUserInput(userName
+ " turn. Enter <row><col>. Eg. 20 for top left cell.");
board.checkForValidCell(playerInput);
markBoardCell(userMark, playerInput);
} catch (CellOccupiedException wrongCell) {
System.out.println(wrongCell.getErrorMessage());
playerInput = null;
} catch (InvalidInputException invalidInput) {
System.out.println(invalidInput.getErrorMessage());
playerInput = null;
}
return playerInput;
}
private void markBoardCell(char mark, String playerInput) {
board.markCell(mark, Integer.parseInt(playerInput.substring(0, 1)),
Integer.parseInt(playerInput.substring(1)));
}
private void printResult(String winnerOrDraw) {
board.print();
System.out.println("Result: " + winnerOrDraw);
System.out.println("Press Enter key to exit...");
try {
System.in.read();
} catch (IOException e) {
e.printStackTrace();
}finally{
inputReader.close();
}
}
}