package model;
import model.field.Field;
import model.field.IField;
import model.field.State;
import org.apache.log4j.Logger;
import util.ClassName;
public class GameModel {
private static final Logger logger = Logger.getLogger(ClassName.getCurrentClassName());
private static final int MINIMAL_FIELD_SIZE = 0;
private static final int MAXIMUM_FIELD_SIZE = 20;
private static final int MINIMAL_WIN_LINE_LENGTH = 0;
private final int totalMovesCount;
private final int winLineLength;
private State turnState = State.CROSS;
private int moveCounter = 0;
private boolean isGameEnded = false;
private State gameWinner = State.NONE;
protected Field gameField;
public GameModel(int fieldSize, int winLineLength) {
logger.debug(String.format("field size %d, win line length %d", fieldSize, winLineLength));
if (fieldSize <= MINIMAL_FIELD_SIZE || fieldSize > MAXIMUM_FIELD_SIZE ||
winLineLength <= MINIMAL_WIN_LINE_LENGTH || winLineLength > fieldSize) {
throw new IllegalArgumentException();
}
this.winLineLength = winLineLength;
this.totalMovesCount = fieldSize * fieldSize;
gameField = new Field(fieldSize);
}
public boolean doMove(int row, int column) {
logger.debug(String.format("attempting to commit move [%d, %d] for field %s ", row, column, gameField.toString()));
if (!gameField.isCellPositionCorrect(row, column) || !gameField.isCellEmpty(row, column)) {
logger.warn(String.format("cell [%d, %d] is not free", row, column));
return false;
}
moveCounter++;
gameField.setCellState(row, column, turnState);
logger.debug("move committed");
checkGameState(row, column);
nextGameTurnState();
logger.debug("field state after committed move " + gameField.toString());
return true;
}
private void nextGameTurnState() {
logger.debug("switching turn from " + turnState);
turnState = (turnState == State.CIRCLE) ? State.CROSS : State.CIRCLE;
}
private int getLineLength(int row, int column,
int rowShift, int columnShift) {
State lineState = gameField.getCellState(row, column);
// exclude start point from length
int counter = -1;
do {
row += rowShift;
column += columnShift;
counter++;
} while (gameField.isCellPositionCorrect(row, column) &&
(gameField.getCellState(row, column) == lineState));
return counter;
}
private boolean isWinLineConstructed(int row, int column) {
// calculating line length in different directions: south+north, west+east, etc.
return (getLineLength(row, column, 1, 0) + getLineLength(row, column, -1, 0) >= winLineLength - 1) ||
(getLineLength(row, column, 0, 1) + getLineLength(row, column, 0, -1) >= winLineLength - 1) ||
(getLineLength(row, column, 1, 1) + getLineLength(row, column, -1, -1) >= winLineLength - 1) ||
(getLineLength(row, column, 1, -1) + getLineLength(row, column, -1, 1) >= winLineLength - 1);
}
private void checkGameState(int row, int column) {
logger.debug(String.format("checking for win line after move [%d, %d]", row, column));
if (isWinLineConstructed(row, column)) {
logger.debug("win line constructed, finishing game");
isGameEnded = true;
gameWinner = gameField.getCellState(row, column);
logger.debug("setting game winner to " + gameWinner);
} else {
logger.debug("win line was not found");
if (moveCounter == totalMovesCount) {
logger.debug("no free space left at the game field, ending game");
isGameEnded = true;
}
}
}
public boolean isGameFinished() {
return isGameEnded;
}
public String getGameWinner() {
switch (gameWinner) {
case CROSS: return "cross";
case CIRCLE: return "circle";
case NONE: return "draw";
default:
logger.error("unknown game winner " + gameWinner);
throw new IllegalArgumentException();
}
}
public IField getField() {
return gameField;
}
}