diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..d7263b1 --- /dev/null +++ b/README.txt @@ -0,0 +1 @@ +Wood texture is from open source Wordpress resource site wpliving.net. \ No newline at end of file diff --git a/src/net/woodyfolsom/msproj/StandAloneGame.java b/src/net/woodyfolsom/msproj/StandAloneGame.java index 3065407..ba20d68 100644 --- a/src/net/woodyfolsom/msproj/StandAloneGame.java +++ b/src/net/woodyfolsom/msproj/StandAloneGame.java @@ -3,6 +3,8 @@ package net.woodyfolsom.msproj; import java.util.ArrayList; import java.util.List; +import net.woodyfolsom.msproj.gui.Goban; +import net.woodyfolsom.msproj.policy.HumanGuiInput; import net.woodyfolsom.msproj.policy.HumanKeyboardInput; import net.woodyfolsom.msproj.policy.MonteCarloUCT; import net.woodyfolsom.msproj.policy.Policy; @@ -10,8 +12,12 @@ import net.woodyfolsom.msproj.policy.RandomMovePolicy; import net.woodyfolsom.msproj.policy.RootParallelization; public class StandAloneGame { + private static final double DEFAULT_KOMI = 5.5; + private static final int DEFAULT_NUM_GAMES = 1; + private static final int DEFAULT_SIZE = 9; + enum PLAYER_TYPE { - HUMAN, ROOT_PAR, UCT_FAST, UCT_SLOW + HUMAN, HUMAN_GUI, ROOT_PAR, UCT_FAST, UCT_SLOW }; public static void main(String[] args) { @@ -21,8 +27,23 @@ public class StandAloneGame { System.out .println("For example to play 10 games against MC UCT w/ slow moves: StandAloneGame UCT_SLOW HUMAN 10"); } + int nGames = DEFAULT_NUM_GAMES; + int size = DEFAULT_SIZE; + double komi = DEFAULT_KOMI; + + switch (args.length) { + case 5: + nGames = Integer.valueOf(args[4]); + case 4: + komi = Double.valueOf(args[3]); + case 3: + size = Integer.valueOf(args[2]); + break; + default: + System.out.println("Arguments #3-5 not specified. Using default size=" + size +", komi = " + komi +", nGames=" + nGames +"."); + } new StandAloneGame().playGame(parsePlayerType(args[0]), - parsePlayerType(args[1]), Integer.valueOf(args[2])); + parsePlayerType(args[1]), size, komi, nGames); } private static PLAYER_TYPE parsePlayerType(String playerTypeStr) { @@ -35,23 +56,25 @@ public class StandAloneGame { return PLAYER_TYPE.UCT_SLOW; } else if ("HUMAN".equalsIgnoreCase(playerTypeStr)) { return PLAYER_TYPE.HUMAN; + } else if ("HUMAN_GUI".equalsIgnoreCase(playerTypeStr)) { + return PLAYER_TYPE.HUMAN_GUI; } else { throw new RuntimeException("Unknown player type: " + playerTypeStr); } } public void playGame(PLAYER_TYPE playerType1, PLAYER_TYPE playerType2, - int rounds) { + int size, double komi, int rounds) { - Policy player1 = getPolicy(playerType1); - Policy player2 = getPolicy(playerType2); + GameConfig gameConfig = new GameConfig(size); + gameConfig.setKomi(komi); Referee referee = new Referee(); - referee.setPolicy(Player.BLACK, player1); - referee.setPolicy(Player.WHITE, player2); + referee.setPolicy(Player.BLACK, getPolicy(playerType1, gameConfig, Player.BLACK)); + referee.setPolicy(Player.WHITE, getPolicy(playerType2, gameConfig, Player.WHITE)); List results = new ArrayList(); - GameConfig gameConfig = new GameConfig(9); + for (int round = 0; round < rounds; round++) { results.add(referee.play(gameConfig)); } @@ -63,12 +86,14 @@ public class StandAloneGame { } } - private Policy getPolicy(PLAYER_TYPE playerType) { + private Policy getPolicy(PLAYER_TYPE playerType, GameConfig gameConfig, Player player) { switch (playerType) { case HUMAN: return new HumanKeyboardInput(); + case HUMAN_GUI: + return new HumanGuiInput(new Goban(gameConfig, player)); case ROOT_PAR: - return new RootParallelization(3, 6000L); + return new RootParallelization(4, 6000L); case UCT_SLOW: return new MonteCarloUCT(new RandomMovePolicy(), 4000L); case UCT_FAST: diff --git a/src/net/woodyfolsom/msproj/gui/BoardState.java b/src/net/woodyfolsom/msproj/gui/BoardState.java new file mode 100644 index 0000000..259503c --- /dev/null +++ b/src/net/woodyfolsom/msproj/gui/BoardState.java @@ -0,0 +1,13 @@ +package net.woodyfolsom.msproj.gui; + +public class BoardState { + + /** + * @param args + */ + public static void main(String[] args) { + // TODO Auto-generated method stub + + } + +} diff --git a/src/net/woodyfolsom/msproj/gui/Collision.java b/src/net/woodyfolsom/msproj/gui/Collision.java new file mode 100644 index 0000000..1e7cbfd --- /dev/null +++ b/src/net/woodyfolsom/msproj/gui/Collision.java @@ -0,0 +1,6 @@ +package net.woodyfolsom.msproj.gui; + +public class Collision { + + +} \ No newline at end of file diff --git a/src/net/woodyfolsom/msproj/gui/Goban.java b/src/net/woodyfolsom/msproj/gui/Goban.java new file mode 100644 index 0000000..136a041 --- /dev/null +++ b/src/net/woodyfolsom/msproj/gui/Goban.java @@ -0,0 +1,75 @@ +package net.woodyfolsom.msproj.gui; + +import java.awt.BorderLayout; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; + +import javax.swing.JFrame; + +import net.woodyfolsom.msproj.Action; +import net.woodyfolsom.msproj.GameConfig; +import net.woodyfolsom.msproj.GameState; +import net.woodyfolsom.msproj.Player; + +public class Goban extends JFrame implements KeyListener { + + private static final long serialVersionUID = 1L; + + //private GameState gameState; + private GridPanel gridPanel; + + /* + public static void main(String[] args) { + Goban goban = new Goban(); + goban.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + goban.setVisible(true); + goban.pack(); + }*/ + + public Goban(GameConfig gameConfig, Player guiPlayer) { + setLayout(new BorderLayout()); + this.gridPanel = new GridPanel(gameConfig, guiPlayer); + add(gridPanel,BorderLayout.CENTER); + addKeyListener(this); + + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + setVisible(true); + pack(); + } + + public Action getAction() { + return gridPanel.getAction(); + } + + public void setGameState(GameState gameState) { + gridPanel.setGameState(gameState); + } + + @Override + public void keyPressed(KeyEvent arg0) { + // TODO Auto-generated method stub + + } + + @Override + public void keyReleased(KeyEvent arg0) { + // TODO Auto-generated method stub + + } + + @Override + public void keyTyped(KeyEvent arg0) { + switch (arg0.getKeyChar()) + { + /* + case 't' : + case 'T' : + //Player currentPlayer = GoGame.getNextPlayer(gameState.getPlayerToMove()); + //System.out.println("Switching players. Current player is now " + currentPlayer); + //gameState. + break;*/ + default : + System.out.println("Ignoring unbound key: " + arg0.getKeyChar()); + } + } +} diff --git a/src/net/woodyfolsom/msproj/gui/GridPanel.java b/src/net/woodyfolsom/msproj/gui/GridPanel.java new file mode 100644 index 0000000..a9b0bd3 --- /dev/null +++ b/src/net/woodyfolsom/msproj/gui/GridPanel.java @@ -0,0 +1,284 @@ +package net.woodyfolsom.msproj.gui; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; +import java.net.URL; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; + +import javax.swing.ImageIcon; +import javax.swing.JPanel; + +import net.woodyfolsom.msproj.Action; +import net.woodyfolsom.msproj.GameBoard; +import net.woodyfolsom.msproj.GameConfig; +import net.woodyfolsom.msproj.GameState; +import net.woodyfolsom.msproj.Player; + +public class GridPanel extends JPanel implements MouseListener, + MouseMotionListener { + + private static final long serialVersionUID = 1L; + + private static final int BOARD_HEIGHT = 300; + private static final int BOARD_WIDTH = 300; + private static final int BORDER_WIDTH = 10; + + private static final int DOT_WIDTH = 5; + private static final int STONE_WIDTH = DOT_WIDTH * 2; + + private Image backgroundImg; + private int boardSize; + + private int mouseX = 0; + private int mouseY = 0; + + // + private char[][] board; + //private static final char WHITE = 'O'; + //private static final char BLACK = 'X'; + private static final char EMPTY = '.'; + // + + private GameState gameState; + private LinkedBlockingQueue actionQueue = new LinkedBlockingQueue(); + + private Player guiPlayer; + + private String[] COLS = { "A", "B", "C", "D", "E", "F", "G", "H", "J" }; + private String[] ROWS; + + public GridPanel(GameConfig gameConfig, Player guiPlayer) { + this.guiPlayer = guiPlayer; + + this.boardSize = gameConfig.getSize(); + + initRows(this.boardSize); + + this.setPreferredSize(new Dimension(BOARD_WIDTH + BORDER_WIDTH * 2, + BOARD_HEIGHT + BORDER_WIDTH * 2)); + URL urlBackgroundImg = getClass().getResource("wood3.jpg"); + this.backgroundImg = new ImageIcon(urlBackgroundImg).getImage(); + this.addMouseListener(this); + this.addMouseMotionListener(this); + + // + board = new char[boardSize][boardSize]; + for (int i = 0; i < boardSize; i++) { + for (int j = 0; j < boardSize; j++) { + board[i][j] = EMPTY; + } + } + } + + public Action getAction() { + int timeLimit = 10; + TimeUnit timeUnit = TimeUnit.SECONDS; + + try { + Action action = actionQueue.poll(timeLimit, timeUnit); + if (action == null) { + return Action.NONE; + } + return action; + } catch (InterruptedException ie) { + System.out.println("Interrupted while waiting " + timeLimit + " " + timeUnit + "s for player to move."); + return Action.NONE; + } + } + + private void initRows(int boardSize) { + ROWS = new String[boardSize]; + for (int i = 0; i < boardSize; i++) { + ROWS[i] = Integer.valueOf(boardSize - i).toString(); + } + } + + // Given a pair of (x,y) coordinates (pixels), returns a row index in the + // range [0..(boardSize-1)]. + private int getColumn(int x, int y) { + int intersectionSize = BOARD_WIDTH / boardSize; + + return (x - BORDER_WIDTH/*- centerOffset*/) / intersectionSize; + } + + // Given a pair of (x,y) coordinates (pixels), returns a row index in the + // range [0..(boardSize-1)]. + private int getRow(int x, int y) { + int intersectionSize = BOARD_WIDTH / boardSize; + + return (y - BORDER_WIDTH/*- centerOffset*/) / intersectionSize; + } + + @Override + protected void paintComponent(Graphics g) { + super.paintComponent(g); + + // tile wood texture + int iw = backgroundImg.getWidth(this); + int ih = backgroundImg.getHeight(this); + if (iw > 0 && ih > 0) { + for (int x = 0; x < getWidth(); x += iw) { + for (int y = 0; y < getHeight(); y += ih) { + g.drawImage(backgroundImg, x, y, iw, ih, this); + } + } + } + + int intersectionSize = BOARD_WIDTH / boardSize; + int centerOffset = intersectionSize / 2; + + g.translate(BORDER_WIDTH, BORDER_WIDTH); + + for (int row = 0; row < boardSize; row++) { + for (int col = 0; col < boardSize; col++) { + g.fillOval(intersectionSize * col + centerOffset - DOT_WIDTH, + intersectionSize * row + centerOffset - DOT_WIDTH, + DOT_WIDTH * 2, DOT_WIDTH * 2); + } + } + + for (int row = 0; row < boardSize; row++) { + g.drawLine(centerOffset, centerOffset + row * intersectionSize, + intersectionSize * boardSize - centerOffset, centerOffset + + row * intersectionSize); + } + + for (int col = 0; col < boardSize; col++) { + g.drawLine(centerOffset + col * intersectionSize, centerOffset, + centerOffset + col * intersectionSize, intersectionSize + * boardSize - centerOffset); + } + + Color defaultColor = g.getColor(); + g.setColor(Color.YELLOW); + + int stoneX = getColumn(mouseX, mouseY) * intersectionSize + + centerOffset; + int stoneY = getRow(mouseX, mouseY) * intersectionSize + centerOffset; + + g.drawOval(stoneX - STONE_WIDTH, stoneY - STONE_WIDTH, STONE_WIDTH * 2, + STONE_WIDTH * 2); + + g.setColor(defaultColor); + + for (int col = 0; col < boardSize; col++) { + // g.drawLine(centerOffset + col * intersectionSize, centerOffset, + // centerOffset + col * intersectionSize, intersectionSize * + // boardSize - centerOffset); + g.drawBytes(COLS[col].getBytes(), 0, 1, centerOffset + col + * intersectionSize - 5, BOARD_WIDTH + 5); + } + + for (int row = 0; row < boardSize; row++) { + // g.drawLine(centerOffset + col * intersectionSize, centerOffset, + // centerOffset + col * intersectionSize, intersectionSize * + // boardSize - centerOffset); + g.drawBytes(ROWS[row].getBytes(), 0, 1, BOARD_WIDTH - 5, + centerOffset + row * intersectionSize + 5); + } + + if (gameState != null) { + GameBoard gameBoard = gameState.getGameBoard(); + + for (int row = 0; row < boardSize; row++) { + for (int col = 0; col < boardSize; col++) { + + char symbol = gameBoard.getSymbolAt(col,boardSize - row - 1); + + switch (symbol) { + case 'X' : + g.setColor(Color.BLACK); + break; + case 'O' : + g.setColor(Color.WHITE); + break; + default : + continue; + } + + g.fillOval(intersectionSize * col + centerOffset - STONE_WIDTH, + intersectionSize * row + centerOffset - STONE_WIDTH, + STONE_WIDTH * 2, STONE_WIDTH * 2); + } + } + } + } + + public void setGameState(GameState gameState) { + this.gameState = gameState; + } + + @Override + public void mouseDragged(MouseEvent arg0) { + // TODO Auto-generated method stub + + } + + @Override + public void mouseMoved(MouseEvent arg0) { + this.mouseX = arg0.getX(); + this.mouseY = arg0.getY(); + + this.repaint(); + } + + @Override + public void mouseClicked(MouseEvent arg0) { + if (gameState == null) { + System.out.println("Wait your turn!"); + return; + } + + if (!actionQueue.isEmpty()) { + System.out.println("You already moved. Be patient!"); + return; + } + // ystem.out.println("Mouse clicked: " + arg0); + int row = getRow(mouseX, mouseY); + int column = getColumn(mouseX, mouseY); + + Player currentPlayer = gameState.getPlayerToMove(); + if (currentPlayer == guiPlayer) { + // gameState.playStone(guiPlayer, Action.getInstance(COLS[row] + + // ROWS[column])); + Action action = Action.getInstance(COLS[column] + ROWS[row]); + System.out.println("Made move: " + action); + actionQueue.add(action); + } else { + System.out.println("Not your turn!"); + } + + this.repaint(); + } + + @Override + public void mouseEntered(MouseEvent arg0) { + // TODO Auto-generated method stub + + } + + @Override + public void mouseExited(MouseEvent arg0) { + // TODO Auto-generated method stub + + } + + @Override + public void mousePressed(MouseEvent arg0) { + // TODO Auto-generated method stub + + } + + @Override + public void mouseReleased(MouseEvent arg0) { + // TODO Auto-generated method stub + + } + +} \ No newline at end of file diff --git a/src/net/woodyfolsom/msproj/gui/Stone.java b/src/net/woodyfolsom/msproj/gui/Stone.java new file mode 100644 index 0000000..aea1aeb --- /dev/null +++ b/src/net/woodyfolsom/msproj/gui/Stone.java @@ -0,0 +1,6 @@ +package net.woodyfolsom.msproj.gui; + +public class Stone { + + +} \ No newline at end of file diff --git a/src/net/woodyfolsom/msproj/gui/wood3.jpg b/src/net/woodyfolsom/msproj/gui/wood3.jpg new file mode 100644 index 0000000..adeb10d Binary files /dev/null and b/src/net/woodyfolsom/msproj/gui/wood3.jpg differ diff --git a/src/net/woodyfolsom/msproj/policy/HumanGuiInput.java b/src/net/woodyfolsom/msproj/policy/HumanGuiInput.java new file mode 100644 index 0000000..65ce15b --- /dev/null +++ b/src/net/woodyfolsom/msproj/policy/HumanGuiInput.java @@ -0,0 +1,54 @@ +package net.woodyfolsom.msproj.policy; + +import java.io.IOException; +import java.util.Collection; + +import net.woodyfolsom.msproj.Action; +import net.woodyfolsom.msproj.GameConfig; +import net.woodyfolsom.msproj.GameState; +import net.woodyfolsom.msproj.Player; +import net.woodyfolsom.msproj.gui.Goban; + +public class HumanGuiInput implements Policy { + private Goban goban; + + public HumanGuiInput(Goban goban) { + this.goban = goban; + } + + @Override + public Action getAction(GameConfig gameConfig, GameState gameState, + Player player) { + Action action = null; + String input = ""; + + do { + System.out.println(player + + " to move: (Use GUI)"); + + goban.setGameState(gameState); + action = goban.getAction(); + + if (action.isNone()) { + System.out.println("No move was made within 10 seconds. Hurry up!"); + System.out.println(gameState); + continue; + } + } while (action == null); + + return action; + } + + @Override + public Action getAction(GameConfig gameConfig, GameState gameState, + Collection prohibitedActions, Player player) { + throw new UnsupportedOperationException("Not implemented"); + } + + @Override + public int getNumStateEvaluations() { + // TODO Auto-generated method stub + return 1; + } + +} diff --git a/src/net/woodyfolsom/msproj/policy/MonteCarlo.java b/src/net/woodyfolsom/msproj/policy/MonteCarlo.java index 4f3de3a..6137e94 100644 --- a/src/net/woodyfolsom/msproj/policy/MonteCarlo.java +++ b/src/net/woodyfolsom/msproj/policy/MonteCarlo.java @@ -13,7 +13,7 @@ import net.woodyfolsom.msproj.tree.GameTreeNode; import net.woodyfolsom.msproj.tree.MonteCarloProperties; public abstract class MonteCarlo implements Policy { - protected static final int ROLLOUT_DEPTH_LIMIT = 100; + protected static final int ROLLOUT_DEPTH_LIMIT = 400; protected int numStateEvaluations = 0; protected Policy movePolicy; diff --git a/src/net/woodyfolsom/msproj/policy/MonteCarloAMAF.java b/src/net/woodyfolsom/msproj/policy/MonteCarloAMAF.java new file mode 100644 index 0000000..7c46576 --- /dev/null +++ b/src/net/woodyfolsom/msproj/policy/MonteCarloAMAF.java @@ -0,0 +1,10 @@ +package net.woodyfolsom.msproj.policy; + + +public class MonteCarloAMAF extends MonteCarloUCT { + + public MonteCarloAMAF(Policy movePolicy, long searchTimeLimit) { + super(movePolicy, searchTimeLimit); + } + +} \ No newline at end of file