Мой первый проект на Java. Говорят - код читабельный, табуляция расставлена по правилам. Можно скачать с github.
Буду рад услышать замечания и подсказки, как улучшить код:)
https://github.com/Vsailor/TicTac2
Иерархия классов:

Прямая ссылка:
http://imgdepo.ru/id/i6692234
Form.java
abstract public class Form {
protected static final int SIZE_OF_MATRIX = 8;
protected static final char BORDER_MATERIAL = '#';
protected static final char EMPTY_CELL = ' ';
protected static char[][] matrix = new char[SIZE_OF_MATRIX][SIZE_OF_MATRIX];
protected static final char FIRST_TOP_COORD = 'a';
protected static final char FIRST_LEFT_COORD = '1';
protected static final char MARK_X = 'X';
protected static final char MARK_O = 'O';
protected static final int WINNER_SCORE = 3;
protected static final int STRINGS_MATRIX_COUNT = 3;
protected static final int TOP_AND_LEFT_BORDER_SIZE = 2;
protected static final int DOWN_AND_RIGHT_BORDER_SIZE = 1;
protected static final String COMPUTER_NAME = "Computer";
protected static final void wrongInputMessage () {
System.out.println("Wrong input. Please, repeat input.");
}
protected static final void notEmptyCellMessage () {
System.out.println("This cell isn't empty. Please, repeat input.");
}
}
IPlayer.java
public interface IPlayer {
public char getMark ();
public void setMark (char mark);
public String getPlayerName();
public void setPlayerName(String playerName);
public void go (Square square, Round round);
}
Human.java
import java.util.Scanner;
public class Human extends Form implements IPlayer {
private String playerName = "Player";
public void setPlayerName (String playerName) {
this.playerName = playerName;
}
public String getPlayerName () {
return playerName;
}
private char mark;
public Human (char mark) {
this.mark = mark;
}
public Human () {}
public void setMark (char mark) {
this.mark = mark;
};
public void go (Square square, Round round) {
Mark playerMark = new Mark(mark);
Scanner input= new Scanner(System.in);
String str;
do {
do {
str = input.next();
playerMark.consoleInput(str);
} while(!playerMark.cinGood(str));
if (!square.emptyCell(playerMark.getLeftCoord(), playerMark.getTopCoord())) {
notEmptyCellMessage();
}
} while (!square.emptyCell(playerMark.getLeftCoord(), playerMark.getTopCoord()));
square.putMark(playerMark);
};
public char getMark () {
return mark;
};
}
Computer.java
import java.util.Random;
public class Computer extends Form implements IPlayer {
private char mark;
private String playerName = "Computer";
public void setPlayerName (String playerName) {
this.playerName = playerName;
}
public String getPlayerName () {
return playerName;
}
public Computer (char mark) {
setMark(mark);
}
public Computer () {}
private boolean canPutMarkInTheCenterOfTheMatrix (Square square) {
if (square.emptyCell('2', 'b')) {
return true;
} else {
return false;
}
}
private void putMarkInCenterOfTheMatrix (Square square, Mark mark) {
mark.setLeftCoord('2');
mark.setTopCoord('b');
if (square.emptyCell(mark.getLeftCoord(), mark.getTopCoord())) {
square.putMark(mark);
}
}
private boolean canPutMarkInTheConnerOfTheMatrix (Square square) {
if (square.emptyCell('1','a') || square.emptyCell('1','c') || square.emptyCell('3','a') || square.emptyCell('3','c')) {
return true;
} else {
return false;
}
}
private void putMarkInTheConnerOfTheMatrix (Square square, Mark mark) {
Random rand = new Random(System.currentTimeMillis());
do {
switch (rand.nextInt(4)) {
case 0:
mark.setLeftCoord('1');
mark.setTopCoord('a');
break;
case 1:
mark.setLeftCoord('1');
mark.setTopCoord('c');
break;
case 2:
mark.setLeftCoord('3');
mark.setTopCoord('a');
break;
case 3:
mark.setLeftCoord('3');
mark.setTopCoord('c');
break;
default:
}
} while (!square.emptyCell(mark.getLeftCoord(),mark.getTopCoord()));
square.putMark(mark);
}
private void putMarkInTheRandomPlace (Square square, Mark mark) {
Random rand = new Random(System.currentTimeMillis());
do {
switch (rand.nextInt(3)) {
case 0:
mark.setLeftCoord('1');
break;
case 1:
mark.setLeftCoord('2');
break;
case 2:
mark.setLeftCoord('3');
break;
default:
}
switch (rand.nextInt(3)) {
case 0:
mark.setTopCoord('a');
break;
case 1:
mark.setTopCoord('b');
break;
case 2:
mark.setTopCoord('c');
break;
default:
}
} while (!square.emptyCell(mark.getLeftCoord(),mark.getTopCoord()));
square.putMark(mark);
}
private boolean playerWillBeWinnerInTheNextStep (Square square, IPlayer player) {
Mark mark = new Mark(player.getMark());
for (char i=FIRST_LEFT_COORD; i<FIRST_LEFT_COORD + STRINGS_MATRIX_COUNT; i++) {
for (char j=FIRST_TOP_COORD; j<FIRST_TOP_COORD + STRINGS_MATRIX_COUNT; j++) {
mark.setLeftCoord(i);
mark.setTopCoord(j);
if (square.emptyCell(mark.getLeftCoord(), mark.getTopCoord())) {
square.putMark(mark);
if (square.winner(player)) {
square.clearCell(mark.getLeftCoord(), mark.getTopCoord());
return true;
} else {
square.clearCell(mark.getLeftCoord(), mark.getTopCoord());
}
}
}
}
return false;
}
private void blockCellThatPlayerWillNotBeWinnerInTheNextStep (Square square, Human human) {
Mark mark = new Mark(human.getMark());
for (char i=FIRST_LEFT_COORD; i<FIRST_LEFT_COORD + STRINGS_MATRIX_COUNT; i++) {
for (char j=FIRST_TOP_COORD; j<FIRST_TOP_COORD + STRINGS_MATRIX_COUNT; j++) {
mark.setLeftCoord(i);
mark.setTopCoord(j);
if (square.emptyCell(mark.getLeftCoord(), mark.getTopCoord())) {
square.putMark(mark);
if (square.winner(human)) {
square.clearCell(mark.getLeftCoord(), mark.getTopCoord());
if (human.getMark() == MARK_X) {
mark.setMark(MARK_O);
} else {
mark.setMark(MARK_X);
}
square.putMark(mark);
return;
} else {
square.clearCell(mark.getLeftCoord(), mark.getTopCoord());
}
}
}
}
}
private void chooseCellToWinInTheNextStep (Square square, IPlayer player) {
Mark mark = new Mark(player.getMark());
for (char i=FIRST_LEFT_COORD; i<FIRST_LEFT_COORD + STRINGS_MATRIX_COUNT; i++) {
for (char j=FIRST_TOP_COORD; j<FIRST_TOP_COORD + STRINGS_MATRIX_COUNT; j++) {
mark.setLeftCoord(i);
mark.setTopCoord(j);
if (square.emptyCell(mark.getLeftCoord(), mark.getTopCoord())) {
square.putMark(mark);
if (!square.winner(player)) {
square.clearCell(mark.getLeftCoord(), mark.getTopCoord());
} else {
return;
}
}
}
}
}
public void setMark (char mark) {
this.mark = mark;
}
public char getMark () {
return mark;
};
private boolean cleverRandom (Square square, Human human, Mark mark) {
Mark humanMark = new Mark(human.getMark());
if (square.belongs(humanMark, '2', 'a') && square.belongs(humanMark, '1', 'b')) {
mark.setLeftCoord('1');
mark.setTopCoord('a');
square.putMark(mark);
return true;
}
if (square.belongs(humanMark, '1', 'b') && square.belongs(humanMark, '2', 'c')) {
mark.setLeftCoord('1');
mark.setTopCoord('c');
square.putMark(mark);
return true;
}
if (square.belongs(humanMark, '3', 'b') && square.belongs(humanMark, '2', 'c')) {
mark.setLeftCoord('3');
mark.setTopCoord('c');
square.putMark(mark);
return true;
}
if (square.belongs(humanMark, '3', 'b') && square.belongs(humanMark, '2', 'a')) {
mark.setLeftCoord('3');
mark.setTopCoord('a');
square.putMark(mark);
return true;
}
return false;
}
public void go (Square square, Round round) {
Mark humanMark;
Mark computerMark = new Mark(this.getMark());
Human fakeHuman;
if (round.start == 1) {
if (this.getMark() == MARK_X) {
fakeHuman = new Human(MARK_O);
humanMark = new Mark(MARK_O);
} else {
fakeHuman = new Human(MARK_X);
humanMark = new Mark(MARK_X);
}
} else {
if (this.getMark() == MARK_O) {
fakeHuman = new Human(MARK_X);
humanMark = new Mark(MARK_X);
} else {
fakeHuman = new Human(MARK_O);
humanMark = new Mark(MARK_O);
}
}
if (playerWillBeWinnerInTheNextStep(square, this)) {
chooseCellToWinInTheNextStep(square, this);
return;
}
if (playerWillBeWinnerInTheNextStep(square, fakeHuman)) {
blockCellThatPlayerWillNotBeWinnerInTheNextStep(square, fakeHuman);
return;
}
computerMark.setLeftCoord('2');
computerMark.setTopCoord('b');
if (square.emptyCell(computerMark.getLeftCoord(), computerMark.getTopCoord())) {
square.putMark(computerMark);
return;
}
if (!cleverRandom(square, fakeHuman, computerMark)) {
if (square.emptyCell('1', 'a') || square.emptyCell('1', 'c') || square.emptyCell('3', 'a') || square.emptyCell('3', 'c')) {
putMarkInTheConnerOfTheMatrix(square, computerMark);
return;
}
}
putMarkInTheRandomPlace(square, computerMark);
}
}
Round.java
import java.util.Scanner;
public class Round extends Form {
public int start = 0;
private char typeOfGame;
public char getTypeOfGame() {
return typeOfGame;
}
public void registration (IPlayer player1, IPlayer player2) {
Scanner input= new Scanner(System.in);
if (player1.getPlayerName() == COMPUTER_NAME) {
System.out.println("Enter your name:");
player2.setPlayerName(input.next());
} else if (player2.getPlayerName() == COMPUTER_NAME) {
System.out.println("Enter your name:");
player1.setPlayerName(input.next());
} else {
System.out.println("Name of first player:");
player1.setPlayerName(input.next());
System.out.println("Hello " + player1.getPlayerName() + "!");
System.out.println("Name of second player:");
player2.setPlayerName(input.next());
System.out.println("Hello " + player2.getPlayerName() + "!");
}
}
public void setMarksForPlayers (IPlayer player1, IPlayer player2) {
Scanner input= new Scanner(System.in);
String str;
System.out.println("Who will be playing X?");
System.out.println();
if (player1.getPlayerName() == COMPUTER_NAME || player2.getPlayerName() == COMPUTER_NAME) {
System.out.println("1. Me");
System.out.println("2. " + COMPUTER_NAME);
System.out.println();
char answer = '0';
do {
str = input.next();
if (str.length() == 1) {
char []var = str.toCharArray();
answer = var[0];
if (!((var[0] == '1' ) || (var[0] == '2'))) {
wrongInputMessage();
}
if (answer == '1') {
this.start = 1;
}
if (answer == '2') {
this.start = 2;
}
} else {
wrongInputMessage();
}
} while(!(answer == '1' || answer == '2'));
} else {
System.out.println("1. " + player1.getPlayerName());
System.out.println("2. " + player2.getPlayerName());
System.out.println();
char answer = '0';
do {
str = input.next();
if (str.length() == 1) {
char []var = str.toCharArray();
answer = var[0];
if (!((var[0] == '1' ) || (var[0] == '2'))) {
wrongInputMessage();
}
if (answer == '1') {
start = 1;
} else {
start = 2;
}
} else {
wrongInputMessage();
}
} while(!(answer == '1' || answer == '2'));
}
}
public void hello() {
String str;
System.out.println();
System.out.println("***************************************************************");
System.out.println("* *");
System.out.println("* TIC TAC *");
System.out.println("* *");
System.out.println("* ALPHA *");
System.out.println("* *");
System.out.println("***************************************************************");
System.out.println();
System.out.println("Choose the type of the game:");
System.out.println();
System.out.println("1. Player VS Player");
System.out.println("2. Player VS Computer");
System.out.println();
Scanner input= new Scanner(System.in);
do {
str = input.next();
if (str.length() == 1) {
char []var = str.toCharArray();
typeOfGame = var[0];
if (!((var[0] == '1' ) || (var[0] == '2'))) {
wrongInputMessage();
}
} else {
wrongInputMessage();
}
} while(!(typeOfGame == '1' || typeOfGame == '2'));
}
public boolean restartGame() {
Scanner input= new Scanner(System.in);
System.out.println("Do you want to restart the game?[y/n] ");
String str;
char ans = 0;
do {
str = input.next();
if (str.length() == 1) {
char []var = str.toCharArray();
ans = var[0];
if (!((var[0] == 'y' ) || (var[0] == 'n'))) {
wrongInputMessage();
}
} else {
wrongInputMessage();
}
} while(!(ans == 'y' || ans == 'n'));
if (ans == 'y') {
return true;
} else {
System.out.println("Good bye!");
return false;
}
}
}
Mark.java
public class Mark extends Form {
private char mark;
private char leftCoord;
private char topCoord;
public Mark (char mark) {
setMark(mark);
}
public void setMark (char mark) {
if (mark == MARK_X || mark == MARK_O) {
this.mark = mark;
} else {
System.out.println("Wrong mark input.");
}
}
public Mark () {}
public char getMark() {
return mark;
}
public char getTopCoord() {
return topCoord;
}
public char getLeftCoord() {
return leftCoord;
}
public void setLeftCoord(char leftCoord) {
if (leftCoord>=FIRST_LEFT_COORD && leftCoord<=FIRST_LEFT_COORD+SIZE_OF_MATRIX/2-TOP_AND_LEFT_BORDER_SIZE) {
this.leftCoord = leftCoord;
}
}
public void setTopCoord(char topCoord) {
if (topCoord>=FIRST_TOP_COORD && topCoord<=FIRST_TOP_COORD+SIZE_OF_MATRIX/2-TOP_AND_LEFT_BORDER_SIZE){
this.topCoord = topCoord;
}
}
public void consoleInput(String str) {
char []string = str.toCharArray();
setTopCoord(string[0]);
setLeftCoord(string[1]);
}
public boolean cinGood(String str) {
char []string = str.toCharArray();
if (str.length()==2) {
if (string[0] >= FIRST_TOP_COORD && string[0] <= FIRST_TOP_COORD+SIZE_OF_MATRIX/2-TOP_AND_LEFT_BORDER_SIZE) {
if (string[1] >= FIRST_LEFT_COORD && string[1] <= FIRST_LEFT_COORD+SIZE_OF_MATRIX/2-DOWN_AND_RIGHT_BORDER_SIZE) {
return true;
} else {
wrongInputMessage();
return false;
}
} else {
wrongInputMessage();
return false;
}
} else {
wrongInputMessage();
return false;
}
}
}
Square.java
import java.util.Scanner;
public class Square extends Form {
public Square() {
for (int i=0; i< SIZE_OF_MATRIX; i++) {
eraseLine(i);
}
setBorder();
}
private void eraseLine (int line_number) {
for (int i=0; i< SIZE_OF_MATRIX; i++){
matrix[line_number][i] = EMPTY_CELL;
}
}
private boolean winnerScore (int count) {
if (count == WINNER_SCORE) {
return true;
} else {
return false;
}
}
private void setBorder() {
for (int i=TOP_AND_LEFT_BORDER_SIZE-1; i< SIZE_OF_MATRIX; i+=2) {
for (int k=TOP_AND_LEFT_BORDER_SIZE-1; k< SIZE_OF_MATRIX; k++) {
matrix[i][k] = BORDER_MATERIAL;
}
for (int k=TOP_AND_LEFT_BORDER_SIZE; k< SIZE_OF_MATRIX; k++) {
matrix[k][i] = BORDER_MATERIAL;
}
}
char topCoord = FIRST_TOP_COORD;
for (int i=TOP_AND_LEFT_BORDER_SIZE; i< SIZE_OF_MATRIX; i+=2) {
matrix[0][i] = topCoord;
topCoord++;
}
char leftCoord = FIRST_LEFT_COORD;
for (int i=TOP_AND_LEFT_BORDER_SIZE; i< SIZE_OF_MATRIX; i+=2) {
matrix[i][0] = leftCoord;
leftCoord++;
}
}
public int countOfMarks (char mark) {
int count = 0;
for (int i=0; i<SIZE_OF_MATRIX; i++) {
for (int k=0; k<SIZE_OF_MATRIX; k++) {
if (matrix[i][k] == mark) {
count++;
}
}
}
return count;
}
private boolean checkWinInHorizontalAndVerticalLines (IPlayer player) {
int leftLineCount = 0;
int topLineCount = 0;
for (int i=0; i<SIZE_OF_MATRIX; i++) {
for (int k=0; k<SIZE_OF_MATRIX; k++) {
if (matrix[i][k] == player.getMark()) {
leftLineCount++;
}
if (matrix[k][i] == player.getMark()) {
topLineCount++;
}
if (winnerScore(leftLineCount) || winnerScore(topLineCount)) {
return true;
}
}
leftLineCount = 0;
topLineCount = 0;
}
return false;
}
private boolean checkWinInDiagonalLines (IPlayer player) {
int count1 = 0;
for (int i=0; i<SIZE_OF_MATRIX; i++) {
if (matrix[i][i] == player.getMark()) {
count1++;
}
}
int count2 = 0;
for (int i=SIZE_OF_MATRIX-DOWN_AND_RIGHT_BORDER_SIZE, j=TOP_AND_LEFT_BORDER_SIZE-1; i>=TOP_AND_LEFT_BORDER_SIZE; i--, j++) {
if (matrix[i][j] == player.getMark()) {
count2++;
}
}
if (count1 == WINNER_SCORE || count2 == WINNER_SCORE) {
return true;
} else {
return false;
}
}
private boolean playerWillBeWinnerInTheNextStep (IPlayer player) {
Mark mark = new Mark(player.getMark());
for (char i=FIRST_LEFT_COORD; i<FIRST_LEFT_COORD + STRINGS_MATRIX_COUNT; i++) {
for (char j=FIRST_TOP_COORD; j<FIRST_TOP_COORD + STRINGS_MATRIX_COUNT; j++) {
mark.setLeftCoord(i);
mark.setTopCoord(j);
if (emptyCell(mark.getLeftCoord(), mark.getTopCoord())) {
putMark(mark);
if (winner(player)) {
clearCell(mark.getLeftCoord(), mark.getTopCoord());
return true;
} else {
clearCell(mark.getLeftCoord(), mark.getTopCoord());
}
}
}
}
return false;
}
private void showMatrixLine (int line_number) {
for (int i=0; i< SIZE_OF_MATRIX; i++) {
System.out.print(matrix[line_number][i]);
}
}
public void showMatrix () {
for (int i=0; i< SIZE_OF_MATRIX; i++) {
showMatrixLine(i);
System.out.println();
}
}
public void winMessage (IPlayer player) {
System.out.print(player.getPlayerName() + " is winner!");
}
public boolean winner (IPlayer player) {
if (checkWinInHorizontalAndVerticalLines(player) || checkWinInDiagonalLines(player)) {
return true;
} else {
return false;
}
}
public boolean belongs (Mark mark, char leftCoord, char topCoord) {
if (matrix[(leftCoord-FIRST_LEFT_COORD)*2+TOP_AND_LEFT_BORDER_SIZE][(topCoord-FIRST_TOP_COORD)*2+TOP_AND_LEFT_BORDER_SIZE] == mark.getMark()) {
return true;
}
return false;
}
public boolean endWithoutWinner () {
for (int i=TOP_AND_LEFT_BORDER_SIZE; i<SIZE_OF_MATRIX; i++) {
for (int k=TOP_AND_LEFT_BORDER_SIZE; k<SIZE_OF_MATRIX; k++) {
if (matrix[i][k] == EMPTY_CELL) {
return false;
}
}
}
return true;
}
public void endWithoutWinnerMessage () {
System.out.println("Game over. Winner is absent.");
}
public boolean emptyCell (char leftCoord, char topCoord) {
if (matrix[(leftCoord-FIRST_LEFT_COORD)*2+TOP_AND_LEFT_BORDER_SIZE][(topCoord-FIRST_TOP_COORD)*2+TOP_AND_LEFT_BORDER_SIZE] == EMPTY_CELL) {
return true;
} else {
return false;
}
}
public void clearCell(char leftCoord, char topCoord) {
matrix[(leftCoord-FIRST_LEFT_COORD)*2+TOP_AND_LEFT_BORDER_SIZE][(topCoord-FIRST_TOP_COORD)*2+TOP_AND_LEFT_BORDER_SIZE] = EMPTY_CELL;
}
public void putMark (Mark mark) {
if (matrix[(mark.getLeftCoord()-FIRST_LEFT_COORD)*2+TOP_AND_LEFT_BORDER_SIZE][(mark.getTopCoord()-FIRST_TOP_COORD)*2+TOP_AND_LEFT_BORDER_SIZE] == EMPTY_CELL) {
matrix[(mark.getLeftCoord()-FIRST_LEFT_COORD)*2+TOP_AND_LEFT_BORDER_SIZE][(mark.getTopCoord()-FIRST_TOP_COORD)*2+TOP_AND_LEFT_BORDER_SIZE] = mark.getMark();
}
}
}
Main.java
import java.util.Scanner;
public class Main extends Form {
public static void main(String[] args) {
Round round;
do {
round = new Round();
Square square = new Square();
round.hello();
IPlayer player1 = new Human();
IPlayer player2;
if (round.getTypeOfGame() == '2') {
player2 = new Computer();
} else {
player2 = new Human();
}
round.registration(player1,player2);
round.setMarksForPlayers(player1, player2);
if (round.start == 1) {
player1.setMark(MARK_X);
player2.setMark(MARK_O);
} else {
player1.setMark(MARK_O);
player2.setMark(MARK_X);
}
square.showMatrix();
while (true) {
if (round.start == 1) {
player1.go(square,round);
square.showMatrix();
if (square.winner(player1)) {
square.winMessage(player1);
break;
}
if (square.endWithoutWinner()) {
square.endWithoutWinnerMessage();
break;
}
round.start = 2;
} else {
player2.go(square, round);
square.showMatrix();
if (square.winner(player2)) {
square.winMessage(player2);
break;
}
if (square.endWithoutWinner()) {
square.endWithoutWinnerMessage();
break;
}
round.start = 1;
}
}
} while (round.restartGame());
}
}