Commit 0a460a98 authored by mva021's avatar mva021
Browse files

Updated the Game classes with comments and renamed the FourInRow class

parent 11a093a9
package inf101.v20.sem2.GUI; package inf101.v20.sem2.GUI;
import inf101.v20.sem2.games.Game; import inf101.v20.sem2.games.AbstractGame;
import inf101.v20.sem2.games.TicTacToe; import inf101.v20.sem2.games.TicTacToe;
public class GUIMain { public class GUIMain {
public static void main(String[] args) { public static void main(String[] args) {
Game game = new TicTacToe(GameGUI.getPlayers()); AbstractGame game = new TicTacToe(GameGUI.getPlayers());
MNKGameGUI gameGUI = new MNKGameGUI(game); MNKGameGUI gameGUI = new MNKGameGUI(game);
GameGUI gui = new GameGUI(gameGUI); GameGUI gui = new GameGUI(gameGUI);
} }
......
...@@ -10,8 +10,8 @@ import javax.swing.JFrame; ...@@ -10,8 +10,8 @@ import javax.swing.JFrame;
import javax.swing.JOptionPane; import javax.swing.JOptionPane;
import javax.swing.JPanel; import javax.swing.JPanel;
import inf101.v20.sem2.games.FourinRow; import inf101.v20.sem2.games.FourInRow;
import inf101.v20.sem2.games.Game; import inf101.v20.sem2.games.AbstractGame;
import inf101.v20.sem2.games.MiniMaxPlayer; import inf101.v20.sem2.games.MiniMaxPlayer;
import inf101.v20.sem2.games.Player; import inf101.v20.sem2.games.Player;
import inf101.v20.sem2.games.TicTacToe; import inf101.v20.sem2.games.TicTacToe;
...@@ -75,7 +75,7 @@ public class GameGUI implements ActionListener{ ...@@ -75,7 +75,7 @@ public class GameGUI implements ActionListener{
Iterable<Player> players = getPlayers(); Iterable<Player> players = getPlayers();
frame.remove(gameBoard); frame.remove(gameBoard);
if(e.getSource() == playConnectFourButton) { if(e.getSource() == playConnectFourButton) {
this.gameBoard = new MNKGameGUI(new FourinRow(players)); this.gameBoard = new MNKGameGUI(new FourInRow(players));
} }
if(e.getSource() == playTicTacToeButton) { if(e.getSource() == playTicTacToeButton) {
this.gameBoard = new MNKGameGUI(new TicTacToe(players)); this.gameBoard = new MNKGameGUI(new TicTacToe(players));
...@@ -87,14 +87,14 @@ public class GameGUI implements ActionListener{ ...@@ -87,14 +87,14 @@ public class GameGUI implements ActionListener{
public static Iterable<Player> getPlayers() { public static Iterable<Player> getPlayers() {
ArrayList<Player> players = new ArrayList<Player>(); ArrayList<Player> players = new ArrayList<Player>();
//add player1 //add player1
players.add(new GuiPlayer(Game.piece1)); players.add(new GuiPlayer(AbstractGame.piece1));
//add player2 //add player2
if(promptMultiplayer()) { if(promptMultiplayer()) {
players.add(new GuiPlayer(Game.piece2)); players.add(new GuiPlayer(AbstractGame.piece2));
}else { }else {
//make AI //make AI
//TODO: prompt for level of intelligence in AI player //TODO: prompt for level of intelligence in AI player
players.add(new MiniMaxPlayer(Game.piece2, 5)); players.add(new MiniMaxPlayer(AbstractGame.piece2, 5));
} }
......
...@@ -9,7 +9,7 @@ import java.util.List; ...@@ -9,7 +9,7 @@ import java.util.List;
import javax.swing.JLabel; import javax.swing.JLabel;
import javax.swing.JPanel; import javax.swing.JPanel;
import inf101.v20.sem2.games.Game; import inf101.v20.sem2.games.AbstractGame;
/** /**
* *
...@@ -20,11 +20,11 @@ public class MNKGameGUI extends JPanel{ ...@@ -20,11 +20,11 @@ public class MNKGameGUI extends JPanel{
private static final long serialVersionUID = 8755882090377973497L; private static final long serialVersionUID = 8755882090377973497L;
// Fields // Fields
private Game game; //the game logic private AbstractGame game; //the game logic
private ClickableGrid clickablePanels; //clickable grid for user input private ClickableGrid clickablePanels; //clickable grid for user input
private JLabel statusMessage; //field for displaying message to user private JLabel statusMessage; //field for displaying message to user
public MNKGameGUI(Game game) { public MNKGameGUI(AbstractGame game) {
this.game = game; this.game = game;
game.setGui(this); game.setGui(this);
statusMessage = new JLabel(); statusMessage = new JLabel();
...@@ -44,7 +44,7 @@ public class MNKGameGUI extends JPanel{ ...@@ -44,7 +44,7 @@ public class MNKGameGUI extends JPanel{
validate(); validate();
} }
public void reset(Game newGame) { public void reset(AbstractGame newGame) {
this.game = newGame; this.game = newGame;
this.game.setGui(this); this.game.setGui(this);
//updateMessage(); //updateMessage();
......
...@@ -10,10 +10,11 @@ import inf101.v20.sem2.grid.Location; ...@@ -10,10 +10,11 @@ import inf101.v20.sem2.grid.Location;
/** /**
* A game consists of a GameBoard, and 2 players which each has a piece. * A game consists of a GameBoard, and 2 players which each has a piece.
* Pieces are then placed on the board until a winning, loosing or draw condition * Pieces are then placed on the board until a winning, loosing or draw condition
* @author mva021 *
* @author Martin Vatshelle - martin.vatshelle@uib.no
* *
*/ */
public abstract class Game implements IGame { public abstract class AbstractGame implements IGame {
GameBoard board; GameBoard board;
PlayerList players; PlayerList players;
...@@ -28,7 +29,7 @@ public abstract class Game implements IGame { ...@@ -28,7 +29,7 @@ public abstract class Game implements IGame {
* @param board - The board to play on * @param board - The board to play on
* @param players - The players to play the game * @param players - The players to play the game
*/ */
public Game(GameBoard board, Iterable<Player> players) { public AbstractGame(GameBoard board, Iterable<Player> players) {
this(board); this(board);
for(Player p: players) { for(Player p: players) {
addPlayer(p); addPlayer(p);
...@@ -39,7 +40,7 @@ public abstract class Game implements IGame { ...@@ -39,7 +40,7 @@ public abstract class Game implements IGame {
* Constructor which creates a game without players * Constructor which creates a game without players
* @param board * @param board
*/ */
public Game(GameBoard board) { public AbstractGame(GameBoard board) {
players = new PlayerList(); players = new PlayerList();
this.board = board; this.board = board;
} }
...@@ -218,7 +219,7 @@ public abstract class Game implements IGame { ...@@ -218,7 +219,7 @@ public abstract class Game implements IGame {
* This method checks if the game is over * This method checks if the game is over
* @return * @return
*/ */
protected boolean gameOver() { public boolean gameOver() {
return hasWinner() || isDraw(); return hasWinner() || isDraw();
} }
...@@ -240,11 +241,6 @@ public abstract class Game implements IGame { ...@@ -240,11 +241,6 @@ public abstract class Game implements IGame {
} }
return moves; return moves;
} }
/**
* @return The name of the game
*/
public abstract String getName();
@Override @Override
public GameBoard getGameBoard() { public GameBoard getGameBoard() {
...@@ -271,13 +267,12 @@ public abstract class Game implements IGame { ...@@ -271,13 +267,12 @@ public abstract class Game implements IGame {
} }
/** /**
* This method is needed for the AI players to try out different moves without * Advances the PlayerList until currentPlayer equals the given player.
* actually changing the game. * This can be used for deciding who should be the first player.
* It is also used by the copy method.
* *
* @return * @param player the player which should be the current player
*/ */
public abstract Game copy();
public void setPlayer(Player player) { public void setPlayer(Player player) {
while(player != getCurrentPlayer()) { while(player != getCurrentPlayer()) {
players.nextPlayer(); players.nextPlayer();
......
...@@ -3,17 +3,25 @@ package inf101.v20.sem2.games; ...@@ -3,17 +3,25 @@ package inf101.v20.sem2.games;
import inf101.v20.sem2.grid.GridDirection; import inf101.v20.sem2.grid.GridDirection;
import inf101.v20.sem2.grid.Location; import inf101.v20.sem2.grid.Location;
public class FourinRow extends Game { /**
* This game is played on a 6 x 7 board.
* The players select a column and the placement will be on the lowest
* available row of that column.
*
* @author Martin Vatshelle - martin.vatshelle@uib.no
*
*/
public class FourInRow extends AbstractGame {
public FourinRow() { public FourInRow() {
super(new GameBoard(6, 7)); super(new GameBoard(6, 7));
} }
public FourinRow(Iterable<Player> players) { public FourInRow(Iterable<Player> players) {
super(new GameBoard(6, 7),players); super(new GameBoard(6, 7),players);
} }
public FourinRow(GameBoard board, Iterable<Player> players) { public FourInRow(GameBoard board, Iterable<Player> players) {
super(board,players); super(board,players);
} }
...@@ -68,8 +76,8 @@ public class FourinRow extends Game { ...@@ -68,8 +76,8 @@ public class FourinRow extends Game {
return loc; return loc;
} }
@Override @Override
public Game copy() { public AbstractGame copy() {
Game newGame = new FourinRow(board.copy(),players); AbstractGame newGame = new FourInRow(board.copy(),players);
newGame.setPlayer(getCurrentPlayer()); newGame.setPlayer(getCurrentPlayer());
return newGame; return newGame;
} }
......
...@@ -4,6 +4,12 @@ import java.util.List; ...@@ -4,6 +4,12 @@ import java.util.List;
import inf101.v20.sem2.grid.Location; import inf101.v20.sem2.grid.Location;
/**
* This Interface is used to describe what is needed for playing a Game
*
* @author Martin Vatshelle - martin.vatshelle@uib.no
*
*/
public interface IGame { public interface IGame {
/** /**
...@@ -17,9 +23,18 @@ public interface IGame { ...@@ -17,9 +23,18 @@ public interface IGame {
*/ */
public Iterable<Player> players(); public Iterable<Player> players();
/**
* @return The name of the game
*/
public String getName();
/** /**
* The game has rules for where the players can place. * The game has rules for where the players can place.
* In both TicTacToe and Connect4 it does not matter who the player is, but it might in other games. * In both TicTacToe and Connect4 it does not matter who the player is, but it might in other games.
*
* This is both used to verify that the move a Player returns is valid
* and for the AI to know where it can place.
*
* @param loc - where to place * @param loc - where to place
* @param player - who wants to place * @param player - who wants to place
* @return true if it is a valid move, false otherwise. * @return true if it is a valid move, false otherwise.
...@@ -48,6 +63,9 @@ public interface IGame { ...@@ -48,6 +63,9 @@ public interface IGame {
/** /**
* Will find all the possible moves the current player can make * Will find all the possible moves the current player can make
* This is mainly for the AI to more easily select a move.
* Did not need to be in the Interface, but it might be a handy method to have.
*
* @return list of all possible Locations for next move * @return list of all possible Locations for next move
*/ */
public List<Location> possibleMoves(); public List<Location> possibleMoves();
...@@ -66,7 +84,33 @@ public interface IGame { ...@@ -66,7 +84,33 @@ public interface IGame {
*/ */
public boolean isWinner(Player p); public boolean isWinner(Player p);
/**
* Checks if the game is a draw
* @return true if the game is a draw, false otherwise
*/
public boolean isDraw(); public boolean isDraw();
public abstract Game copy(); /**
* Creates a copy of the game.
*
* This method is needed for the AI players to try out different moves without
* actually changing the game.
*
* @return a copy of the game.
*/
public IGame copy();
/**
* This method is used for testing and by the AI which simulates
* several moves ahead to find the best move.
* @param loc
* @return
*/
public boolean makeMove(Location loc);
/**
* This method
* @return
*/
public boolean gameOver();
} }
...@@ -49,7 +49,7 @@ public class MiniMaxPlayer extends AbstractPlayer { ...@@ -49,7 +49,7 @@ public class MiniMaxPlayer extends AbstractPlayer {
//try each possible strategy //try each possible strategy
for (Location loc : game.possibleMoves()) { for (Location loc : game.possibleMoves()) {
//make a copy of the game and try the move //make a copy of the game and try the move
Game newGame = game.copy(); IGame newGame = game.copy();
newGame.makeMove(loc); //note that this changes the current player in the copy but not the real game newGame.makeMove(loc); //note that this changes the current player in the copy but not the real game
int score = 0; int score = 0;
if(newGame.gameOver() || depth==1) { //No more moves can be made if(newGame.gameOver() || depth==1) { //No more moves can be made
...@@ -81,7 +81,7 @@ public class MiniMaxPlayer extends AbstractPlayer { ...@@ -81,7 +81,7 @@ public class MiniMaxPlayer extends AbstractPlayer {
* @param p * @param p
* @return * @return
*/ */
private int score(Game game, Player p) { private int score(IGame game, Player p) {
if(game.isWinner(p)) { if(game.isWinner(p)) {
return 1; return 1;
} }
...@@ -113,7 +113,8 @@ public class MiniMaxPlayer extends AbstractPlayer { ...@@ -113,7 +113,8 @@ public class MiniMaxPlayer extends AbstractPlayer {
/** /**
* A inner class only to be used by MiniMax player * A inner class only to be used by MiniMax player
* This class keeps track of a move and a score associated with that move * This class keeps track of a move and a score associated with that move
* @author mva021 *
* @author Martin Vatshelle - martin.vatshelle@uib.no
* *
*/ */
class Strategy{ class Strategy{
......
...@@ -4,8 +4,11 @@ import java.util.ArrayList; ...@@ -4,8 +4,11 @@ import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
/** /**
* This class keep track of players and who's turn it is. * This class keep track of players and who's turn it is.
* @author mva021 * In this project that might be overkill since there are only 2 players.
* But I think the code becomes more readable when we have a PlayerList class
*
* @author Martin Vatshelle - martin.vatshelle@uib.no
*/ */
public class PlayerList implements Iterable<Player>{ public class PlayerList implements Iterable<Player>{
...@@ -44,15 +47,23 @@ public class PlayerList implements Iterable<Player>{ ...@@ -44,15 +47,23 @@ public class PlayerList implements Iterable<Player>{
updateIndex(); updateIndex();
} }
/**
* Advances the index to the next in the list, if the end is reached
* the index restarts on the beginning.
*/
private void updateIndex() { private void updateIndex() {
if(currentIndex>=players.size() || currentIndex<0) if(currentIndex>=players.size() || currentIndex<0)
currentIndex = 0; currentIndex = 0;
} }
/** /**
* This method removes a player from the list.
* In this project there is no need to remove a Player.
* But in general one might think of games with more players
* where those who loose the game is removed
* *
* @param index * @param index The index to remove
* @return * @return The Player removed from the PlayerList
*/ */
public Player remove(int index) { public Player remove(int index) {
Player p = players.remove(index); Player p = players.remove(index);
......
package inf101.v20.sem2.games; package inf101.v20.sem2.games;
public class TicTacToe extends Game { /**
* This game is played on a n by n board, normally n = 3.
* The goal is to get 3 in a row.
*
* @author Martin Vatshelle - martin.vatshelle@uib.no
*
*/
public class TicTacToe extends AbstractGame {
/** /**
* Constructor for normal 3x3 TicTacToe * Constructor for normal 3x3 TicTacToe
*/ */
...@@ -39,8 +46,8 @@ public class TicTacToe extends Game { ...@@ -39,8 +46,8 @@ public class TicTacToe extends Game {
} }
@Override @Override
public Game copy() { public TicTacToe copy() {
Game newGame = new TicTacToe(board.copy(),players()); TicTacToe newGame = new TicTacToe(board.copy(),players());
newGame.setPlayer(getCurrentPlayer()); newGame.setPlayer(getCurrentPlayer());
return newGame; return newGame;
} }
......
...@@ -6,7 +6,7 @@ import java.util.Scanner; ...@@ -6,7 +6,7 @@ import java.util.Scanner;
import inf101.v20.sem2.grid.Location; import inf101.v20.sem2.grid.Location;
import inf101.v20.sem2.games.AbstractPlayer; import inf101.v20.sem2.games.AbstractPlayer;
import inf101.v20.sem2.games.FourinRow; import inf101.v20.sem2.games.FourInRow;
import inf101.v20.sem2.games.IGame; import inf101.v20.sem2.games.IGame;
/** /**
...@@ -57,8 +57,8 @@ public class ConsolePlayer extends AbstractPlayer { ...@@ -57,8 +57,8 @@ public class ConsolePlayer extends AbstractPlayer {
@Override @Override
public Location getMove(IGame game) { public Location getMove(IGame game) {
game.getGameBoard().printBoard(); game.getGameBoard().printBoard();
if(game instanceof FourinRow) { if(game instanceof FourInRow) {
return getColumn((FourinRow) game); return getColumn((FourInRow) game);
} }
else else
return getLocation(game); return getLocation(game);
...@@ -67,7 +67,7 @@ public class ConsolePlayer extends AbstractPlayer { ...@@ -67,7 +67,7 @@ public class ConsolePlayer extends AbstractPlayer {
/** /**
* Reads input for the FourInARow game * Reads input for the FourInARow game
*/ */
private Location getColumn(FourinRow game) { private Location getColumn(FourInRow game) {
System.out.println("Player "+this.toString()+" type [Col] to make a move."); System.out.println("Player "+this.toString()+" type [Col] to make a move.");
boolean done = false; boolean done = false;
int col = 0; int col = 0;
......
...@@ -3,7 +3,7 @@ package inf101.v20.sem2.terminal; ...@@ -3,7 +3,7 @@ package inf101.v20.sem2.terminal;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Scanner; import java.util.Scanner;
import inf101.v20.sem2.games.FourinRow; import inf101.v20.sem2.games.FourInRow;
import inf101.v20.sem2.games.IGame; import inf101.v20.sem2.games.IGame;
import inf101.v20.sem2.games.MiniMaxPlayer; import inf101.v20.sem2.games.MiniMaxPlayer;
import inf101.v20.sem2.games.Player; import inf101.v20.sem2.games.Player;
...@@ -42,7 +42,7 @@ public class TerminalMenu { ...@@ -42,7 +42,7 @@ public class TerminalMenu {
break; break;
case 2: case 2:
game = new FourinRow(players); game = new FourInRow(players);
break; break;
default: default:
throw new IllegalArgumentException("Unexpected value: " + choice); throw new IllegalArgumentException("Unexpected value: " + choice);
......
...@@ -14,7 +14,7 @@ class FourinRowTest { ...@@ -14,7 +14,7 @@ class FourinRowTest {
public final static Player player1 = new ConsolePlayer("X", "Martin"); public final static Player player1 = new ConsolePlayer("X", "Martin");
public final static Player player2 = new ConsolePlayer("O", "Laura"); public final static Player player2 = new ConsolePlayer("O", "Laura");
public FourinRow game; public FourInRow game;
public final Random rand = new Random(); public final Random rand = new Random();
@BeforeEach @BeforeEach
...@@ -22,8 +22,8 @@ class FourinRowTest { ...@@ -22,8 +22,8 @@ class FourinRowTest {
game = makeGame(); game = makeGame();
} }
public static FourinRow makeGame() { public static FourInRow makeGame() {
FourinRow game = new FourinRow();