Skip to content

Instantly share code, notes, and snippets.

@marvk
Created February 19, 2019 10:59
Show Gist options
  • Save marvk/bd97e5e9540b8c9df3598cd0edb83f3c to your computer and use it in GitHub Desktop.
Save marvk/bd97e5e9540b8c9df3598cd0edb83f3c to your computer and use it in GitHub Desktop.
package net.marvk.nuthello.game;
import javafx.beans.property.SimpleListProperty;
import javafx.collections.FXCollections;
import net.marvk.nuthello.player.Player;
import net.marvk.nuthello.player.PlayerFactory;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Optional;
public final class Game {
private final int sideLength;
private final PlayerFactory blackFactory;
private final Player black;
private final PlayerFactory whiteFactory;
private final Player white;
private Move lastMove;
private final SimpleListProperty<Move> history;
private Disc turn;
private GameResult result;
public Game(final int sideLength, final PlayerFactory blackFactory, final PlayerFactory whiteFactory) {
this.sideLength = sideLength;
this.lastMove = Move.of(Board.initialConfiguration(sideLength), null);
this.blackFactory = blackFactory;
this.whiteFactory = whiteFactory;
this.black = blackFactory.newInstance(Disc.BLACK);
this.white = whiteFactory.newInstance(Disc.WHITE);
this.turn = Disc.BLACK;
this.history = new SimpleListProperty<>(FXCollections.observableArrayList());
history.add(lastMove);
}
public PlayerFactory getPlayerFactory(final Disc disc) {
return disc == Disc.BLACK ? blackFactory : whiteFactory;
}
private Player getPlayer(final Disc disc) {
return disc == Disc.BLACK ? black : white;
}
public Board getBoard() {
return lastMove.getBoard();
}
public Optional<GameResult> getResult() {
return Optional.ofNullable(result);
}
public int getNumberOfDiscs(final Disc disc) {
return getBoard().discCount(disc);
}
public SimpleListProperty<Move> getHistory() {
return history;
}
public synchronized boolean hasNextMove() {
return result == null;
}
/**
* @return the board after the next move has been executed
*
* @throws NoSuchElementException if the game is finished ({@link Game#hasNextMove()} returns {@code false}) and no further move can be made
*/
public synchronized Move nextMove() {
if (!hasNextMove()) {
throw new NoSuchElementException("can not perform next move, game has ended");
}
final List<Move> validMoves = getBoard().getValidMoves(turn);
final Player player = getPlayer(turn);
final Point play = player.play(lastMove);
final Optional<Board> potentialNewBoard = validMoves.stream()
.filter(move -> move.getPoint().equals(play))
.findAny()
.map(Move::getBoard);
if (potentialNewBoard.isPresent()) {
lastMove = Move.of(potentialNewBoard.get(), play);
history.add(lastMove);
turn = turn.opponent();
final Optional<GameResult> gameResult = getBoard().findGameResult(blackFactory, whiteFactory);
gameResult.ifPresent(result -> this.result = result);
} else {
System.err.println(turn + " tried to play invalid move: " + play);
result = new GameResult(
getBoard().discCount(Disc.BLACK),
getBoard().discCount(Disc.WHITE),
blackFactory,
whiteFactory,
turn.opponent(),
getBoard(),
EndCondition.INVALID_PLAY
);
}
return lastMove;
}
public int getSideLength() {
return sideLength;
}
public Disc getTurn() {
return turn;
}
@Override
public String toString() {
return getBoard().toString();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment