package com.captstudios.games.tafl.core.es.model;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.utils.Array;
import com.captstudios.games.tafl.core.consts.Constants;
import com.captstudios.games.tafl.core.enums.AiType;
import com.captstudios.games.tafl.core.enums.LifeCycle;
import com.captstudios.games.tafl.core.enums.RulesEngineType;
import com.captstudios.games.tafl.core.es.TaflWorld;
import com.captstudios.games.tafl.core.es.model.ai.AiFactory;
import com.captstudios.games.tafl.core.es.model.ai.AiStrategy;
import com.captstudios.games.tafl.core.es.model.ai.optimization.BitBoard;
import com.captstudios.games.tafl.core.es.model.ai.optimization.moves.Move;
import com.captstudios.games.tafl.core.es.model.ai.optimization.transposition.ZorbistHash;
import com.captstudios.games.tafl.core.es.model.rules.RulesFactory;
public class TaflMatch {
public TaflWorld gameWorld;
public String name;
public LifeCycle status;
public int turn = Constants.BoardConstants.NO_TEAM;
public RulesEngineType rulesType;
public long created;
public long updated;
public int computerTeam = Constants.BoardConstants.NO_TEAM;
public String boardRepresentation;
public Array<Move> initialUndoStack;
public TaflBoard board;
public AiStrategy aiStrategy;
public AiStrategy hintStrategy;
public boolean computerStarts;
public Array<TaflMatchObserver> observers;
/**
* For serialization only.
*/
@Deprecated
public TaflMatch() {
this(null);
}
public TaflMatch(TaflWorld gameWorld) {
observers = new Array<TaflMatchObserver>();
this.gameWorld = gameWorld;
}
public void initialize(TaflMatchObserver...observers) {
initializeComponents();
intializeTurn();
registerObservers(observers);
initializeMatch();
}
private void intializeTurn() {
if (turn == Constants.BoardConstants.NO_TEAM) {
turn = board.rules.getFirstTurn();
}
if (computerTeam == Constants.BoardConstants.NO_TEAM) {
int firstTurn = board.rules.getFirstTurn();
int secondTurn = (firstTurn + 1) % 2;
computerTeam = computerStarts ? firstTurn : secondTurn;
}
}
private void initializeComponents() {
int boardSize = boardRepresentation.length();
ZorbistHash hash = new ZorbistHash(Constants.BoardConstants.PIECE_TYPES,
boardSize);
hash.generate();
OrthographicCamera camera = null;
if (gameWorld != null) {
camera = gameWorld.camera;
}
board = new TaflBoard((int)Math.sqrt(boardRepresentation.length()),
Constants.BoardConstants.PIECE_TYPES,
hash,
RulesFactory.getRules(rulesType),
camera);
if (initialUndoStack != null && initialUndoStack.size > 0) {
for (Move move : initialUndoStack) {
board.undoStack.add(board.movePool.obtain().populate(move));
}
initialUndoStack.clear();
}
hintStrategy = AiFactory.getAiStrategy(AiType.AI_INTERMEDIATE, board);
}
private void initializeMatch() {
addPieces();
for (TaflMatchObserver observer : observers) {
observer.initializeMatch(this);
}
}
private void registerObservers(TaflMatchObserver... observers) {
registerObserver(board.rules);
for (TaflMatchObserver observer : observers) {
registerObserver(observer);
}
}
public void registerObserver(TaflMatchObserver observer) {
observers.add(observer);
}
private void addPieces() {
for (int i = 0; i < boardRepresentation.length(); i++) {
char current = boardRepresentation.charAt(i);
if (current == Constants.BoardConstants.WHITE_PIECE) {
board.addPiece(Constants.BoardConstants.WHITE_TEAM, i);
} else if (current == Constants.BoardConstants.BLACK_PIECE) {
board.addPiece(Constants.BoardConstants.BLACK_TEAM, i);
} else if (current == Constants.BoardConstants.KING_PIECE) {
board.addPiece(Constants.BoardConstants.KING, i);
}
}
}
@Override
public int hashCode() {
return name == null ? 0 : name.hashCode();
}
@Override
public boolean equals(Object other) {
return other != null &&
other instanceof TaflMatch &&
name != null &&
name.equals(((TaflMatch)other).name);
}
@Override
public String toString() {
return boardRepresentation;
}
public void applyMove(Move move, boolean simulate) {
board.applyMove(move, simulate);
if (!simulate) {
for (TaflMatchObserver observer : observers) {
observer.applyMove(this, move);
}
}
}
public Move undoMove() {
Move move = board.undoMove();
if (move != null) {
for (TaflMatchObserver observer : observers) {
observer.undoMove(this, move);
}
changeTurn();
return move;
}
return null;
}
public void removePieces(int team, BitBoard capturedPieces) {
board.removePieces(team, capturedPieces);
for (TaflMatchObserver observer : observers) {
observer.removePieces(this, team, capturedPieces);
}
}
public boolean acceptInput() {
return turn != computerTeam;
}
public void changeTurn() {
turn = (turn + 1) % 2;
for (TaflMatchObserver observer : observers) {
observer.changeTurn(this);
}
}
public void gameOver(LifeCycle status) {
this.status = status;
for (TaflMatchObserver observer : observers) {
observer.gameOver(this, status);
}
}
}