Added simple GUI for 9x9 go. Use HUMAN_GUI player option.

This commit is contained in:
2012-11-13 10:38:34 -05:00
parent c8dff2f594
commit 8c69c62184
11 changed files with 485 additions and 11 deletions

1
README.txt Normal file
View File

@@ -0,0 +1 @@
Wood texture is from open source Wordpress resource site wpliving.net.

View File

@@ -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<GameResult> results = new ArrayList<GameResult>();
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:

View File

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

View File

@@ -0,0 +1,6 @@
package net.woodyfolsom.msproj.gui;
public class Collision {
}

View File

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

View File

@@ -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<Action> actionQueue = new LinkedBlockingQueue<Action>();
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
}
}

View File

@@ -0,0 +1,6 @@
package net.woodyfolsom.msproj.gui;
public class Stone {
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

View File

@@ -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<Action> prohibitedActions, Player player) {
throw new UnsupportedOperationException("Not implemented");
}
@Override
public int getNumStateEvaluations() {
// TODO Auto-generated method stub
return 1;
}
}

View File

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

View File

@@ -0,0 +1,10 @@
package net.woodyfolsom.msproj.policy;
public class MonteCarloAMAF extends MonteCarloUCT {
public MonteCarloAMAF(Policy movePolicy, long searchTimeLimit) {
super(movePolicy, searchTimeLimit);
}
}