Commit c9d700d4 authored by Anna Maria Eilertsen's avatar Anna Maria Eilertsen
Browse files

abstracted out gameplay and types for players

parent d5a54627
......@@ -20,8 +20,10 @@ import javax.swing.JPanel;
import inf101.v20.lab4.grid.Grid;
import inf101.v20.sem2.mnkgames.MNKGame;
import inf101.v20.sem2.mnkgames.MNKGame.Piece;
import inf101.v20.sem2.mnkgames.AI.AIPlayer;
import inf101.v20.sem2.mnkgames.AI.SimpleStatelessAIPlayer;
import inf101.v20.sem2.mnkgames.gameplay.TwoPlayerGame;
import inf101.v20.sem2.mnkgames.player.HumanPlayer;
import inf101.v20.sem2.mnkgames.player.AI.AIPlayer;
import inf101.v20.sem2.mnkgames.player.AI.SimpleAIPlayer;
/**
*
......@@ -47,22 +49,18 @@ s * Initializes a JFrame in which we place the game
}
// Fields
private MNKGame game;
private JButton playConnectFourButton;
private JButton playTicTacToeButton;
private JLabel statusMessage;
private Grid<GamePanel> clickablePanels;
private GameSupplier gameSupplier;
private String player1_screenName;
private String player2_screenName;
private boolean multiplayer;
private AIPlayer ai;
private TwoPlayerGame helperGame;
public MNKGameGUI(GameSupplier gameSupplier) {
this.gameSupplier = gameSupplier;
//initialize to default values
this.game = gameSupplier.getTicTacToeGame();
this.ai = new SimpleStatelessAIPlayer();
helperGame = new TwoPlayerGame(gameSupplier.getTicTacToeGame());
}
/*
......@@ -83,23 +81,13 @@ s * Initializes a JFrame in which we place the game
}
private void reset(MNKGame game) {
this.game = game;
this.helperGame = helperGame.getNewGame(game);
updateMessage();
removeAll();
initialize();
this.updateUI();
}
/**
* Children panels can call this method after being clicked.
*/
private void registerClick() {
endOfTurn();
if(!multiplayer) {
AIPlayerTurn();
}
}
/**
* Should be called after a click to update the UI to reflect the current game state
*/
......@@ -107,25 +95,19 @@ s * Initializes a JFrame in which we place the game
clickablePanels.forEach(item -> item.updateToGame());
updateMessage();
MNKGameGUI.super.updateUI();
if(game.hasWinner()) {
System.out.println("Winner!");
if(!helperGame.hasPossibleMoves()) {
stop();
}
}
private void AIPlayerTurn() {
ai.makeMove(game);
endOfTurn();
}
/**
* Helper method to control the status message
*/
private void updateMessage() {
if (game.hasWinner())
statusMessage.setText("The game is over! The winner is " + getPlayerName(game.getWinner()));
else if(game.hasPossibleMoves()) {
statusMessage.setText("Next move from " + getPlayerName(game.getCurrent()));
if (helperGame.hasWinner())
statusMessage.setText("The game is over! The winner is " + helperGame.getWinner());
else if(helperGame.hasPossibleMoves()) {
statusMessage.setText("Next move from " + helperGame.getCurrentPlayer());
}else{
statusMessage.setText("The game is over! No one won.");
}
......@@ -135,7 +117,6 @@ s * Initializes a JFrame in which we place the game
* Should be called once a game stops
*/
private void stop() {
updateMessage();
clickablePanels.forEach(item -> item.removeMouseListeners());
}
......@@ -153,34 +134,17 @@ s * Initializes a JFrame in which we place the game
* @param pieceAt The piece to be drawn
* @return The color that this GUI implementation associates with the provided piece
*/
protected Color getColor(Piece pieceAt) {
protected Color pieceToColor(Piece pieceAt) {
switch(pieceAt) {
case BLACK : return Color.getHSBColor(90, 65, 20.3f);
case WHITE : return Color.getHSBColor(308, 26, 34);
default: return Color.WHITE;
}
}
/**
* Maps from Piece values to players
*
* @param pieceAt The piece to be drawn
* @return The player name
*/
private String getPlayerName(Piece pieceAt) {
if(pieceAt.equals(Piece.NONE))
return "No Player";
if(pieceAt.equals(MNKGame.getStartColor())) {
return player1_screenName;
}
else {
return player2_screenName;
}
}
@Override
public Dimension getPreferredSize() {
return new Dimension(100*game.getHeight(), 100*game.getWidth());
return new Dimension(100*helperGame.height(), 100*helperGame.width());
}
/**
......@@ -207,7 +171,7 @@ s * Initializes a JFrame in which we place the game
}
private void updateToGame() {
setBackground(getColor(game.getPieceAt(x, y)));
setBackground(pieceToColor(helperGame.getPieceAt(x, y)));
if(filled()) {
makeUnClickable();
}
......@@ -218,18 +182,23 @@ s * Initializes a JFrame in which we place the game
}
private boolean filled() {
return game.getPieceAt(x, y) != Piece.NONE;
return helperGame.getPieceAt(x, y) != Piece.NONE;
}
public void click() {
game.putPieceAt(x, y);
registerClick();
helperGame.takeTurnforHumanPlayer(x, y);
endOfTurn();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(3, 3);
}
@Override
public Color getBackground() {
return pieceToColor(helperGame.getPieceAt(x, y));
}
}
/**
......@@ -238,14 +207,13 @@ s * Initializes a JFrame in which we place the game
public void initialize() {
setLayout(new BorderLayout());
JPanel p = new JPanel();
p.setLayout(new GridLayout(game.getHeight(), game.getWidth()));
p.setLayout(new GridLayout(helperGame.height(), helperGame.width()));
p.setBorder(BorderFactory.createEmptyBorder(50, 50, 50, 50));
this.clickablePanels = new Grid<GamePanel>(game.getWidth(), game.getHeight(), null);
for(int y = 0; y<game.getHeight(); y++) {
for (int x=0; x<game.getWidth(); x++) {
this.clickablePanels = new Grid<GamePanel>(helperGame.width(), helperGame.height(), null);
for(int y = 0; y<helperGame.height(); y++) {
for (int x=0; x<helperGame.width(); x++) {
GamePanel pan = new GamePanel(x, y);
pan.setEnabled(true);
pan.setBackground(getColor(game.getPieceAt(x, y)));
pan.setBorder(BorderFactory.createLineBorder(Color.GRAY));
pan.addMouseListener(new BoxListener()); // add a mouse listener to make the panels clickable
p.add(pan);
......@@ -277,7 +245,7 @@ s * Initializes a JFrame in which we place the game
playConnectFourButton.setText("Connect Four");
statusMessage = new JLabel();
statusMessage.setText("Welcome to this game! " + player1_screenName + " begins.");
statusMessage.setText("Welcome to this game! " + helperGame.player1() + " begins.");
JPanel buttons = new JPanel();
buttons.setLayout(new BorderLayout());
......@@ -292,12 +260,12 @@ s * Initializes a JFrame in which we place the game
private void collectPlayerInfo() {
JFrame frame = new JFrame();
multiplayer = promptMultiplayer(frame);
player1_screenName = promptPlayerName(frame, "Player 1");
helperGame.setHumanPlayer1(promptPlayerName(frame, "Player 1"));
if(multiplayer) {
player2_screenName = promptPlayerName(frame, "Player 2");
helperGame.setHumanPlayer2(promptPlayerName(frame, "Player 2"));
}
else {
player2_screenName = "AI player";
helperGame.setAIPlayer2();
}
}
......
package inf101.v20.sem2.mnkgames.gameplay;
import inf101.v20.sem2.mnkgames.MNKGame;
import inf101.v20.sem2.mnkgames.MNKGame.Piece;
import inf101.v20.sem2.mnkgames.player.HumanPlayer;
import inf101.v20.sem2.mnkgames.player.Player;
import inf101.v20.sem2.mnkgames.player.AI.AIPlayer;
import inf101.v20.sem2.mnkgames.player.AI.SimpleAIPlayer;
/**
* Class that controls the game play with two players and a MNKGame
*
* Supports autonomous turns for AI player
*
* @author Anna Eilertsen - anna.eilertsen@uib.no
*
*/
public class TwoPlayerGame {
private Player p1, p2;
private MNKGame game;
private Player currentPlayer;
public TwoPlayerGame() {
}
public TwoPlayerGame(MNKGame game) {
this.game = game;
}
public TwoPlayerGame(MNKGame game, Player player1, Player player2) {
this.p1 = player1;
this.p2 = player2;
this.game = game;
initializeCurrentPlayer();
}
public void setGame(MNKGame game) {
if(game!=null) {
throw new IllegalStateException("Game is already initialized");
}
this.game = game;
}
public void setHumanPlayer1(String name) {
if(p1!=null) {
throw new IllegalStateException("Player 1 is already initialized");
}
this.p1 = new HumanPlayer(name, MNKGame.getStartColor());
}
public void setHumanPlayer2(String name) {
if(p2!=null) {
throw new IllegalStateException("Player 2 is already initialized");
}
this.p2 = new HumanPlayer(name, MNKGame.getStartColor().next());
}
public void setAIPlayer2() {
if(p2!=null) {
throw new IllegalStateException("Player 2 is already initialized");
}
this.p2 = new SimpleAIPlayer(MNKGame.getStartColor().next());
}
private void initializeCurrentPlayer() {
currentPlayer = p1;
}
private Player next() {
return currentPlayer == p1 ? p2 : p1;
}
public void checkComplete() {
if(p1 == null || p2 == null || game == null) {
throw new IllegalStateException("Cannot use object before it is completely instanciated");
}
}
public String player1() {
return p1.name();
}
public String getPlayer2() {
return p2.name();
}
public String getCurrentPlayer() {
return currentPlayer.name();
}
public boolean hasWinner() {
return game.hasWinner();
}
public String getWinner() {
return getPlayerFromPiece(game.getWinner());
}
public boolean hasPossibleMoves() {
return !game.hasWinner() && game.hasPossibleMoves();
}
public Piece getPieceAt(int x, int y) {
return game.getPieceAt(x, y);
}
public String getPlayerFromPiece(Piece piece) {
if(piece.equals(Piece.NONE))
return "No Player";
if(p1.getColor()==piece)
return p1.name();
else
return p2.name();
}
public int height() {
return game.getHeight();
}
public int width() {
return game.getWidth();
}
public void takeTurnforHumanPlayer(int x, int y) {
checkComplete();
if(currentPlayer==null) {
initializeCurrentPlayer();
}
if(! (currentPlayer instanceof HumanPlayer))
throw new IllegalStateException("This method is only supported for AI players");
HumanPlayer pl = (HumanPlayer) currentPlayer;
pl.makeMove(game, x, y);
currentPlayer = next();
if(currentPlayer instanceof AIPlayer) {
takeTurnForAI();
}
}
private void takeTurnForAI() {
checkComplete();
if(currentPlayer==null) {
initializeCurrentPlayer();
}
if(! (currentPlayer instanceof AIPlayer))
throw new IllegalStateException("This method is only supported for AI players");
AIPlayer ai = (AIPlayer) currentPlayer;
ai.makeMove(game);
currentPlayer = next();
}
public TwoPlayerGame getNewGame(MNKGame game) {
return new TwoPlayerGame(game, p1, p2);
}
}
package inf101.v20.sem2.mnkgames.AI;
package inf101.v20.sem2.mnkgames.player.AI;
import inf101.v20.sem2.mnkgames.MNKGame;
import inf101.v20.sem2.mnkgames.player.Player;
public interface AIPlayer {
public interface AIPlayer extends Player{
public void makeMove(MNKGame game);
......
package inf101.v20.sem2.mnkgames.AI;
package inf101.v20.sem2.mnkgames.player.AI;
import inf101.v20.sem2.mnkgames.MNKGame;
import inf101.v20.sem2.mnkgames.player.AbstractPlayer;
public class SimpleStatelessAIPlayer implements AIPlayer{
public class SimpleAIPlayer extends AbstractPlayer implements AIPlayer{
public SimpleStatelessAIPlayer() {
public SimpleAIPlayer(String name, MNKGame.Piece color) {
super(name, color);
}
public SimpleAIPlayer(MNKGame.Piece color) {
super("AIPlayer", color);
}
@Override
public void makeMove(MNKGame game) {
for (int i = 0; i < game.getWidth(); i++) {
for(int j = 0; j < game.getHeight(); j++) {
......
package inf101.v20.sem2.mnkgames.player;
import inf101.v20.sem2.mnkgames.MNKGame;
import inf101.v20.sem2.mnkgames.MNKGame.Piece;
public abstract class AbstractPlayer implements Player{
private final String name;
private final MNKGame.Piece color;
public AbstractPlayer(String name, Piece color) {
this.name = name;
this.color = color;
}
@Override
public String name() {
return name;
}
@Override
public Piece getColor() {
return color;
}
}
\ No newline at end of file
package inf101.v20.sem2.mnkgames.player;
import inf101.v20.sem2.mnkgames.MNKGame;
public class HumanPlayer extends AbstractPlayer{
public HumanPlayer(String name, MNKGame.Piece color) {
super(name, color);
}
}
package inf101.v20.sem2.mnkgames.player;
import inf101.v20.sem2.mnkgames.MNKGame;
public interface Player {
default public void makeMove(MNKGame game, int x, int y) {
game.putPieceAt(x, y);
}
public String name();
public MNKGame.Piece getColor();
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment