Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package reversi;
- import java.util.*;
- import java.awt.*;
- import java.awt.event.*;
- import java.awt.geom.*;
- import javax.swing.*;
- /**
- * SquareValue represents one of the three states a square on the board can be
- * in
- */
- enum SquareValue {
- EMPTY,
- PLAYER,
- CPU;
- }
- /**
- * Move represents a move on the board
- */
- class Move implements Comparable<Move> {
- private int x;
- private int y;
- private SquareValue player;
- private int total;
- private boolean directionUsed[];
- private int directionRun[];
- /**
- * Constructs a new move
- *
- * @param board board to put the move on
- * @param x X position on the board
- * @param y Y position on the board
- * @param player player making the move
- */
- public Move(Board board, int x, int y, SquareValue player) {
- this.x = x;
- this.y = y;
- this.player = player;
- directionUsed = new boolean[8];
- directionRun = new int[8];
- total = 0;
- // check for the opposite of the move's color
- SquareValue checkValue = player == SquareValue.CPU ? SquareValue.PLAYER : SquareValue.CPU;
- for (int i = 0; i < directionUsed.length; i++) {
- int length = board.getRun(x, y, i, checkValue);
- directionRun[i] = length;
- directionUsed[i] = length > 0;
- total += length;
- }
- }
- /**
- * Gets the X position of the move
- *
- * @return the X position
- */
- public int getX() {
- return x;
- }
- /**
- * Gets the Y position of the move
- *
- * @return the Y position
- */
- public int getY() {
- return y;
- }
- /**
- * Gets the player associated with the move
- *
- * @return the player
- */
- public SquareValue getPlayer() {
- return player;
- }
- /**
- * Checks if a given direction is used
- *
- * @param direction direction to check
- * @return whether the direction is used
- */
- public boolean isDirectionUsed(int direction) {
- return directionUsed[direction];
- }
- /**
- * Gets the amount of possible flips are in a given direction
- *
- * @param direction direction to check
- * @return amount of flips in that direction
- */
- public int getDirectionRun(int direction) {
- return directionRun[direction];
- }
- /**
- * Gets the total number of flips in the move
- *
- * @return total number of flips
- */
- public int getTotal() {
- return total;
- }
- /**
- * Checks if the move is valid or not
- *
- * @return whether or not the move is valid
- */
- public boolean isValid() {
- return total > 0;
- }
- /**
- * Compares two moves
- *
- * @param other other move
- * @return result of the comparison with the other move
- */
- @Override
- public int compareTo(Move other) {
- return this.total - other.total;
- }
- }
- /**
- * Represents a board full of squares
- */
- class Board {
- public static final int WIDTH = 8;
- public static final int HEIGHT = 8;
- // the dir_ tables are offsets for moving in a direction on the board
- public static final int dirX[] = {1, 1, 0, -1, -1, -1, 0, 1};
- public static final int dirY[] = {0, 1, 1, 1, 0, -1, -1, -1};
- private SquareValue squares[][];
- /**
- * Applies a given move to the board
- *
- * @param move move to apply
- */
- void applyMove(Move move) {
- SquareValue value = move.getPlayer();
- squares[move.getX()][move.getY()] = value;
- for (int i = 0; i < 8; i++) {
- if (move.isDirectionUsed(i)) {
- int x = move.getX();
- int y = move.getY();
- for (int length = move.getDirectionRun(i); length > 0; length--) {
- x += dirX[i];
- y += dirY[i];
- squares[x][y] = value;
- }
- }
- }
- }
- /**
- * Sets the value of a square on the board
- *
- * @param x X position
- * @param y Y position
- * @param value value to set
- */
- public void setSquare(int x, int y, SquareValue value) {
- squares[x][y] = value;
- }
- /**
- * Gets the value of a given square
- *
- * @param x X position
- * @param y Y position
- * @return value of the square
- */
- public SquareValue getSquare(int x, int y) {
- return squares[x][y];
- }
- /**
- * Checks if a given X and Y position are actually on the board
- *
- * @param x X position
- * @param y Y position
- * @return whether or not the square is on the board
- */
- public static boolean isSquareOnBoard(int x, int y) {
- return x >= 0 && x < WIDTH && y >= 0 && y < HEIGHT;
- }
- /**
- * Gets the total for a specific player
- *
- * @param value value to count towards the total
- * @return total
- */
- public int getPlayerTotal(SquareValue value) {
- int total = 0;
- for (SquareValue col[] : squares) {
- for (SquareValue cell : col) {
- total += cell == value ? 1 : 0;
- }
- }
- return total;
- }
- /**
- * Get the number of flippable circles in a given direction
- *
- * @param x X position
- * @param y Y position
- * @param direction direction to check in
- * @param value color of circles to check for
- * @return number of flippable circles
- */
- public int getRun(int x, int y, int direction, SquareValue value) {
- // starting at a non-empty square is invalid
- if (squares[x][y] != SquareValue.EMPTY) {
- return 0;
- }
- // starts at zero because the loop will increase it to 0
- int count = -1;
- do {
- count++;
- x += dirX[direction];
- y += dirY[direction];
- if (!isSquareOnBoard(x, y)) { // not valid if it goes off the board
- return 0;
- }
- } while (squares[x][y] == value);
- // the next square after the run can't be empty
- // because there needs to be another square on the end
- if (squares[x][y] == SquareValue.EMPTY) {
- return 0;
- }
- return count;
- }
- /**
- * Constructs a new board
- */
- public Board() {
- squares = new SquareValue[WIDTH][];
- for (int x = 0; x < WIDTH; x++) {
- squares[x] = new SquareValue[HEIGHT];
- for (int y = 0; y < HEIGHT; y++) {
- squares[x][y] = SquareValue.EMPTY;
- }
- }
- }
- }
- /**
- * Main class that simply sets up the frame
- */
- public class Main {
- public static void main(String[] args) {
- MyFrame frame = new MyFrame();
- ReversiPanel panel = new ReversiPanel(frame);
- frame.add(panel);
- frame.setVisible(true);
- }
- }
- /**
- * Holder for MyPanel
- */
- class MyFrame extends JFrame {
- public static final int WIDTH = 400;
- public static final int HEIGHT = 400;
- public MyFrame() {
- super();
- setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
- setSize(WIDTH, HEIGHT);
- setResizable(false);
- }
- }
- /**
- * Contains most of the Reversi implementation
- */
- class ReversiPanel extends JPanel {
- private Board board;
- private int mouseX, mouseY; // positions in pixels
- private int mouseBoardX = -1, mouseBoardY = -1; // positions on the board
- private boolean mouseEntered = false; // mouse is on the window
- private Move move = null;
- private JFrame parent;
- /**
- * Gets a random number from 0 to max
- *
- * @param max limit for the random numbers
- * @return a random number
- */
- private int random(int max) {
- return (int) (Math.random() * max);
- }
- /**
- * Try all possible moves
- *
- * @param value player to check for
- * @return all possible moves in an array
- */
- private Move[][] getAllPossibleMoves(SquareValue value) {
- Move[][] out = new Move[Board.WIDTH][];
- for (int x = 0; x < Board.WIDTH; x++) {
- out[x] = new Move[Board.HEIGHT];
- for (int y = 0; y < Board.HEIGHT; y++) {
- out[x][y] = new Move(board, x, y, value);
- }
- }
- return out;
- }
- /**
- * Makes an ArrayList of all the valid moves in a 2D array
- *
- * @param all array of moves
- * @return the list of moves
- */
- private ArrayList<Move> getValidMovesOnly(Move[][] all) {
- ArrayList<Move> valid = new ArrayList<>();
- // add all valid moves to list
- for (int x = 0; x < Board.WIDTH; x++) {
- for (int y = 0; y < Board.HEIGHT; y++) {
- if (all[x][y].isValid()) {
- valid.add(all[x][y]);
- }
- }
- }
- return valid;
- }
- /**
- * Do the computer's turn
- */
- private void doComputerMove() {
- Move all[][] = getAllPossibleMoves(SquareValue.CPU);
- // take the corners if possible
- if (all[0][0].isValid()) {
- board.applyMove(all[0][0]);
- } else if (all[Board.WIDTH - 1][0].isValid()) {
- board.applyMove(all[Board.WIDTH - 1][0]);
- } else if (all[0][Board.HEIGHT - 1].isValid()) {
- board.applyMove(all[0][Board.HEIGHT - 1]);
- } else if (all[Board.WIDTH - 1][Board.HEIGHT - 1].isValid()) {
- board.applyMove(all[Board.WIDTH - 1][Board.HEIGHT - 1]);
- } else { // pick the move that removes the fewest player's circles
- ArrayList<Move> valid = getValidMovesOnly(all);
- // skip if no valid moves
- if (valid.size() > 0) {
- Collections.sort(valid);
- // find the number of moves with the smallest total
- int max;
- for (max = 0; max < valid.size() && valid.get(max).getTotal()
- == valid.get(0).getTotal(); max++);
- // apply a random move out of these
- board.applyMove(valid.get(random(max)));
- }
- }
- }
- /**
- * Reacts to mouse clicks, enters and exits
- */
- private class MouseHandler extends MouseAdapter {
- /**
- * Reacts to a mouse click
- *
- * @param e mouse event
- */
- public void mousePressed(MouseEvent e) {
- if (move != null && move.isValid()) {
- applyMove();
- move = null;
- }
- repaint();
- }
- /**
- * Reacts to a mouse enter
- *
- * @param e mouse event
- */
- public void mouseEntered(MouseEvent e) {
- mouseEntered = true;
- repaint();
- }
- /**
- * Reacts to a mouse exit
- *
- * @param e mouse event
- */
- public void mouseExited(MouseEvent e) {
- mouseEntered = false;
- repaint();
- }
- }
- /**
- * Reacts to mouse moving
- */
- private class MouseMotionHandler extends MouseMotionAdapter {
- /**
- * Reacts to a mouse move
- *
- * @param e mouse event
- */
- public void mouseMoved(MouseEvent e) {
- mouseX = e.getX();
- mouseY = e.getY();
- updateMove();
- repaint();
- }
- }
- /**
- * Resets the board
- */
- private void resetBoard() {
- board = new Board();
- // create starting layout
- board.setSquare(Board.WIDTH / 2 - 0, Board.HEIGHT / 2 - 0, SquareValue.PLAYER);
- board.setSquare(Board.WIDTH / 2 - 1, Board.HEIGHT / 2 - 0, SquareValue.CPU);
- board.setSquare(Board.WIDTH / 2 - 0, Board.HEIGHT / 2 - 1, SquareValue.CPU);
- board.setSquare(Board.WIDTH / 2 - 1, Board.HEIGHT / 2 - 1, SquareValue.PLAYER);
- }
- /**
- * Constructs the panel
- */
- public ReversiPanel(JFrame parent) {
- super();
- resetBoard();
- this.parent = parent;
- // add listeners
- addMouseListener(new MouseHandler());
- addMouseMotionListener(new MouseMotionHandler());
- }
- /**
- * Resets the game
- */
- public void resetGame() {
- resetBoard();
- repaint();
- }
- /**
- * Apply the player's move, and do the computer's move
- */
- public void applyMove() {
- if (move != null && move.isValid()) {
- board.applyMove(move);
- while (true) {
- doComputerMove();
- ArrayList<Move> player = getValidMovesOnly(getAllPossibleMoves(SquareValue.PLAYER));
- ArrayList<Move> cpu = getValidMovesOnly(getAllPossibleMoves(SquareValue.CPU));
- if (player.size() == 0 && cpu.size() == 0) { // game over
- GameResultsDialog test = new GameResultsDialog(board.getPlayerTotal(SquareValue.PLAYER),
- board.getPlayerTotal(SquareValue.CPU), parent, this);
- test.setVisible(true);
- return;
- }
- if(player.size() != 0) { // keep doing computer turns if player can't move
- break;
- }
- }
- }
- }
- /**
- * Update the information for the player's move
- */
- public void updateMove() {
- // get size for individual squares
- int width = this.getWidth() / Board.WIDTH;
- int height = this.getHeight() / Board.HEIGHT;
- // get place mouse is hovering over
- if (mouseEntered) {
- int newMouseBoardX = mouseX / width;
- int newMouseBoardY = mouseY / height;
- // don't try to calculate moves for out of bounds cels
- if (newMouseBoardX < 0 || newMouseBoardX >= Board.WIDTH
- || newMouseBoardY < 0 || newMouseBoardY >= Board.HEIGHT) {
- move = null;
- } // only calculate moves when necessary
- else if (newMouseBoardX != mouseBoardX || newMouseBoardY != mouseBoardY) {
- mouseBoardX = newMouseBoardX;
- mouseBoardY = newMouseBoardY;
- move = new Move(board, mouseBoardX, mouseBoardY, SquareValue.PLAYER);
- }
- } else {
- move = null;
- }
- }
- /**
- * Draw the panel
- */
- @Override
- public void paintComponent(Graphics g) {
- // get size for individual squares
- int width = this.getWidth() / Board.WIDTH;
- int height = this.getHeight() / Board.HEIGHT;
- // draw the board
- Graphics2D g2 = (Graphics2D) g;
- for (int x = 0; x < Board.WIDTH; x++) {
- for (int y = 0; y < Board.HEIGHT; y++) {
- if (mouseEntered && mouseBoardX == x && mouseBoardY == y && move != null && move.isValid()) {
- g2.setColor(new Color(128, 255, 128));
- } else if (((x ^ y) & 1) == 0) { // checkerboard
- g2.setColor(new Color(128, 255, 255));
- } else {
- g2.setColor(new Color(255, 255, 128));
- }
- Rectangle2D r = new Rectangle2D.Double(x * width,
- y * height, width - 1, height - 1);
- g2.draw(r);
- g2.fill(r);
- // draw circle if present
- SquareValue value = board.getSquare(x, y);
- if (value == SquareValue.PLAYER) { // set to the proper color
- g2.setColor(new Color(255, 0, 0));
- } else if (value == SquareValue.CPU) {
- g2.setColor(new Color(0, 0, 255));
- }
- // draw if square not empty
- if (value != SquareValue.EMPTY) {
- Ellipse2D e = new Ellipse2D.Double(x * width + 1,
- y * height + 1, width - 2, height - 2);
- g2.draw(e);
- g2.fill(e);
- }
- }
- }
- // draw move, if needed
- if (move != null && move.isValid()) {
- int middleX = mouseBoardX * width + width / 2;
- int middleY = mouseBoardY * height + height / 2;
- // for all 8 directions draw a line if needed
- g2.setColor(new Color(128, 255, 128));
- for (int i = 0; i < 8; i++) {
- if (move.isDirectionUsed(i)) {
- int length = move.getDirectionRun(i) + 1;
- Line2D line = new Line2D.Double(middleX, middleY,
- middleX + Board.dirX[i] * length * width, middleY + Board.dirY[i] * length * height);
- g2.draw(line);
- }
- }
- }
- }
- }
- /**
- * Displays game results
- */
- class GameResultsDialog extends JDialog {
- /**
- * Creates a game results frame
- *
- * @param player player's total
- * @param cpu CPU's total
- * @param otherPanel reference to the panel that created this frame
- */
- public GameResultsDialog(int player, int cpu, JFrame frame, ReversiPanel otherPanel) {
- super(frame, "Results", false);
- setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
- // display score
- JPanel panel = new JPanel();
- panel.add(new JLabel("Player: " + player));
- panel.add(new JLabel("CPU: " + cpu));
- add(panel, BorderLayout.NORTH);
- // display winner
- panel = new JPanel();
- if (player > cpu) {
- panel.add(new JLabel("Player wins"));
- } else if (player < cpu) {
- panel.add(new JLabel("CPU wins"));
- } else {
- panel.add(new JLabel("Draw"));
- }
- add(panel, BorderLayout.CENTER);
- // display button
- panel = new JPanel();
- JButton button = new JButton("Play again");
- button.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- otherPanel.resetGame();
- dispose();
- }
- });
- panel.add(button);
- add(panel, BorderLayout.SOUTH);
- pack();
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement