Commit 21d8a62d authored by Son Pham's avatar Son Pham

Homework 2, commplete.

parent fa272f56
/**
* CSCI205 - Software Design and Engineering
* Name: Robert Cowen & Son Pham
*
* Work: homework-2
* Created: Nov 11, 2014, 10:23:41 PM
*/
==============================================
THE GUIDE TO USE THE TIC-TAC-TOE GAME PROPERLY
==============================================
1. To change the game mode and the player, select them in the drop down box and click "New Game"
2. AI can only be trained when you are in Player vs. Computer Mode and have Computer Type set as AI
3. Try to get a row of 3 to win the game
\ No newline at end of file
/**
* CSCI205 - Software Design and Engineering
* Name: Robert Cowen & Son Pham
*
* Work: homework-2
* Created: Nov 11, 2014, 10:23:41 PM
*/
==============================================
THE GUIDE TO USE THE TIC-TAC-TOE GAME PROPERLY
==============================================
1. To change the game mode and the player, select them in the drop down box and click "New Game"
2. AI can only be trained when you are in Player vs. Computer Mode and have Computer Type set as AI
3. Try to get a row of 3 to win the game
\ No newline at end of file
......@@ -8,8 +8,8 @@
import java.awt.EventQueue;
import view.TTTMainView;
import controller.TTTController;
import view.TTTMainView;
/**
* @author skp011
......
......@@ -171,13 +171,7 @@ public class TTTController implements ActionListener {
}
if (theGame.getCurrentPlayer() instanceof AutoPlayable) {
int pos = ((AutoPlayable) theGame.getCurrentPlayer()).getMove();
while (!theGame.getTheBoard().isEmpty(pos)) {
pos = ((AutoPlayable) theGame.getCurrentPlayer()).getMove();
}
theView.getButton(pos).doClick();
if (theGame.getAIPlayer() instanceof AIPlayer) {
((AIPlayer) theGame.getAIPlayer()).createNode(pos);
}
}
}
updateNextLabel();
......@@ -201,44 +195,61 @@ public class TTTController implements ActionListener {
*/
@Override
public void actionPerformed(ActionEvent evt) {
if (theGame.getAIPlayer() instanceof AIPlayer) {
boolean check = ((AIPlayer) theGame.getAIPlayer()).getCurrentNode() == ((AIPlayer) theGame.getAIPlayer()).getHeadNode();
System.out.println("Check head node:" + check);
}
/** Make a JButton instance that stores the event source */
JButton btnClicked = (JButton) evt.getSource();
/** If button click is New Game */
if (btnClicked == theView.getControlPanel().getBtnNewGame()) {
JComboBox<GameType> gameTypeBox = theView.getPlayerPanel()
.getGameChoices();
JComboBox<GameType> gameTypeBox = theView.getPlayerPanel().getGameChoices();
theGame.setGameType((GameType) gameTypeBox.getSelectedItem());
JComboBox<ComputerType> compTypeBox = theView.getPlayerPanel()
.getComputerChoices();
JComboBox<ComputerType> compTypeBox = theView.getPlayerPanel().getComputerChoices();
theGame.setComputerType((ComputerType) compTypeBox
.getSelectedItem());
/** Reset the game */
theGame.newGame();
/** If the AIPlayer is opponent, add the current game to its processor */
if (theGame.getAIPlayer() instanceof AIPlayer) {
((AIPlayer)theGame.getAIPlayer()).setGame(theGame);
}
/** Update the reset board */
updateBoard();
updateNextLabel();
} else if (btnClicked == theView.getControlPanel().getBtnTrainAI()
&& theGame.getComputerType() == ComputerType.AI_PLAYER) {
JTextField trainText = theView.getControlPanel()
} else if (btnClicked == theView.getControlPanel().getBtnTrainAI()) {
if (theGame.getComputerType() == ComputerType.AI_PLAYER) {
JTextField trainText = theView.getControlPanel()
.getTrainPractices();
try {
int trainingTimes = Integer.parseInt(trainText.getText());
((AIPlayer) theGame.getAIPlayer()).trainAI(trainingTimes);
} catch (Exception e) {
// Do nothing
try {
int trainingTimes = Integer.parseInt(trainText.getText());
((AIPlayer) theGame.getAIPlayer()).trainAI(trainingTimes);
/** Reset the game after training the AI */
theGame.newGame();
/** If the AIPlayer is opponent, add the current game to its processor */
if (theGame.getAIPlayer() instanceof AIPlayer) {
((AIPlayer)theGame.getAIPlayer()).setGame(theGame);
}
/** Update the reset board */
updateBoard();
updateNextLabel();
} catch (NumberFormatException e) {
JOptionPane.showMessageDialog(null, "Invalid training time", "Error", JOptionPane.ERROR_MESSAGE);
} catch (Exception e) {
/* Do nothing */
}
} else {
JOptionPane.showMessageDialog(null, "You need to train the AI in the AI mode", "Error", JOptionPane.ERROR_MESSAGE);
}
} else {
/** Check every Board button to determine the source of the even */
for (int row = 0; row < SIZE; row++)
......@@ -246,10 +257,6 @@ public class TTTController implements ActionListener {
if (evt.getSource() == theView.getButton(row, col)) {
if (theGame.getTheBoard().placeMark(
theGame.getCurrentPlayer(), row, col)) {
if (theGame.getAIPlayer() instanceof AIPlayer) {
((AIPlayer)theGame.getAIPlayer()).createNode(BoardUtility.convertPosToInt(row, col, SIZE));
}
// Update the state of the board
theGame.updateGameState();
updateViewFromModel();
......
......@@ -17,7 +17,7 @@ import model.player.Player;
*
*/
public class Board {
public class Board implements Comparable<Board>{
/** Assume the size of Tic Tac Toe board is 3 */
public static final int SIZE = 3;
......@@ -96,7 +96,26 @@ public class Board {
int[] position = BoardUtility.convertIntToPos(pos, SIZE);
return isEmpty(position[0],position[1]);
}
/**
* Remove the mark at the row and col position
* @param row
* @param col
*/
public void removeMark(int row, int col) {
board[row][col] = Mark.NONE;
}
/**
* Remove the mark at the row and col position
* @param row
* @param col
*/
public void removeMark(int pos) {
int[] position = BoardUtility.convertIntToPos(pos, SIZE);
removeMark(position[0],position[1]);
}
/**
* Place the mark in the position if possible
*
......@@ -210,6 +229,13 @@ public class Board {
}
return true;
}
public void cloneBoard(Board boardCopy) {
for (int row = 0; row < 3; row++)
for (int col = 0; col < 3; col++) {
this.board[row][col] = boardCopy.getMark(row, col);
}
}
/**
* Updates the board state everytime there's a new mark placed on the board
......@@ -281,4 +307,25 @@ public class Board {
}
return s;
}
@Override
public int compareTo(Board checkBoard) {
for (int row=0; row < this.SIZE; row++){
for(int col=0; col < this.SIZE; col++){
if(board[row][col] != checkBoard.getMark(row, col))
return -1;
}
}
return 0;
}
public boolean equals(Board checkBoard) {
for (int row=0; row < this.board.length; row++){
for(int col=0; col < this.board[row].length; col++){
if(board[row][col] != checkBoard.getMark(row, col))
return false;
}
}
return true;
}
}
......@@ -10,6 +10,9 @@ package model;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import model.player.Player;
import org.junit.After;
......@@ -57,6 +60,14 @@ public class BoardTest {
assertTrue(board1.getMark(2, 1) == Mark.NONE);
assertTrue(board1.getMark(2, 2) == Mark.NONE);
}
@Test
public void testCompareBoard() {
Board board1 = new Board();
Board board2 = new Board();
assertTrue(board1.compareTo(board2) == 0);
board2.placeMark(Mark.X, 0, 0);
}
/**
* Test the isEmpty method
......@@ -93,6 +104,23 @@ public class BoardTest {
board1.placeMark(Mark.X, 2, 2);
assertTrue(board1.isFull());
}
/**
* Test isFull method
*/
@Test
public void testContain() {
ArrayList<Board> boards = new ArrayList<Board>();
Board board1 = new Board();
Board board2 = new Board();
Board board3 = new Board();
board3.cloneBoard(board1);
boards.add(board1);
assertTrue(boards.contains(board1));
board3.placeMark(Mark.X, 0, 0);
assertFalse(boards.contains(board3));
board3.removeMark(0);
}
/**
* Test isFull method
......@@ -105,6 +133,7 @@ public class BoardTest {
board1.placeMark(Mark.X, 1, 0);
board1.placeMark(Mark.O, 1, 2);
board1.placeMark(Mark.X, 2, 2);
board1.updateBoardState();
assertFalse(board1.isPlayable());
}
......@@ -113,7 +142,6 @@ public class BoardTest {
*/
@Test
public void testToString() {
System.out.println(board1);
}
@After
......
......@@ -183,7 +183,6 @@ public class Game {
*/
public void playGame() {
if (players[currentPlayer] instanceof AutoPlayable) {
System.out.println(((AIPlayer)(this.getAIPlayer())).getCurrentNode());
AIMove = ((AutoPlayable) players[currentPlayer]).getMove();
players[currentPlayer].move(AIMove);
System.out.println(this.getTheBoard());
......@@ -292,7 +291,7 @@ public class Game {
// Print the board
System.out.println(theBoard);
// Print the current Player
System.out.println("This is playe1r "
System.out.println("This is player "
+ players[currentPlayer].toString() + "'s turn");
// Ask for a valid move
System.out.print("What position do you want to move:");
......
package model.enumeration;
/**
* CSCI205 - Software Design and Engineering
* Name: Robert Cowen & Son Pham
*
* Work: homework-2
* Created: Nov 11, 2014, 10:23:41 PM
*/
/**
* Represents different type of Computer Player mode
......
package model.enumeration;
/**
* CSCI205 - Software Design and Engineering
* Name: Robert Cowen & Son Pham
*
* Work: homework-2
* Created: Nov 11, 2014, 10:23:41 PM
*/
/**
* Represents the game mode the the user can choose
......
/**
* CSCI205 - Software Design and Engineering
* Name: Son Pham
* Name: Robert Cowen & Son Pham
*
* Work: homework-2
* Created: Nov 11, 2014, 10:06:30 PM
* Created: Nov 11, 2014, 10:23:41 PM
*/
package model.player;
......@@ -12,9 +12,9 @@ import java.util.Random;
import model.Board;
import model.Board.State;
import model.BoardUtility;
import model.Game;
import model.Mark;
import model.enumeration.MoveState;
/**
* @author skp011
......@@ -22,14 +22,12 @@ import model.enumeration.MoveState;
*/
public class AIPlayer extends Player implements AutoPlayable {
/** Instantiate a head MoveNode that is the head of the node tree */
private static MoveNode headNode;
/** Instantiate a movingNode that access other node of the tree */
private MoveNode currentNode;
/** Instantiate a game */
private Game game;
/** Instantiate a random generator */
private Random randomGenerator;
/** Stores all of the bad boards resulting in losses*/
private static ArrayList<Board> badBoards;
/**
* Constructs the AI player
......@@ -39,151 +37,92 @@ public class AIPlayer extends Player implements AutoPlayable {
*/
public AIPlayer(Board board, Mark mark) {
super(board, mark);
/** Check if it is the first time head node is created */
if (this.headNode == null) {
this.headNode = new MoveNode();
}
/** Attach the current node to the head */
this.currentNode = headNode;
if (this.badBoards == null)
badBoards = new ArrayList<Board>();
/** Initialize the random generator */
this.randomGenerator = new Random();
}
/**
* Train the AI by simulating times the number of games
*
* @param times
* Gets the appropriate move based on the the bad boards data
*/
public void trainAI(int times) {
/** number of games counter */
int counter = 0;
/** the position the AI just moved */
int pos;
/** Initialize some game for AI and a RandomPlayer */
RandomPlayer randomPlayer = new RandomPlayer(game.getTheBoard(), Mark.X);
this.setMyMark(Mark.O);
game = new Game(randomPlayer, this);
while (counter < times) {
while (game.isPlayable()) {
game.playGame();
pos = game.getAIMove();
createNode(pos);
/** Check if the game end */
if (game.getState() == State.WIN
&& game.getCurrentPlayer() == this) {
currentNode.setMoveState(MoveState.LOSS);
currentNode.updateNode();
break;
} else if (game.getState() == State.WIN) {
currentNode.setMoveState(MoveState.WIN);
currentNode.updateNode();
public int getMove() {
boolean check;
/** Get current empty position in the board */
ArrayList<Integer> emptyPos = theBoard.getEmptyPosition();
// System.out.println(emptyPos);
/** Check if there's a losing move */
for (int pos: emptyPos) {
System.out.println("Check move: " + pos);
int[] position = BoardUtility.convertIntToPos(pos, SIZE);
theBoard.placeMark(this.getMyMark(), position[0], position[1]);
check = false;
for (Board board: badBoards) {
if (board.compareTo(theBoard) == 0) {
// System.out.println("There is a losing move!");
// System.out.println(theBoard);
check = true;
break;
}
}
randomPlayer = new RandomPlayer(game.getTheBoard(), Mark.X);
this.setMyMark(Mark.O);
game = new Game(randomPlayer, this);
currentNode = headNode;
counter++;
/** If the move is a losing move, avoid that move and choose another move */
if (check == true) {
theBoard.removeMark(pos);
/** If it's a good move, then just return the move */
} else {
theBoard.removeMark(pos);
return pos;
}
}
/** If every move is a losing move, just return a random one among those losing moves */
int randomMove = randomGenerator.nextInt(emptyPos.size());
return emptyPos.get(randomMove);
}
/**
* Create new node base on the new move
*
* @param pos
* Trains the AI by make the AI play with the Random Player for a given amount of time
* @param trainingTimes
*/
public void createNode(int pos) {
/** Do all the null thing */
if (currentNode.getStateArray()[pos] != null) {
currentNode = currentNode.getStateArray()[pos];
} else {
/** make new MoveNode and jump to the new one */
currentNode.getStateArray()[pos] = new MoveNode();
currentNode.getStateArray()[pos].setPrevious(currentNode);
currentNode = currentNode.getStateArray()[pos];
/** Clone the state array */
currentNode.setStateArray(currentNode.getPrevious().getStateArray()
.clone());
currentNode.getStateArray()[pos] = new MoveNode(MoveState.IMMOVABLE);
/**
* Clean up the array so that it has all null objects beside WIN and
* IMMOVABLE
*/
for (MoveNode node : currentNode.getStateArray()) {
if (node != null
&& (node.getMoveState() == MoveState.LOSS || node
.getMoveState() == MoveState.MOVABLE)) {
node = null;
public void trainAI(int trainingTimes) {
/** Set up the counter for training time */
int count = 0;
/** Set up a game used for training */
Game game;
/** Set up the random player */
RandomPlayer randomPLayer;
/** Set up the temporary board for storage usage */
Board tempBoard;
/** Play the game for trainTimes amount of times */
while (count < trainingTimes) {
/** Set up a new game */
game = new Game();
randomPLayer = new RandomPlayer(game.getTheBoard(),Mark.X);
this.setTheBoard(game.getTheBoard()); /*Set the AI board to the traning board */
Player[] players = {randomPLayer, this};
game.setPlayers(players);
/** Play the game */
while (game.isPlayable()) {
tempBoard = new Board(); /* store the current board into tempBoard */
tempBoard.cloneBoard(game.getTheBoard());
game.playGame();
/* If the current board leads to a losing move, then store the board so that AI avoid making that move in the future */
if (game.getState() == State.WIN && game.getCurrentPlayer() instanceof AIPlayer) {
badBoards.add(tempBoard);
}
}
count++; /* Play other game */
// System.out.println(count);
}
/** Check if the game end */
/** if (game.getState() == State.WIN && game.getCurrentPlayer() == this) {
currentNode.setMoveState(MoveState.LOSS);
currentNode.updateNode();
} else if (game.getState() == State.WIN) {
currentNode.setMoveState(MoveState.WIN);
currentNode.updateNode();
} */
}
@Override
public int getMove() {
/** Array for the best move */
ArrayList<Integer> bestMoves = new ArrayList<Integer>();
/** State array in the current node */
MoveNode[] nodes = currentNode.getStateArray();
/** Check for wins */
for (int pos = 0; pos < nodes.length; pos++) {
if (nodes[pos] != null
&& nodes[pos].getMoveState() == MoveState.WIN) {
return pos;
}
}
/** Check for MOVES */
for (int pos = 0; pos < nodes.length; pos++) {
if (nodes[pos] == null
|| nodes[pos].getMoveState() == MoveState.MOVABLE) {
bestMoves.add(pos);
}
}
/** Return a random position if the size of the bestMoves > 0 */
if (bestMoves.size() > 0) {
int index = randomGenerator.nextInt(bestMoves.size());
return bestMoves.get(index);
}
/** Check for LOSSES */
for (int pos = 0; pos < nodes.length; pos++) {
if (nodes[pos] != null
&& nodes[pos].getMoveState() == MoveState.LOSS) {
bestMoves.add(pos);
}
}
/** Return a random position if the size of the bestMoves > 0 */
if (bestMoves.size() > 0) {
int index = randomGenerator.nextInt(bestMoves.size());
return bestMoves.get(index);
}
return -1;
}
public void setGame(Game game) {
this.game = game;
}
public MoveNode getCurrentNode() {
return currentNode;
}
/**
* @return the headNode
*/
public MoveNode getHeadNode() {
return headNode;
}
}
/**
* CSCI205 - Software Design and Engineering
* Name: Son Pham
* Name: Robert Cowen & Son Pham
*
* Work: homework-2
* Created: Nov 12, 2014, 3:20:50 PM
* Created: Nov 11, 2014, 10:23:41 PM
*/
package model.player;
......
/**
* CSCI205 - Software Design and Engineering
* Name: Son Pham
* Name: Robert Cowen & Son Pham
*
* Work: homework-2
* Created: Nov 11, 2014, 10:10:39 PM
* Created: Nov 11, 2014, 10:23:41 PM
*/
package model.player;
......
/**
* CSCI205 - Software Design and Engineering
* Name: Son Pham
* Name: Robert Cowen & Son Pham
*
* Work: homework-2
* Created: Nov 11, 2014, 10:09:25 PM
* Created: Nov 11, 2014, 10:23:41 PM
*/
package model.player;
......
/**
* CSCI205 - Software Design and Engineering
* Name: Son Pham
* Name: Robert Cowen & Son Pham
*
* Work: homework-2
* Created: Nov 11, 2014, 8:53:55 PM
* Created: Nov 11, 2014, 10:23:41 PM
*/
package view;
......
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
<classpathentry kind="output" path="bin"/>
</classpath>
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>hw01</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.7
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.source=1.7
This is a drill. Bobby take this file.
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