Compare commits
11 Commits
d03b4443f6
...
1f7ff56204
| Author | SHA1 | Date | |
|---|---|---|---|
| 1f7ff56204 | |||
|
|
b8d9480ae7 | ||
|
|
3ba0db6ebd | ||
|
|
924780baaf | ||
|
|
48915071d4 | ||
|
|
490d3d0bf6 | ||
|
|
f4ed883d63 | ||
|
|
a9fbdfb50e | ||
|
|
f6e4a32b82 | ||
|
|
e9ead0edda | ||
|
|
f81db19586 |
@@ -5,6 +5,5 @@
|
|||||||
<classpathentry kind="src" path="test"/>
|
<classpathentry kind="src" path="test"/>
|
||||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||||
<classpathentry kind="lib" path="lib/junit-4.10.jar"/>
|
<classpathentry kind="lib" path="lib/junit-4.10.jar"/>
|
||||||
<classpathentry kind="lib" path="lib/log4j-1.2.16.jar"/>
|
|
||||||
<classpathentry kind="output" path="bin"/>
|
<classpathentry kind="output" path="bin"/>
|
||||||
</classpath>
|
</classpath>
|
||||||
|
|||||||
7
LICENSE.txt
Normal file
7
LICENSE.txt
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
Copyright (c) <year> <copyright holders>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
16
README.TXT
Normal file
16
README.TXT
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
MatchAttack! Instructions
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
Unzip the attached archive 'CS8803_P4.zip' and change to the new directory.
|
||||||
|
|
||||||
|
To build MatchAttack!: run 'ant clean' then 'ant' in this directory.
|
||||||
|
|
||||||
|
To run MatchAttack!: change to the 'dist' directory, then run java -jar CS8803_P4.jar
|
||||||
|
|
||||||
|
For full instructions, see writeup/CS8803_P4.PDF.
|
||||||
|
|
||||||
|
For assistance, please contact Woody Folsom <woody.folsom@gatech.edu> or Marshall Gillson <mgillson1@gmail.com>.
|
||||||
|
|
||||||
|
NOTICE
|
||||||
|
------
|
||||||
|
Unless otherwise attributed, code in the 'aima' package is (c) Ciaran O'Reilly and Ravi Mohan. It is used under the MIT license. See LICENSE.TXT for more information. Note that this is the actual license referenced by the project site, with placeholders for date and author names.
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
|
|
||||||
<target name="compile" depends="copy-resources">
|
<target name="compile" depends="copy-resources">
|
||||||
<!-- Compile the java code from ${src} into ${build} -->
|
<!-- Compile the java code from ${src} into ${build} -->
|
||||||
<javac srcdir="${src}" destdir="${build}" classpathref="build.classpath" debug="true" source="1.6" target="1.6"/>
|
<javac srcdir="${src}" destdir="${build}" classpathref="build.classpath" debug="true" source="1.8" target="1.8"/>
|
||||||
</target>
|
</target>
|
||||||
|
|
||||||
<target name="compile-test" depends="compile">
|
<target name="compile-test" depends="compile">
|
||||||
|
|||||||
Binary file not shown.
@@ -33,7 +33,11 @@ public class MDPFactory {
|
|||||||
public static ActionsFunction<GridCell<Double>, GridWorldAction> createActionsFunctionForTileGame(
|
public static ActionsFunction<GridCell<Double>, GridWorldAction> createActionsFunctionForTileGame(
|
||||||
final GridWorld<Double> cw, int maxTiles, int maxScore) {
|
final GridWorld<Double> cw, int maxTiles, int maxScore) {
|
||||||
final Set<GridCell<Double>> terminals = new HashSet<GridCell<Double>>();
|
final Set<GridCell<Double>> terminals = new HashSet<GridCell<Double>>();
|
||||||
terminals.add(cw.getCellAt(maxTiles,maxScore));
|
|
||||||
|
for (int score = 1; score <= maxScore; score++) {
|
||||||
|
terminals.add(cw.getCellAt(maxTiles,score));
|
||||||
|
}
|
||||||
|
//terminals.add(cw.getCellAt(maxTiles,maxScore));
|
||||||
|
|
||||||
ActionsFunction<GridCell<Double>, GridWorldAction> af = new ActionsFunction<GridCell<Double>, GridWorldAction>() {
|
ActionsFunction<GridCell<Double>, GridWorldAction> af = new ActionsFunction<GridCell<Double>, GridWorldAction>() {
|
||||||
|
|
||||||
|
|||||||
@@ -12,14 +12,20 @@ public class Board {
|
|||||||
public static final int NUM_ROWS = 5;
|
public static final int NUM_ROWS = 5;
|
||||||
public static final int ROW_REMOVAL_SIZE = 3;
|
public static final int ROW_REMOVAL_SIZE = 3;
|
||||||
|
|
||||||
public static boolean isLegal(Board brd, CellPointer cp) {
|
private boolean boardEmpty = true;
|
||||||
|
|
||||||
|
public boolean isLegal(CellPointer cp) {
|
||||||
|
//coordinates are out of board bounds
|
||||||
if (cp.r < 0 || cp.r >= Board.NUM_ROWS || cp.c < 0
|
if (cp.r < 0 || cp.r >= Board.NUM_ROWS || cp.c < 0
|
||||||
|| cp.c >= Board.NUM_COLS) {
|
|| cp.c >= Board.NUM_COLS) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean legal = (brd.getTile(cp.r, cp.c) == TileColor.NONE);
|
//target coordinate already has a tile
|
||||||
|
if (board[cp.r][cp.c] != TileColor.NONE) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
boolean rowUp = (cp.r - 1) >= 0;
|
boolean rowUp = (cp.r - 1) >= 0;
|
||||||
boolean rowDown = (cp.r + 1) < Board.NUM_ROWS;
|
boolean rowDown = (cp.r + 1) < Board.NUM_ROWS;
|
||||||
boolean colUp = (cp.c - 1) >= 0;
|
boolean colUp = (cp.c - 1) >= 0;
|
||||||
@@ -27,49 +33,49 @@ public class Board {
|
|||||||
|
|
||||||
// r-1 / c-1
|
// r-1 / c-1
|
||||||
if (rowUp && colUp
|
if (rowUp && colUp
|
||||||
&& (brd.getTile(cp.r - 1, cp.c - 1) != TileColor.NONE)) {
|
&& (board[cp.r - 1][ cp.c - 1] != TileColor.NONE)) {
|
||||||
return legal && true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// r-1 / c
|
// r-1 / c
|
||||||
if (rowUp && (brd.getTile(cp.r - 1, cp.c) != TileColor.NONE)) {
|
if (rowUp && (board[cp.r - 1][ cp.c] != TileColor.NONE)) {
|
||||||
return legal && true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// r-1 / c+1
|
// r-1 / c+1
|
||||||
if (rowUp && colDown
|
if (rowUp && colDown
|
||||||
&& (brd.getTile(cp.r - 1, cp.c + 1) != TileColor.NONE)) {
|
&& (board[cp.r - 1][ cp.c + 1] != TileColor.NONE)) {
|
||||||
return legal && true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// r / c-1
|
// r / c-1
|
||||||
if (colUp && (brd.getTile(cp.r, cp.c - 1) != TileColor.NONE)) {
|
if (colUp && (board[cp.r][ cp.c - 1] != TileColor.NONE)) {
|
||||||
return legal && true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// r / c+1
|
// r / c+1
|
||||||
if (colDown && (brd.getTile(cp.r, cp.c + 1) != TileColor.NONE)) {
|
if (colDown && (board[cp.r][ cp.c + 1] != TileColor.NONE)) {
|
||||||
return legal && true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// r+1 / c-1
|
// r+1 / c-1
|
||||||
if (rowDown && colUp
|
if (rowDown && colUp
|
||||||
&& (brd.getTile(cp.r + 1, cp.c - 1) != TileColor.NONE)) {
|
&& (board[cp.r + 1][ cp.c - 1] != TileColor.NONE)) {
|
||||||
return legal && true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// r+1 / c
|
// r+1 / c
|
||||||
if (rowDown && (brd.getTile(cp.r + 1, cp.c) != TileColor.NONE)) {
|
if (rowDown && (board[cp.r + 1][ cp.c] != TileColor.NONE)) {
|
||||||
return legal && true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// r+1 / c+1
|
// r+1 / c+1
|
||||||
if (rowDown && colDown
|
if (rowDown && colDown
|
||||||
&& (brd.getTile(cp.r + 1, cp.c + 1) != TileColor.NONE)) {
|
&& (board[cp.r + 1][ cp.c + 1] != TileColor.NONE)) {
|
||||||
return legal && true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return brd.isEmpty();
|
return boardEmpty;
|
||||||
}
|
}
|
||||||
|
|
||||||
private final TileColor[][] board;
|
private final TileColor[][] board;
|
||||||
@@ -91,6 +97,7 @@ public class Board {
|
|||||||
|
|
||||||
for (int r = 0; r < NUM_ROWS; r++) {
|
for (int r = 0; r < NUM_ROWS; r++) {
|
||||||
for (int c = 0; c < NUM_COLS; c++) {
|
for (int c = 0; c < NUM_COLS; c++) {
|
||||||
|
this.boardEmpty = that.boardEmpty;
|
||||||
this.board[r][c] = that.board[r][c];
|
this.board[r][c] = that.board[r][c];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -163,7 +170,7 @@ public class Board {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean playTile(CellPointer cp, TileColor tile) {
|
public boolean playTile(CellPointer cp, TileColor tile) {
|
||||||
if (!isLegal(this, cp)) {
|
if (!isLegal(cp)) {
|
||||||
return false; // Illegal move.
|
return false; // Illegal move.
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -304,6 +311,8 @@ public class Board {
|
|||||||
}
|
}
|
||||||
|
|
||||||
numPlies++;
|
numPlies++;
|
||||||
|
|
||||||
|
boardEmpty = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -320,16 +329,4 @@ public class Board {
|
|||||||
}
|
}
|
||||||
return sb1.toString();
|
return sb1.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isEmpty() {
|
|
||||||
for (int r = 0; r < Board.NUM_ROWS; r++) {
|
|
||||||
for (int c = 0; c < Board.NUM_COLS; c++) {
|
|
||||||
if (getTile(r, c) != TileColor.NONE) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -6,8 +6,6 @@ import model.comPlayer.Player;
|
|||||||
import model.playerModel.GameGoal;
|
import model.playerModel.GameGoal;
|
||||||
import model.playerModel.PlayerModel;
|
import model.playerModel.PlayerModel;
|
||||||
|
|
||||||
import org.apache.log4j.Logger;
|
|
||||||
|
|
||||||
import view.BoardPanel;
|
import view.BoardPanel;
|
||||||
import view.HighScoreDialog;
|
import view.HighScoreDialog;
|
||||||
import view.MainFrame;
|
import view.MainFrame;
|
||||||
@@ -16,8 +14,6 @@ import view.ScorePanel;
|
|||||||
public class Referee implements Runnable {
|
public class Referee implements Runnable {
|
||||||
public static final String COM_TURN = "Waiting for the computer's move.";
|
public static final String COM_TURN = "Waiting for the computer's move.";
|
||||||
public static final String GAME_OVER = "Game over!";
|
public static final String GAME_OVER = "Game over!";
|
||||||
public static final Logger LOGGER = Logger.getLogger(Referee.class
|
|
||||||
.getName());
|
|
||||||
|
|
||||||
public static final String PLAYER_TURN = "Waiting for the player's move.";
|
public static final String PLAYER_TURN = "Waiting for the player's move.";
|
||||||
|
|
||||||
@@ -153,7 +149,6 @@ public class Referee implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void play() {
|
private void play() {
|
||||||
int plies = 0;
|
|
||||||
while (!isOver()) {
|
while (!isOver()) {
|
||||||
if (board.isPlayerTurn()) {
|
if (board.isPlayerTurn()) {
|
||||||
boolean wasInterrupted = false;
|
boolean wasInterrupted = false;
|
||||||
@@ -197,7 +192,7 @@ public class Referee implements Runnable {
|
|||||||
getScorePanel().updateScore(getPlayerScore());
|
getScorePanel().updateScore(getPlayerScore());
|
||||||
mf.updateMessage(getMessage());
|
mf.updateMessage(getMessage());
|
||||||
boardPanel.updateIcons();
|
boardPanel.updateIcons();
|
||||||
LOGGER.info("plies: " + plies++);
|
|
||||||
try {
|
try {
|
||||||
Thread.sleep(250L);
|
Thread.sleep(250L);
|
||||||
} catch (InterruptedException ie) {
|
} catch (InterruptedException ie) {
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ public class AdaptiveComPlayer implements Player {
|
|||||||
// take 10 turns to place 6 tiles
|
// take 10 turns to place 6 tiles
|
||||||
double defaultPenalty = -0.25;
|
double defaultPenalty = -0.25;
|
||||||
|
|
||||||
int maxScore = target.getTargetScore();
|
int maxScore = Math.max(1,target.getTargetScore());
|
||||||
int maxTiles = Board.NUM_COLS * Board.NUM_ROWS;
|
int maxTiles = Board.NUM_COLS * Board.NUM_ROWS;
|
||||||
|
|
||||||
gw = GridWorldFactory.createGridWorldForTileGame(maxTiles,
|
gw = GridWorldFactory.createGridWorldForTileGame(maxTiles,
|
||||||
@@ -79,10 +79,11 @@ public class AdaptiveComPlayer implements Player {
|
|||||||
if (action == null || state == null) {
|
if (action == null || state == null) {
|
||||||
System.out
|
System.out
|
||||||
.println("Board state outside of parameters of MDP. Reverting to failsafe behavior.");
|
.println("Board state outside of parameters of MDP. Reverting to failsafe behavior.");
|
||||||
action = GridWorldAction.RandomMove;
|
action = GridWorldAction.AddTile;
|
||||||
}
|
} else {
|
||||||
System.out.println("Performing action " + action + " at state " + state
|
System.out.println("Performing action " + action + " at state " + state
|
||||||
+ " per policy.");
|
+ " per policy.");
|
||||||
|
}
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case AddTile:
|
case AddTile:
|
||||||
// System.out.println("Performing action #" +
|
// System.out.println("Performing action #" +
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import model.playerModel.GameGoal;
|
|||||||
import model.playerModel.PlayerModel;
|
import model.playerModel.PlayerModel;
|
||||||
|
|
||||||
public class AlphaBetaComPlayer implements Player {
|
public class AlphaBetaComPlayer implements Player {
|
||||||
private final MoveGenerator moveGenerator = new AlphaBetaMoveGenerator();
|
final MoveGenerator moveGenerator = new AlphaBetaMoveGenerator();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void denyMove() {
|
public void denyMove() {
|
||||||
|
|||||||
@@ -286,7 +286,7 @@ public class CountingPlayer implements Player {
|
|||||||
|
|
||||||
for (int r = 0; r < Board.NUM_ROWS; r++) {
|
for (int r = 0; r < Board.NUM_ROWS; r++) {
|
||||||
for (int c = 0; c < Board.NUM_COLS; c++) {
|
for (int c = 0; c < Board.NUM_COLS; c++) {
|
||||||
if (Board.isLegal(board, new CellPointer(r, c))) {
|
if (board.isLegal(new CellPointer(r, c))) {
|
||||||
moves.add(new Move(TileColor.BLUE, r, c));
|
moves.add(new Move(TileColor.BLUE, r, c));
|
||||||
moves.add(new Move(TileColor.GREEN, r, c));
|
moves.add(new Move(TileColor.GREEN, r, c));
|
||||||
moves.add(new Move(TileColor.RED, r, c));
|
moves.add(new Move(TileColor.RED, r, c));
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import model.playerModel.GameGoal;
|
|||||||
import model.playerModel.PlayerModel;
|
import model.playerModel.PlayerModel;
|
||||||
|
|
||||||
public class MinimaxComPlayer implements Player {
|
public class MinimaxComPlayer implements Player {
|
||||||
private final MoveGenerator moveGenerator = new MinimaxMoveGenerator();
|
final MoveGenerator moveGenerator = new MinimaxMoveGenerator();
|
||||||
|
|
||||||
public MinimaxComPlayer() {
|
public MinimaxComPlayer() {
|
||||||
super();
|
super();
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import model.playerModel.GameGoal;
|
|||||||
import model.playerModel.PlayerModel;
|
import model.playerModel.PlayerModel;
|
||||||
|
|
||||||
public class MonteCarloComPlayer implements Player {
|
public class MonteCarloComPlayer implements Player {
|
||||||
private final MoveGenerator moveGenerator = new MonteCarloMoveGenerator();
|
final MoveGenerator moveGenerator = new MonteCarloMoveGenerator();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void denyMove() {
|
public void denyMove() {
|
||||||
|
|||||||
@@ -29,4 +29,4 @@ public interface Player {
|
|||||||
public boolean isReady();
|
public boolean isReady();
|
||||||
|
|
||||||
public void setGameGoal(GameGoal target);
|
public void setGameGoal(GameGoal target);
|
||||||
}
|
}
|
||||||
@@ -8,13 +8,9 @@ import model.BoardScorer;
|
|||||||
import model.Move;
|
import model.Move;
|
||||||
import model.SearchResult;
|
import model.SearchResult;
|
||||||
|
|
||||||
import org.apache.log4j.Logger;
|
|
||||||
|
|
||||||
public class AlphaBetaMoveGenerator implements MoveGenerator {
|
public class AlphaBetaMoveGenerator implements MoveGenerator {
|
||||||
private static final int DEFAULT_RECURSIVE_PLAYS = 1;
|
private static final int DEFAULT_RECURSIVE_PLAYS = 1;
|
||||||
private static final Logger LOGGER = Logger
|
private int lookahead = DEFAULT_RECURSIVE_PLAYS;
|
||||||
.getLogger(AlphaBetaMoveGenerator.class.getName());
|
|
||||||
|
|
||||||
private final BoardScorer scorer = new BoardScorer();
|
private final BoardScorer scorer = new BoardScorer();
|
||||||
private final ValidMoveGenerator validMoveGenerator = new ValidMoveGenerator();
|
private final ValidMoveGenerator validMoveGenerator = new ValidMoveGenerator();
|
||||||
|
|
||||||
@@ -22,10 +18,10 @@ public class AlphaBetaMoveGenerator implements MoveGenerator {
|
|||||||
public Move genMove(Board board, boolean asHuman) {
|
public Move genMove(Board board, boolean asHuman) {
|
||||||
|
|
||||||
if (!asHuman) {
|
if (!asHuman) {
|
||||||
return getMaxValue(board, asHuman, DEFAULT_RECURSIVE_PLAYS * 2,
|
return getMaxValue(board, asHuman, lookahead * 2,
|
||||||
Integer.MIN_VALUE, Integer.MAX_VALUE).move;
|
Integer.MIN_VALUE, Integer.MAX_VALUE).move;
|
||||||
} else {
|
} else {
|
||||||
return getMinValue(board, asHuman, DEFAULT_RECURSIVE_PLAYS * 2,
|
return getMinValue(board, asHuman, lookahead * 2,
|
||||||
Integer.MIN_VALUE, Integer.MAX_VALUE).move;
|
Integer.MIN_VALUE, Integer.MAX_VALUE).move;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -36,7 +32,6 @@ public class AlphaBetaMoveGenerator implements MoveGenerator {
|
|||||||
@Override
|
@Override
|
||||||
public List<Move> genMoves(Board board, boolean asHuman, int nMoves) {
|
public List<Move> genMoves(Board board, boolean asHuman, int nMoves) {
|
||||||
Move[] doNothing = new Move[] { Move.NONE };
|
Move[] doNothing = new Move[] { Move.NONE };
|
||||||
LOGGER.info("Minimax genMoves() stub returning []");
|
|
||||||
return Arrays.asList(doNothing);
|
return Arrays.asList(doNothing);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,4 +114,9 @@ public class AlphaBetaMoveGenerator implements MoveGenerator {
|
|||||||
|
|
||||||
return bestResult;
|
return bestResult;
|
||||||
}
|
}
|
||||||
|
@Override
|
||||||
|
public boolean setLookahead(int lookahead) {
|
||||||
|
this.lookahead = lookahead;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -8,12 +8,9 @@ import model.BoardScorer;
|
|||||||
import model.Move;
|
import model.Move;
|
||||||
import model.SearchResult;
|
import model.SearchResult;
|
||||||
|
|
||||||
import org.apache.log4j.Logger;
|
|
||||||
|
|
||||||
public class MinimaxMoveGenerator implements MoveGenerator {
|
public class MinimaxMoveGenerator implements MoveGenerator {
|
||||||
private static final Logger LOGGER = Logger
|
private static final int DEFAULT_RECURSIVE_PLAYS = 1;
|
||||||
.getLogger(MinimaxMoveGenerator.class.getName());
|
private int lookahead = DEFAULT_RECURSIVE_PLAYS;
|
||||||
private static final int DEFAULT_RECURSIVE_PLAYS = 2;
|
|
||||||
|
|
||||||
private final BoardScorer scorer = new BoardScorer();
|
private final BoardScorer scorer = new BoardScorer();
|
||||||
private final ValidMoveGenerator validMoveGenerator = new ValidMoveGenerator();
|
private final ValidMoveGenerator validMoveGenerator = new ValidMoveGenerator();
|
||||||
@@ -24,12 +21,12 @@ public class MinimaxMoveGenerator implements MoveGenerator {
|
|||||||
//have different types of moves.
|
//have different types of moves.
|
||||||
SearchResult searchResult;
|
SearchResult searchResult;
|
||||||
if (!asHuman) {
|
if (!asHuman) {
|
||||||
searchResult = getMaxValue(board, Move.NONE, asHuman, DEFAULT_RECURSIVE_PLAYS * 2);
|
searchResult = getMaxValue(board, Move.NONE, asHuman, lookahead * 2);
|
||||||
} else {
|
} else {
|
||||||
searchResult = getMinValue(board, Move.NONE, asHuman, DEFAULT_RECURSIVE_PLAYS * 2);
|
searchResult = getMinValue(board, Move.NONE, asHuman, lookahead * 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
System.out.println(searchResult);
|
//System.out.println(searchResult);
|
||||||
return searchResult.move;
|
return searchResult.move;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,13 +90,15 @@ public class MinimaxMoveGenerator implements MoveGenerator {
|
|||||||
return recursionLevel < 1;
|
return recursionLevel < 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* AlphaBetaMoveGenerator2 does not support this method.
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public List<Move> genMoves(Board board, boolean asHuman, int nMoves) {
|
public List<Move> genMoves(Board board, boolean asHuman, int nMoves) {
|
||||||
Move[] doNothing = new Move[] { Move.NONE };
|
Move[] doNothing = new Move[] { Move.NONE };
|
||||||
LOGGER.info("Minimax genMoves() stub returning []");
|
|
||||||
return Arrays.asList(doNothing);
|
return Arrays.asList(doNothing);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean setLookahead(int lookahead) {
|
||||||
|
this.lookahead = lookahead;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,12 +8,9 @@ import model.BoardScorer;
|
|||||||
import model.Move;
|
import model.Move;
|
||||||
import model.SearchResult;
|
import model.SearchResult;
|
||||||
|
|
||||||
import org.apache.log4j.Logger;
|
|
||||||
|
|
||||||
public class MonteCarloMoveGenerator implements MoveGenerator {
|
public class MonteCarloMoveGenerator implements MoveGenerator {
|
||||||
private static final Logger LOGGER = Logger
|
private static final int DEFAULT_RECURSIVE_PLAYS = 1;
|
||||||
.getLogger(MonteCarloMoveGenerator.class.getName());
|
private int lookahead = DEFAULT_RECURSIVE_PLAYS;
|
||||||
private static final int DEFAULT_RECURSIVE_PLAYS = 3;
|
|
||||||
private static final int MOVES_PER_LEVEL = 12;
|
private static final int MOVES_PER_LEVEL = 12;
|
||||||
|
|
||||||
private final BoardScorer scorer = new BoardScorer();
|
private final BoardScorer scorer = new BoardScorer();
|
||||||
@@ -22,7 +19,7 @@ public class MonteCarloMoveGenerator implements MoveGenerator {
|
|||||||
@Override
|
@Override
|
||||||
public Move genMove(Board board, boolean asHuman) {
|
public Move genMove(Board board, boolean asHuman) {
|
||||||
|
|
||||||
SearchResult bestResult = genMove(board, asHuman, DEFAULT_RECURSIVE_PLAYS * 2);
|
SearchResult bestResult = genMove(board, asHuman, lookahead * 2);
|
||||||
|
|
||||||
return bestResult.move;
|
return bestResult.move;
|
||||||
}
|
}
|
||||||
@@ -73,13 +70,15 @@ public class MonteCarloMoveGenerator implements MoveGenerator {
|
|||||||
return new SearchResult(bestResult.move, (int)Math.round((double)totalScore / validMoves.size()));
|
return new SearchResult(bestResult.move, (int)Math.round((double)totalScore / validMoves.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* AlphaBetaMoveGenerator2 does not support this method.
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public List<Move> genMoves(Board board, boolean asHuman, int nMoves) {
|
public List<Move> genMoves(Board board, boolean asHuman, int nMoves) {
|
||||||
Move[] doNothing = new Move[] { Move.NONE };
|
Move[] doNothing = new Move[] { Move.NONE };
|
||||||
LOGGER.info("Minimax genMoves() stub returning []");
|
|
||||||
return Arrays.asList(doNothing);
|
return Arrays.asList(doNothing);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean setLookahead(int lookahead) {
|
||||||
|
this.lookahead = lookahead;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -10,4 +10,5 @@ public interface MoveGenerator {
|
|||||||
|
|
||||||
public Move genMove(Board board, boolean asHuman);
|
public Move genMove(Board board, boolean asHuman);
|
||||||
public List<Move> genMoves(Board board, boolean asHuman, int nMoves);
|
public List<Move> genMoves(Board board, boolean asHuman, int nMoves);
|
||||||
|
public boolean setLookahead(int lookahead);
|
||||||
}
|
}
|
||||||
@@ -80,7 +80,7 @@ public class NeuralNetworkMoveGenerator implements MoveGenerator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!Board.isLegal(board, mv.getCell())) {
|
while (!board.isLegal(mv.getCell())) {
|
||||||
mv = new Move(mv.getColor(), new CellPointer(
|
mv = new Move(mv.getColor(), new CellPointer(
|
||||||
PlayerModel.rand.nextInt(Board.NUM_ROWS),
|
PlayerModel.rand.nextInt(Board.NUM_ROWS),
|
||||||
PlayerModel.rand.nextInt(Board.NUM_COLS)));
|
PlayerModel.rand.nextInt(Board.NUM_COLS)));
|
||||||
@@ -94,5 +94,8 @@ public class NeuralNetworkMoveGenerator implements MoveGenerator {
|
|||||||
// Do nothing.
|
// Do nothing.
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@Override
|
||||||
|
public boolean setLookahead(int lookahead) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -9,15 +9,9 @@ import model.Board.TileColor;
|
|||||||
import model.CellPointer;
|
import model.CellPointer;
|
||||||
import model.Move;
|
import model.Move;
|
||||||
|
|
||||||
import org.apache.log4j.Logger;
|
|
||||||
|
|
||||||
public class ValidMoveGenerator implements MoveGenerator {
|
public class ValidMoveGenerator implements MoveGenerator {
|
||||||
private static final Logger LOGGER = Logger
|
|
||||||
.getLogger(ValidMoveGenerator.class.getName());
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Move genMove(Board board, boolean asHuman) {
|
public Move genMove(Board board, boolean asHuman) {
|
||||||
LOGGER.info("ValidMoveGenerator genMove() stub returning NONE");
|
|
||||||
return Move.NONE;
|
return Move.NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -28,13 +22,11 @@ public class ValidMoveGenerator implements MoveGenerator {
|
|||||||
|
|
||||||
for (int r = 0; r < Board.NUM_ROWS; r++) {
|
for (int r = 0; r < Board.NUM_ROWS; r++) {
|
||||||
for (int c = 0; c < Board.NUM_COLS; c++) {
|
for (int c = 0; c < Board.NUM_COLS; c++) {
|
||||||
if (Board.isLegal(board, new CellPointer(r, c))) {
|
if (board.isLegal(new CellPointer(r, c))) {
|
||||||
for (TileColor color : TileColor.values()) {
|
validMoves.add(new Move(TileColor.BLUE, r, c));
|
||||||
if (color == TileColor.NONE) {
|
validMoves.add(new Move(TileColor.GREEN, r, c));
|
||||||
continue;
|
validMoves.add(new Move(TileColor.RED, r, c));
|
||||||
}
|
validMoves.add(new Move(TileColor.YELLOW, r, c));
|
||||||
validMoves.add(new Move(color, r, c));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -47,4 +39,9 @@ public class ValidMoveGenerator implements MoveGenerator {
|
|||||||
return validMoves.subList(0, Math.min(validMoves.size(), nMoves));
|
return validMoves.subList(0, Math.min(validMoves.size(), nMoves));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@Override
|
||||||
|
public boolean setLookahead(int lookahead) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,12 +4,13 @@ public class ArgParser {
|
|||||||
public static ParsedArgs parse(String[] cmdLineArgs) {
|
public static ParsedArgs parse(String[] cmdLineArgs) {
|
||||||
ParsedArgs parsedArgs = new ParsedArgs();
|
ParsedArgs parsedArgs = new ParsedArgs();
|
||||||
for (int i = 0; i < cmdLineArgs.length; i++) {
|
for (int i = 0; i < cmdLineArgs.length; i++) {
|
||||||
if (cmdLineArgs[i].toUpperCase().startsWith("COM=")) {
|
String arg = cmdLineArgs[i].replaceAll("-","");
|
||||||
|
if (arg.toUpperCase().startsWith("COM=")) {
|
||||||
String comPlayer = cmdLineArgs[i].split("=")[1];
|
String comPlayer = cmdLineArgs[i].split("=")[1];
|
||||||
parsedArgs.setComPlayer(comPlayer);
|
parsedArgs.setComPlayer(comPlayer);
|
||||||
System.out.println("ComPlayer set to: " + comPlayer);
|
System.out.println("ComPlayer set to: " + comPlayer);
|
||||||
} else {
|
} else {
|
||||||
System.out.println("Ignoring unrecognized argument: " + cmdLineArgs[i]);
|
System.out.println("Ignoring unrecognized argument: " + arg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return parsedArgs;
|
return parsedArgs;
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ public class UserChooserFrame extends JFrame {
|
|||||||
|
|
||||||
public static final String PLAYER_LIST_FILE = "players.dat";
|
public static final String PLAYER_LIST_FILE = "players.dat";
|
||||||
public static final JLabel RULES_TEXT = new JLabel(
|
public static final JLabel RULES_TEXT = new JLabel(
|
||||||
"Here should go some rules text. Lorem ipsum dolor sit amet, consectetur adipiscing elit...");
|
"<html>Welcome to <i>MatchAttack!</i><br><br>The rules of <i>MatchAttack!</i> are very straightforward.<ol><li>The goal of <i>MatchAttack!</i> is to maxmize your score.<br>You earn a point for each tile you place on the board.</li><li>Unless the board is empty, every tile you place must be adjacent to an existing tile.</li><li>If you create a line of three or more tiles of the same color, horizontally or vertically,<br>then every tile in that row will be removed.</li><li>After each tile you place, the computer will place a tile.<br>The computer will attempt to fill the board.</li></ol>Enter your name below to begin!</html>");
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
private final Player comPlayer;
|
private final Player comPlayer;
|
||||||
|
|||||||
Binary file not shown.
114
test/model/comPlayer/SpeedTest.java
Normal file
114
test/model/comPlayer/SpeedTest.java
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
package model.comPlayer;
|
||||||
|
|
||||||
|
import org.junit.Ignore;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import model.Board;
|
||||||
|
import model.Board.TileColor;
|
||||||
|
import model.playerModel.PlayerModel;
|
||||||
|
import model.CellPointer;
|
||||||
|
|
||||||
|
public class SpeedTest {
|
||||||
|
private static final Board board = new Board();
|
||||||
|
private static final int nTestRounds = 10;
|
||||||
|
private static final int lookahead = 3;
|
||||||
|
|
||||||
|
static {
|
||||||
|
board.playTile(new CellPointer(2,2), TileColor.BLUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRandom() {
|
||||||
|
long testTime = 0L;
|
||||||
|
|
||||||
|
RandomComPlayer player = new RandomComPlayer();
|
||||||
|
|
||||||
|
PlayerModel model = new PlayerModel("test");
|
||||||
|
|
||||||
|
for (int testRound = 0; testRound < nTestRounds; testRound++) {
|
||||||
|
Board newBoard = new Board(board);
|
||||||
|
|
||||||
|
long testStart = System.currentTimeMillis();
|
||||||
|
player.getMove(newBoard, model);
|
||||||
|
long testEnd = System.currentTimeMillis();
|
||||||
|
|
||||||
|
testTime += testEnd - testStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
double avgTime = testTime / (nTestRounds * 1000.0);
|
||||||
|
|
||||||
|
System.out.println("Average time for RandomMoveGenerator.genMove() over " + nTestRounds + " tests: " + avgTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMonteCarlo() {
|
||||||
|
long testTime = 0L;
|
||||||
|
|
||||||
|
MonteCarloComPlayer player = new MonteCarloComPlayer();
|
||||||
|
player.moveGenerator.setLookahead(lookahead);
|
||||||
|
|
||||||
|
PlayerModel model = new PlayerModel("test");
|
||||||
|
|
||||||
|
for (int testRound = 0; testRound < nTestRounds; testRound++) {
|
||||||
|
Board newBoard = new Board(board);
|
||||||
|
|
||||||
|
long testStart = System.currentTimeMillis();
|
||||||
|
player.getMove(newBoard, model);
|
||||||
|
long testEnd = System.currentTimeMillis();
|
||||||
|
|
||||||
|
testTime += testEnd - testStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
double avgTime = testTime / (nTestRounds * 1000.0);
|
||||||
|
|
||||||
|
System.out.println("Average time for MonteCarloGenerator.genMove() over " + nTestRounds + " tests: " + avgTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore
|
||||||
|
public void testMinimax() {
|
||||||
|
long testTime = 0L;
|
||||||
|
|
||||||
|
MinimaxComPlayer player = new MinimaxComPlayer();
|
||||||
|
player.moveGenerator.setLookahead(lookahead);
|
||||||
|
|
||||||
|
PlayerModel model = new PlayerModel("test");
|
||||||
|
|
||||||
|
for (int testRound = 0; testRound < nTestRounds; testRound++) {
|
||||||
|
Board newBoard = new Board(board);
|
||||||
|
|
||||||
|
long testStart = System.currentTimeMillis();
|
||||||
|
player.getMove(newBoard, model);
|
||||||
|
long testEnd = System.currentTimeMillis();
|
||||||
|
|
||||||
|
testTime += testEnd - testStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
double avgTime = testTime / (nTestRounds * 1000.0);
|
||||||
|
|
||||||
|
System.out.println("Average time for MinimaxMoveGenerator.genMove() over " + nTestRounds + " tests: " + avgTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAlphaBeta() {
|
||||||
|
long testTime = 0L;
|
||||||
|
|
||||||
|
AlphaBetaComPlayer player = new AlphaBetaComPlayer();
|
||||||
|
player.moveGenerator.setLookahead(lookahead);
|
||||||
|
|
||||||
|
PlayerModel model = new PlayerModel("test");
|
||||||
|
|
||||||
|
for (int testRound = 0; testRound < nTestRounds; testRound++) {
|
||||||
|
Board newBoard = new Board(board);
|
||||||
|
|
||||||
|
long testStart = System.currentTimeMillis();
|
||||||
|
player.getMove(newBoard, model);
|
||||||
|
long testEnd = System.currentTimeMillis();
|
||||||
|
|
||||||
|
testTime += testEnd - testStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
double avgTime = testTime / (nTestRounds * 1000.0);
|
||||||
|
|
||||||
|
System.out.println("Average time for AlphaBetaMoveGenerator.genMove() over " + nTestRounds + " tests: " + avgTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user