diff --git a/src/net/woodyfolsom/msproj/Referee.java b/src/net/woodyfolsom/msproj/Referee.java index cbece3a..c719f2a 100644 --- a/src/net/woodyfolsom/msproj/Referee.java +++ b/src/net/woodyfolsom/msproj/Referee.java @@ -39,7 +39,13 @@ public class Referee { GameRecord gameRecord = new GameRecord(gameConfig); System.out.println("Game started."); - + + GameState initialGameState = gameRecord.getGameState(gameRecord.getNumTurns()); + + //Allow policy / GUI to do setup. + blackPolicy.setState(initialGameState); + whitePolicy.setState(initialGameState); + try { while (!gameRecord.isFinished()) { GameState gameState = gameRecord.getGameState(gameRecord.getNumTurns()); diff --git a/src/net/woodyfolsom/msproj/gui/Goban.java b/src/net/woodyfolsom/msproj/gui/Goban.java index 05f7088..54041cb 100644 --- a/src/net/woodyfolsom/msproj/gui/Goban.java +++ b/src/net/woodyfolsom/msproj/gui/Goban.java @@ -3,6 +3,8 @@ package net.woodyfolsom.msproj.gui; import java.awt.BorderLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; import javax.swing.JButton; import javax.swing.JFrame; @@ -12,16 +14,32 @@ import net.woodyfolsom.msproj.Action; import net.woodyfolsom.msproj.GameConfig; import net.woodyfolsom.msproj.GameState; import net.woodyfolsom.msproj.Player; +import net.woodyfolsom.msproj.sfx.SfxPlayer; public class Goban extends JFrame { private static final long serialVersionUID = 1L; private GridPanel gridPanel; + private SfxPlayer sfxPlayer; public Goban(GameConfig gameConfig, Player guiPlayer) { setLayout(new BorderLayout()); - this.gridPanel = new GridPanel(gameConfig, guiPlayer); + + addWindowListener(new WindowAdapter() { + @Override + public void windowClosing(WindowEvent e) { + sfxPlayer.cleanup(); + } + }); + + try { + sfxPlayer = new SfxPlayer(); + } catch (Exception ex) { + System.out.println("Unable to initialize click sound due to: " + ex.getMessage()); + } + + this.gridPanel = new GridPanel(gameConfig, guiPlayer, sfxPlayer); add(gridPanel,BorderLayout.CENTER); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); diff --git a/src/net/woodyfolsom/msproj/gui/GridPanel.java b/src/net/woodyfolsom/msproj/gui/GridPanel.java index 60751f4..9ec3d82 100644 --- a/src/net/woodyfolsom/msproj/gui/GridPanel.java +++ b/src/net/woodyfolsom/msproj/gui/GridPanel.java @@ -1,6 +1,7 @@ package net.woodyfolsom.msproj.gui; import java.awt.Color; +import java.awt.Cursor; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Image; @@ -19,14 +20,15 @@ import net.woodyfolsom.msproj.GameBoard; import net.woodyfolsom.msproj.GameConfig; import net.woodyfolsom.msproj.GameState; import net.woodyfolsom.msproj.Player; +import net.woodyfolsom.msproj.sfx.SfxPlayer; 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 final int boardPixelWidth; + private static final int BORDER_WIDTH = 10; private static final int DOT_WIDTH = 5; @@ -37,43 +39,36 @@ public class GridPanel extends JPanel implements MouseListener, 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 SfxPlayer sfxPlayer; + private String[] COLS = { "A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T" }; private String[] ROWS; - public GridPanel(GameConfig gameConfig, Player guiPlayer) { + public GridPanel(GameConfig gameConfig, Player guiPlayer, SfxPlayer sfxPlayer) { this.guiPlayer = guiPlayer; - + this.sfxPlayer = sfxPlayer; this.boardSize = gameConfig.getSize(); initRows(this.boardSize); - this.setPreferredSize(new Dimension(BOARD_WIDTH + BORDER_WIDTH * 2, - BOARD_HEIGHT + BORDER_WIDTH * 2)); + if (boardSize <= 9) { + boardPixelWidth = 300; + } else if (boardSize <= 13) { + boardPixelWidth = 434; + } else { + boardPixelWidth = 634; + } + this.setPreferredSize(new Dimension(boardPixelWidth + BORDER_WIDTH * 2, + boardPixelWidth + 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 void addAction(Action action) { @@ -106,7 +101,7 @@ public class GridPanel extends JPanel implements MouseListener, // 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; + int intersectionSize = boardPixelWidth / boardSize; return (x - BORDER_WIDTH/*- centerOffset*/) / intersectionSize; } @@ -114,7 +109,7 @@ public class GridPanel extends JPanel implements MouseListener, // 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; + int intersectionSize = boardPixelWidth / boardSize; return (y - BORDER_WIDTH/*- centerOffset*/) / intersectionSize; } @@ -134,19 +129,13 @@ public class GridPanel extends JPanel implements MouseListener, } } - int intersectionSize = BOARD_WIDTH / boardSize; + int intersectionSize = boardPixelWidth / 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); - } - } - + g.setColor(Color.BLACK); + for (int row = 0; row < boardSize; row++) { g.drawLine(centerOffset, centerOffset + row * intersectionSize, intersectionSize * boardSize - centerOffset, centerOffset @@ -159,31 +148,17 @@ public class GridPanel extends JPanel implements MouseListener, * 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); + int mouseCol = getColumn(mouseX, mouseY); + int mouseRow = getRow(mouseX, mouseY); 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); + * intersectionSize - 5, boardPixelWidth + 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, + byte[] bytes = ROWS[row].getBytes(); + g.drawBytes(bytes, 0, bytes.length, boardPixelWidth - 5, centerOffset + row * intersectionSize + 5); } @@ -196,19 +171,44 @@ public class GridPanel extends JPanel implements MouseListener, char symbol = gameBoard.getSymbolAt(col,boardSize - row - 1); switch (symbol) { - case 'X' : + case GameBoard.BLACK_STONE : g.setColor(Color.BLACK); + g.fillOval(intersectionSize * col + centerOffset - STONE_WIDTH, + intersectionSize * row + centerOffset - STONE_WIDTH, + STONE_WIDTH * 2, STONE_WIDTH * 2); break; - case 'O' : + case GameBoard.WHITE_STONE : g.setColor(Color.WHITE); + g.fillOval(intersectionSize * col + centerOffset - STONE_WIDTH, + intersectionSize * row + centerOffset - STONE_WIDTH, + STONE_WIDTH * 2, STONE_WIDTH * 2); + break; + case GameBoard.EMPTY_INTERSECTION : + if (row == mouseRow && col == mouseCol && gameState.getPlayerToMove() == guiPlayer) { + if (guiPlayer == Player.BLACK) { + g.setColor(Color.BLACK); + } else if (guiPlayer == Player.WHITE) { + g.setColor(Color.WHITE); + } else { + throw new RuntimeException("Invalid guiPlayer: " + guiPlayer); + } + g.fillOval(intersectionSize * col + centerOffset - STONE_WIDTH, + intersectionSize * row + centerOffset - STONE_WIDTH, + STONE_WIDTH * 2, STONE_WIDTH * 2); + g.setColor(Color.RED); + g.drawOval(intersectionSize * col + centerOffset - STONE_WIDTH, + intersectionSize * row + centerOffset - STONE_WIDTH, + STONE_WIDTH * 2, STONE_WIDTH * 2); + } else { + g.setColor(Color.BLACK); + g.fillOval(intersectionSize * col + centerOffset - DOT_WIDTH, + intersectionSize * row + centerOffset - DOT_WIDTH, + DOT_WIDTH * 2, DOT_WIDTH * 2); + } break; default : continue; } - - g.fillOval(intersectionSize * col + centerOffset - STONE_WIDTH, - intersectionSize * row + centerOffset - STONE_WIDTH, - STONE_WIDTH * 2, STONE_WIDTH * 2); } } } @@ -216,7 +216,21 @@ public class GridPanel extends JPanel implements MouseListener, public void setGameState(GameState gameState) { this.gameState = gameState; + + if (gameState.getPlayerToMove() == guiPlayer || gameState.isTerminal()) { + setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + } else { + setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + } + this.repaint(); + + new Thread(new Runnable() { + + @Override + public void run() { + sfxPlayer.play(); + }}).start(); } @Override @@ -248,6 +262,14 @@ public class GridPanel extends JPanel implements MouseListener, int row = getRow(mouseX, mouseY); int column = getColumn(mouseX, mouseY); + if (row < 0 || row >= boardSize) { + return; + } + + if (column < 0 || column >= boardSize) { + return; + } + Player currentPlayer = gameState.getPlayerToMove(); if (currentPlayer == guiPlayer) { // gameState.playStone(guiPlayer, Action.getInstance(COLS[row] + diff --git a/src/net/woodyfolsom/msproj/sfx/Click-SoundBible.com-1387633738.wav b/src/net/woodyfolsom/msproj/sfx/Click-SoundBible.com-1387633738.wav new file mode 100644 index 0000000..1d3143b Binary files /dev/null and b/src/net/woodyfolsom/msproj/sfx/Click-SoundBible.com-1387633738.wav differ diff --git a/src/net/woodyfolsom/msproj/sfx/SfxPlayer.java b/src/net/woodyfolsom/msproj/sfx/SfxPlayer.java new file mode 100644 index 0000000..b23c5a9 --- /dev/null +++ b/src/net/woodyfolsom/msproj/sfx/SfxPlayer.java @@ -0,0 +1,41 @@ +package net.woodyfolsom.msproj.sfx; + +import java.io.IOException; +import java.io.InputStream; + +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.Clip; +import javax.sound.sampled.LineUnavailableException; +import javax.sound.sampled.UnsupportedAudioFileException; + +public class SfxPlayer { + private static final String clickFilename = "Click-SoundBible.com-1387633738.wav"; + private Clip clip; + + public SfxPlayer() throws LineUnavailableException, IOException, UnsupportedAudioFileException { + init(); + } + + public void cleanup() { + if (clip != null) { + clip.close(); + } + } + + public void init() throws LineUnavailableException, IOException, UnsupportedAudioFileException { + if (clip != null) { + clip.close(); + } + + InputStream inputStream = SfxPlayer.class.getResourceAsStream(clickFilename); + clip = AudioSystem.getClip(); + clip.open(AudioSystem.getAudioInputStream(inputStream)); + } + + public void play() { + if (clip!= null && !clip.isActive()) { + clip.setFramePosition(0); + clip.start(); + } + } +}