Introduce Model and ViewModel factories, Extract interfaces out of models
Replace some duplicated classnames with var keyword Fix a hierarchy violation in the view class
This commit is contained in:
parent
2cfa7130fc
commit
016d6db839
@ -1,7 +1,8 @@
|
|||||||
package de.icaotix.ultimatetictactoe;
|
package de.icaotix.ultimatetictactoe;
|
||||||
|
|
||||||
|
import de.icaotix.ultimatetictactoe.model.ModelFactory;
|
||||||
import de.icaotix.ultimatetictactoe.view.UltimateTicTacToeView;
|
import de.icaotix.ultimatetictactoe.view.UltimateTicTacToeView;
|
||||||
import de.icaotix.ultimatetictactoe.viewmodel.UltimateTicTacToePanelViewModel;
|
import de.icaotix.ultimatetictactoe.viewmodel.ViewModelFactory;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
|
|
||||||
@ -9,7 +10,11 @@ public class Main {
|
|||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
SwingUtilities.invokeLater(() -> {
|
SwingUtilities.invokeLater(() -> {
|
||||||
final UltimateTicTacToePanelViewModel ultimateTicTacToePanelViewModel = new UltimateTicTacToePanelViewModel();
|
|
||||||
|
ModelFactory modelFactory = new ModelFactory();
|
||||||
|
ViewModelFactory viewModelFactory = new ViewModelFactory(modelFactory);
|
||||||
|
|
||||||
|
final var ultimateTicTacToePanelViewModel = viewModelFactory.getUltimateTicTacToePanelViewModel();
|
||||||
new UltimateTicTacToeView(ultimateTicTacToePanelViewModel);
|
new UltimateTicTacToeView(ultimateTicTacToePanelViewModel);
|
||||||
ultimateTicTacToePanelViewModel.prepareNextMove();
|
ultimateTicTacToePanelViewModel.prepareNextMove();
|
||||||
});
|
});
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
package de.icaotix.ultimatetictactoe.model;
|
||||||
|
|
||||||
|
import de.icaotix.ultimatetictactoe.model.definitions.CellState;
|
||||||
|
import de.icaotix.ultimatetictactoe.model.definitions.GameState;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface ITicTacToeGame {
|
||||||
|
void setCellState(int cell, CellState state);
|
||||||
|
|
||||||
|
CellState[] getCells();
|
||||||
|
|
||||||
|
List<Integer> getAvailableFields();
|
||||||
|
|
||||||
|
boolean isFinished();
|
||||||
|
|
||||||
|
GameState getState();
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package de.icaotix.ultimatetictactoe.model;
|
||||||
|
|
||||||
|
import de.icaotix.ultimatetictactoe.model.definitions.GameState;
|
||||||
|
import de.icaotix.ultimatetictactoe.model.definitions.Player;
|
||||||
|
|
||||||
|
public interface IUltimateTicTacToe {
|
||||||
|
ITicTacToeGame getSubGame(int id);
|
||||||
|
|
||||||
|
int getActiveField();
|
||||||
|
|
||||||
|
Player getCurrentPlayer();
|
||||||
|
|
||||||
|
GameState getGameState();
|
||||||
|
|
||||||
|
void doPlayerMove(int cell);
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
package de.icaotix.ultimatetictactoe.model;
|
||||||
|
|
||||||
|
public class ModelFactory {
|
||||||
|
|
||||||
|
private final UltimateTicTacToe ultimateTicTacToe;
|
||||||
|
|
||||||
|
public ModelFactory() {
|
||||||
|
this.ultimateTicTacToe = new UltimateTicTacToe();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IUltimateTicTacToe getUltimateTicTacToe() {
|
||||||
|
return ultimateTicTacToe;
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +0,0 @@
|
|||||||
package de.icaotix.ultimatetictactoe.model;
|
|
||||||
|
|
||||||
public enum Player {
|
|
||||||
X,
|
|
||||||
O
|
|
||||||
}
|
|
@ -1,11 +1,14 @@
|
|||||||
package de.icaotix.ultimatetictactoe.model;
|
package de.icaotix.ultimatetictactoe.model;
|
||||||
|
|
||||||
|
import de.icaotix.ultimatetictactoe.model.definitions.CellState;
|
||||||
|
import de.icaotix.ultimatetictactoe.model.definitions.GameState;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class TicTacToeGame {
|
public class TicTacToeGame implements ITicTacToeGame {
|
||||||
|
|
||||||
public static final Integer[][] winningCombinations = new Integer[][]{
|
public static final Integer[][] winningCombinations = new Integer[][]{
|
||||||
{0, 1, 2},
|
{0, 1, 2},
|
||||||
@ -27,6 +30,22 @@ public class TicTacToeGame {
|
|||||||
this.state = GameState.RUNNING;
|
this.state = GameState.RUNNING;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DEBUG
|
||||||
|
public static void printField(ITicTacToeGame game) {
|
||||||
|
final var cells = game.getCells();
|
||||||
|
System.out.println("--------------CURRENT STATE--------------");
|
||||||
|
for (int i = 0; i < cells.length; i++) {
|
||||||
|
System.out.print(cells[i] + " ");
|
||||||
|
if ((i + 1) % 3 == 0) {
|
||||||
|
System.out.println();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
System.out.println("FREE: " + game.getAvailableFields());
|
||||||
|
System.out.println("STATE: " + game.getState());
|
||||||
|
System.out.println("IS FINISHED: " + game.isFinished());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void setCellState(int cell, CellState state) {
|
public void setCellState(int cell, CellState state) {
|
||||||
if (this.state != GameState.RUNNING) return;
|
if (this.state != GameState.RUNNING) return;
|
||||||
if (this.cells[cell] == CellState.EMPTY) {
|
if (this.cells[cell] == CellState.EMPTY) {
|
||||||
@ -35,10 +54,12 @@ public class TicTacToeGame {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public CellState[] getCells() {
|
public CellState[] getCells() {
|
||||||
return cells;
|
return cells;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public List<Integer> getAvailableFields() {
|
public List<Integer> getAvailableFields() {
|
||||||
final LinkedList<Integer> emptyFields = new LinkedList<>();
|
final LinkedList<Integer> emptyFields = new LinkedList<>();
|
||||||
for (int i = 0; i < this.cells.length; i++) {
|
for (int i = 0; i < this.cells.length; i++) {
|
||||||
@ -49,17 +70,19 @@ public class TicTacToeGame {
|
|||||||
return emptyFields;
|
return emptyFields;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean isFinished() {
|
public boolean isFinished() {
|
||||||
return this.state != GameState.RUNNING;
|
return this.state != GameState.RUNNING;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public GameState getState() {
|
public GameState getState() {
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateGameState() {
|
private void updateGameState() {
|
||||||
for (Integer[] winningCombination : winningCombinations) {
|
for (Integer[] winningCombination : winningCombinations) {
|
||||||
final HashSet<CellState> interestingStates = new HashSet<>();
|
final var interestingStates = new HashSet<CellState>();
|
||||||
interestingStates.add(this.cells[winningCombination[0]]);
|
interestingStates.add(this.cells[winningCombination[0]]);
|
||||||
interestingStates.add(this.cells[winningCombination[1]]);
|
interestingStates.add(this.cells[winningCombination[1]]);
|
||||||
interestingStates.add(this.cells[winningCombination[2]]);
|
interestingStates.add(this.cells[winningCombination[2]]);
|
||||||
@ -77,19 +100,4 @@ public class TicTacToeGame {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DEBUG
|
|
||||||
public static void printField(TicTacToeGame game) {
|
|
||||||
final CellState[] cells = game.getCells();
|
|
||||||
System.out.println("--------------CURRENT STATE--------------");
|
|
||||||
for (int i = 0; i < cells.length; i++) {
|
|
||||||
System.out.print(cells[i] + " ");
|
|
||||||
if ((i + 1) % 3 == 0) {
|
|
||||||
System.out.println();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
System.out.println("FREE: " + game.getAvailableFields());
|
|
||||||
System.out.println("STATE: " + game.getState());
|
|
||||||
System.out.println("IS FINISHED: " + game.isFinished());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,22 @@
|
|||||||
package de.icaotix.ultimatetictactoe.model;
|
package de.icaotix.ultimatetictactoe.model;
|
||||||
|
|
||||||
|
import de.icaotix.ultimatetictactoe.model.definitions.CellState;
|
||||||
|
import de.icaotix.ultimatetictactoe.model.definitions.GameState;
|
||||||
|
import de.icaotix.ultimatetictactoe.model.definitions.Player;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
|
||||||
public class UltimateTicTacToe {
|
public class UltimateTicTacToe implements IUltimateTicTacToe {
|
||||||
|
|
||||||
private final TicTacToeGame[] subGames;
|
private final ITicTacToeGame[] subGames;
|
||||||
private final GameState[] masterGameStates;
|
private final GameState[] masterGameStates;
|
||||||
private Player currentPlayer;
|
private Player currentPlayer;
|
||||||
private int activeField;
|
private int activeField;
|
||||||
private GameState gameState;
|
private GameState gameState;
|
||||||
|
|
||||||
public UltimateTicTacToe() {
|
public UltimateTicTacToe() {
|
||||||
this.subGames = new TicTacToeGame[9];
|
this.subGames = new ITicTacToeGame[9];
|
||||||
for (int i = 0; i < this.subGames.length; i++) {
|
for (int i = 0; i < this.subGames.length; i++) {
|
||||||
this.subGames[i] = new TicTacToeGame();
|
this.subGames[i] = new TicTacToeGame();
|
||||||
}
|
}
|
||||||
@ -25,26 +29,31 @@ public class UltimateTicTacToe {
|
|||||||
this.gameState = GameState.RUNNING;
|
this.gameState = GameState.RUNNING;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TicTacToeGame getSubGame(int id) {
|
@Override
|
||||||
|
public ITicTacToeGame getSubGame(int id) {
|
||||||
return this.subGames[id];
|
return this.subGames[id];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int getActiveField() {
|
public int getActiveField() {
|
||||||
return activeField;
|
return activeField;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public Player getCurrentPlayer() {
|
public Player getCurrentPlayer() {
|
||||||
return this.currentPlayer;
|
return this.currentPlayer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public GameState getGameState() {
|
public GameState getGameState() {
|
||||||
return gameState;
|
return gameState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void doPlayerMove(int cell) {
|
public void doPlayerMove(int cell) {
|
||||||
if (!getSubGame(this.activeField).getAvailableFields().contains(cell)) return;
|
if (!getSubGame(this.activeField).getAvailableFields().contains(cell)) return;
|
||||||
|
|
||||||
CellState nextCellState = this.currentPlayer == Player.X ? CellState.X : CellState.O;
|
var nextCellState = this.currentPlayer == Player.X ? CellState.X : CellState.O;
|
||||||
getSubGame(this.activeField).setCellState(cell, nextCellState);
|
getSubGame(this.activeField).setCellState(cell, nextCellState);
|
||||||
|
|
||||||
this.masterGameStates[this.activeField] = getSubGame(this.activeField).getState();
|
this.masterGameStates[this.activeField] = getSubGame(this.activeField).getState();
|
||||||
@ -60,7 +69,7 @@ public class UltimateTicTacToe {
|
|||||||
|
|
||||||
private void updateGameState() {
|
private void updateGameState() {
|
||||||
for (Integer[] winningCombination : TicTacToeGame.winningCombinations) {
|
for (Integer[] winningCombination : TicTacToeGame.winningCombinations) {
|
||||||
final HashSet<GameState> interestingStates = new HashSet<>();
|
final var interestingStates = new HashSet<GameState>();
|
||||||
interestingStates.add(this.masterGameStates[winningCombination[0]]);
|
interestingStates.add(this.masterGameStates[winningCombination[0]]);
|
||||||
interestingStates.add(this.masterGameStates[winningCombination[1]]);
|
interestingStates.add(this.masterGameStates[winningCombination[1]]);
|
||||||
interestingStates.add(this.masterGameStates[winningCombination[2]]);
|
interestingStates.add(this.masterGameStates[winningCombination[2]]);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package de.icaotix.ultimatetictactoe.model;
|
package de.icaotix.ultimatetictactoe.model.definitions;
|
||||||
|
|
||||||
public enum CellState {
|
public enum CellState {
|
||||||
X("X"),
|
X("X"),
|
@ -1,4 +1,4 @@
|
|||||||
package de.icaotix.ultimatetictactoe.model;
|
package de.icaotix.ultimatetictactoe.model.definitions;
|
||||||
|
|
||||||
public enum GameState {
|
public enum GameState {
|
||||||
X_WON("X won"),
|
X_WON("X won"),
|
@ -0,0 +1,6 @@
|
|||||||
|
package de.icaotix.ultimatetictactoe.model.definitions;
|
||||||
|
|
||||||
|
public enum Player {
|
||||||
|
X,
|
||||||
|
O
|
||||||
|
}
|
@ -1,6 +1,5 @@
|
|||||||
package de.icaotix.ultimatetictactoe.view;
|
package de.icaotix.ultimatetictactoe.view;
|
||||||
|
|
||||||
import de.icaotix.ultimatetictactoe.model.Player;
|
|
||||||
import de.icaotix.ultimatetictactoe.viewmodel.TicTacToePanelViewModel;
|
import de.icaotix.ultimatetictactoe.viewmodel.TicTacToePanelViewModel;
|
||||||
import de.icaotix.ultimatetictactoe.viewmodel.UltimateTicTacToePanelViewModel;
|
import de.icaotix.ultimatetictactoe.viewmodel.UltimateTicTacToePanelViewModel;
|
||||||
|
|
||||||
@ -53,11 +52,7 @@ public class UltimateTicTacToeView extends JFrame {
|
|||||||
this.getContentPane().repaint();
|
this.getContentPane().repaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCurrentPlayer(Player player) {
|
public void setCurrentPlayer(String playerText) {
|
||||||
if (player == Player.O) {
|
this.currentPlayerLabel.setText(playerText);
|
||||||
this.currentPlayerLabel.setText("Current player: O");
|
|
||||||
} else if (player == Player.X) {
|
|
||||||
this.currentPlayerLabel.setText("Current player: X");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,27 +1,25 @@
|
|||||||
package de.icaotix.ultimatetictactoe.viewmodel;
|
package de.icaotix.ultimatetictactoe.viewmodel;
|
||||||
|
|
||||||
|
|
||||||
import de.icaotix.ultimatetictactoe.model.GameState;
|
import de.icaotix.ultimatetictactoe.model.IUltimateTicTacToe;
|
||||||
import de.icaotix.ultimatetictactoe.model.Player;
|
import de.icaotix.ultimatetictactoe.model.ModelFactory;
|
||||||
import de.icaotix.ultimatetictactoe.model.TicTacToeGame;
|
import de.icaotix.ultimatetictactoe.model.definitions.GameState;
|
||||||
import de.icaotix.ultimatetictactoe.model.UltimateTicTacToe;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
public class UltimateTicTacToePanelViewModel {
|
public class UltimateTicTacToePanelViewModel {
|
||||||
|
|
||||||
private final TicTacToePanelViewModel[] subGameViewModels;
|
private final TicTacToePanelViewModel[] subGameViewModels;
|
||||||
private final UltimateTicTacToe ultimateTicTacToe;
|
private final IUltimateTicTacToe ultimateTicTacToe;
|
||||||
private Consumer<String> gameResultCallback;
|
private Consumer<String> gameResultCallback;
|
||||||
private Consumer<Player> currentPlayerCallback;
|
private Consumer<String> currentPlayerCallback;
|
||||||
|
|
||||||
public UltimateTicTacToePanelViewModel() {
|
public UltimateTicTacToePanelViewModel(ModelFactory modelFactory, ViewModelFactory viewModelFactory) {
|
||||||
this.subGameViewModels = new TicTacToePanelViewModel[9];
|
this.subGameViewModels = new TicTacToePanelViewModel[9];
|
||||||
for (int i = 0; i < this.subGameViewModels.length; i++) {
|
for (int i = 0; i < this.subGameViewModels.length; i++) {
|
||||||
this.subGameViewModels[i] = new TicTacToePanelViewModel(this);
|
this.subGameViewModels[i] = viewModelFactory.getTicTacToePanelViewModel(this);
|
||||||
}
|
}
|
||||||
this.ultimateTicTacToe = new UltimateTicTacToe();
|
this.ultimateTicTacToe = modelFactory.getUltimateTicTacToe();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void prepareNextMove() {
|
public void prepareNextMove() {
|
||||||
@ -35,15 +33,16 @@ public class UltimateTicTacToePanelViewModel {
|
|||||||
}
|
}
|
||||||
// Setup next move
|
// Setup next move
|
||||||
final int fieldId = this.ultimateTicTacToe.getActiveField();
|
final int fieldId = this.ultimateTicTacToe.getActiveField();
|
||||||
final List<Integer> availableFields = this.ultimateTicTacToe.getSubGame(fieldId).getAvailableFields();
|
final var availableFields = this.ultimateTicTacToe.getSubGame(fieldId).getAvailableFields();
|
||||||
this.subGameViewModels[fieldId].activate(availableFields);
|
this.subGameViewModels[fieldId].activate(availableFields);
|
||||||
this.currentPlayerCallback.accept(this.ultimateTicTacToe.getCurrentPlayer());
|
this.currentPlayerCallback.accept("Current player: "
|
||||||
|
+ this.ultimateTicTacToe.getCurrentPlayer().name());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onCellClicked(int cell) {
|
public void onCellClicked(int cell) {
|
||||||
final int oldActiveGameId = this.ultimateTicTacToe.getActiveField();
|
final int oldActiveGameId = this.ultimateTicTacToe.getActiveField();
|
||||||
final TicTacToePanelViewModel oldActiveGameViewModel = this.subGameViewModels[oldActiveGameId];
|
final var oldActiveGameViewModel = this.subGameViewModels[oldActiveGameId];
|
||||||
final TicTacToeGame oldActiveGame = this.ultimateTicTacToe.getSubGame(oldActiveGameId);
|
final var oldActiveGame = this.ultimateTicTacToe.getSubGame(oldActiveGameId);
|
||||||
oldActiveGameViewModel.deactivate();
|
oldActiveGameViewModel.deactivate();
|
||||||
|
|
||||||
this.ultimateTicTacToe.doPlayerMove(cell);
|
this.ultimateTicTacToe.doPlayerMove(cell);
|
||||||
@ -67,7 +66,7 @@ public class UltimateTicTacToePanelViewModel {
|
|||||||
this.gameResultCallback = gameResultCallback;
|
this.gameResultCallback = gameResultCallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCurrentPlayerCallback(Consumer<Player> currentPlayerCallback) {
|
public void setCurrentPlayerCallback(Consumer<String> currentPlayerCallback) {
|
||||||
this.currentPlayerCallback = currentPlayerCallback;
|
this.currentPlayerCallback = currentPlayerCallback;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,20 @@
|
|||||||
|
package de.icaotix.ultimatetictactoe.viewmodel;
|
||||||
|
|
||||||
|
import de.icaotix.ultimatetictactoe.model.ModelFactory;
|
||||||
|
|
||||||
|
public class ViewModelFactory {
|
||||||
|
|
||||||
|
private final ModelFactory modelFactory;
|
||||||
|
|
||||||
|
public ViewModelFactory(ModelFactory modelFactory) {
|
||||||
|
this.modelFactory = modelFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UltimateTicTacToePanelViewModel getUltimateTicTacToePanelViewModel() {
|
||||||
|
return new UltimateTicTacToePanelViewModel(this.modelFactory, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TicTacToePanelViewModel getTicTacToePanelViewModel(UltimateTicTacToePanelViewModel ultimateTicTacToePanelViewModel) {
|
||||||
|
return new TicTacToePanelViewModel(ultimateTicTacToePanelViewModel);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user