Compare commits

..

11 Commits

Author SHA1 Message Date
1f7ff56204 Updated build for Java 8. Version 6 is no longer supported as of Java SE JDK 25. 2026-02-10 11:33:51 -05:00
Woody Folsom
b8d9480ae7 Added license and README.txt. 2012-05-02 08:30:14 -04:00
Woody Folsom
3ba0db6ebd All MoveGenerators default to 1 move lookahead.
Made MoveGenerators protected for unit testing.
Added unit test for some analysis of MoveGenerator speeds.
Fixed MDP to consider all states where #turns = maxTurns terminal.
2012-05-01 22:24:02 -04:00
Woody Folsom
924780baaf Substantially improved performance of Board.isLegal().
No longer a static method.
AlphaBeta is now playable with 4-move lookahead (although slow).
2012-05-01 09:38:32 -04:00
Woody Folsom
48915071d4 Now allows a leading - character for command-line arguments. The presence or absence of this character a has not effect. 2012-05-01 09:11:39 -04:00
Woody Folsom
490d3d0bf6 Fixed various errors when target = 0. 2012-04-30 19:53:46 -04:00
Woody Folsom
f4ed883d63 Removed references to log4j. 2012-04-30 19:40:43 -04:00
Marshall
a9fbdfb50e Merge branch 'master' of woodyfolsom.net:/opt/git/cs8803p4 2012-04-30 19:11:48 -04:00
Marshall
f6e4a32b82 - Added rules text. 2012-04-30 19:11:32 -04:00
Woody Folsom
e9ead0edda Merge branch 'master' of woodyfolsom.net:/opt/git/cs8803p4 2012-04-30 18:36:09 -04:00
Marshall
f81db19586 - Test PlayerModel.dat file should not be versioned, I don't think... 2012-04-30 17:59:44 -04:00
24 changed files with 233 additions and 100 deletions

View File

@@ -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
View 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
View 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.

View File

@@ -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.

View File

@@ -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>() {

View File

@@ -12,13 +12,19 @@ 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;
@@ -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;
}
} }

View File

@@ -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) {

View File

@@ -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 #" +

View File

@@ -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() {

View File

@@ -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));

View File

@@ -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();

View File

@@ -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() {

View File

@@ -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;
}
} }

View File

@@ -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;
}
} }

View File

@@ -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;
}
} }

View File

@@ -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);
} }

View File

@@ -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;
}
} }

View File

@@ -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;
}
} }

View File

@@ -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;

View File

@@ -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.

View 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);
}
}