Ask Questions?

View Latest Questions


 
 

Five-in-a-row
Posted on: July 22, 2006 at 12:00 AM
Two players alternate making moves. The player who places five pieces in a row wins.

Java: Example - Five-in-a-row

Two players alternate making moves. The player who places five pieces in a row wins.

The source program consists of three files: a short main program, a graphical user interface, and a logic class. The logic class knows nothing about the GUI, and could just as easily be used with a text interface or by a web interface.

There's a lot of room for improvement. Some possible exercises:

  1. This game may have originated on a Go board where the pieces are placed on intersections, not in empty spaces. Change the program to put pieces on the intersections.
  2. The Undo button doesn't do anything. Fix it in both the GUI and in logic
  3. A more challenging problem is to write a machine player, which should be defined as an interface so that it would be possible to use many classes as players, allowing machine vs. machine games for example. The machine player should be passed a copy of the state of the game, the logic object, so that it doesn't mess up the current state.

The main program

  1 
  2 
  3 
  4 
  5 
  6 
  7 
  8 
  9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
// Five.java - main program for Five-In-A-Row Program
import javax.swing.JFrame;

////////////////////////////////////////////////////// class Five
/** Five.java - Winner is able to put 5 pieces in a row.
   The Five program consists of three files:
   Five.java      - this file with main to create window.
   FiveGUI.java   - implements the GUI interface.
   FiveLogic.java - the logical functioning.
   @author Fred Swartz
   @version 2004-05-02
   */
class Five {
    //================================================ method main
    public static void main(String[] args) {
        JFrame window = new JFrame("Five In A Row");
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        window.setContentPane(new FiveGUI());
        window.pack();  // finalize layout
        window.setResizable(false);
        window.show();  // make window visible
    }//end main
}//endclass Five

The GUI, implemented as a subclass of JPanel

  1 
  2 
  3 
  4 
  5 
  6 
  7 
  8 
  9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
 26 
 27 
 28 
 29 
 30 
 31 
 32 
 33 
 34 
 35 
 36 
 37 
 38 
 39 
 40 
 41 
 42 
 43 
 44 
 45 
 46 
 47 
 48 
 49 
 50 
 51 
 52 
 53 
 54 
 55 
 56 
 57 
 58 
 59 
 60 
 61 
 62 
 63 
 64 
 65 
 66 
 67 
 68 
 69 
 70 
 71 
 72 
 73 
 74 
 75 
 76 
 77 
 78 
 79 
 80 
 81 
 82 
 83 
 84 
 85 
 86 
 87 
 88 
 89 
 90 
 91 
 92 
 93 
 94 
 95 
 96 
 97 
 98 
 99 
100 
101 
102 
103 
104 
105 
106 
107 
108 
109 
110 
111 
112 
113 
114 
115 
116 
117 
118 
119 
120 
121 
122 
123 
124 
125 
126 
127 
128 
129 
130 
131 
132 
133 
134 
135 
136 
137 
138 
139 
140 
141 
142 
143 
144 
145 
146 
147 
148 
149 
150 
151 
152 
153 
154 
155 
156 
157 
158 
159 
160 
161 
162 
// FiveGUI.java
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;

/////////////////////////////////////////////////// class FiveGUI
/** A Graphical User Interface for a Five-In-A-Row game.
    This implements the user interface (view and controller),
    but the logic (model) is implemented in a separate class that
    knows nothing about the user interface.
    <p>This subclasses JPanel and puts the some buttons in the north,
    a graphical display of the board in the center, and
    a status field in the south.
    </p>
    <p>Exercise: This game probably originated on a Go board where
       the pieces are placed on the intersections, not in the 
       empty spaces.  Change the program to put all pieces on the
       intersections.
    </p>
    <p>Exercise: The Undo button doesn't do anything.  Fix it here
       in the GUI and in the logic.
    </p>
    <p>Exercise: Create a machine player.</p>
    @author Fred Swartz
    @version 2004-05-02 Rodenbach
    */
class FiveGUI extends JPanel {
    //=============================================== instance variables
    private GraphicsPanel boardDisplay_;
    private JTextField    statusField_ = new JTextField();
    private FiveLogic     gameLogic_ = new FiveLogic(9, 9);
    private boolean       gameOver_ = false;
    
    private static final Color[]  PLAYER_COLOR = {null, Color.BLACK, Color.WHITE};
    private static final String[] PLAYER_NAME  = {null, "BLACK", "WHITE"};

    //====================================================== constructor
    public FiveGUI() {
        //--- Create some buttons
        JButton newGameButton = new JButton("New Game");
        JButton undoButton = new JButton("Undo");

        //--- Create control panel
        JPanel controlPanel = new JPanel();
        controlPanel.setLayout(new FlowLayout());
        controlPanel.add(newGameButton);
        controlPanel.add(undoButton);
        
        //--- Create graphics panel
        boardDisplay_ = new GraphicsPanel();
        
        //--- Set the layout and add the components
        this.setLayout(new BorderLayout());
        this.add(controlPanel , BorderLayout.NORTH);
        this.add(boardDisplay_, BorderLayout.CENTER);
        this.add(statusField_ , BorderLayout.SOUTH);
        
        //-- Add action listeners
        newGameButton.addActionListener(new NewGameAction());
    }//end constructor

    //////////////////////////////////////////////// class GraphicsPanel
    // This is defined inside the outer class so that
    // it can use the game logic variable.
    class GraphicsPanel extends JPanel implements MouseListener {
        private static final int ROWS = 9;
        private static final int COLS = 9;
        private static final int CELL_SIZE = 30; // Pixels
        private static final int WIDTH  = COLS * CELL_SIZE;
        private static final int HEIGHT = ROWS * CELL_SIZE;
        
        //================================================== constructor
        public GraphicsPanel() {
            this.setPreferredSize(new Dimension(WIDTH, HEIGHT));
            this.setBackground(Color.GRAY);
            this.addMouseListener(this);  // Listen own mouse events.
        }//end constructor
        
        //============================================== paintComponent
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            //-- Paint grid (could be done once and saved).
            for (int r=1; r<ROWS; r++) {  // Horizontal lines
                g.drawLine(0, r*CELL_SIZE, WIDTH, r*CELL_SIZE);
            }
            for (int c=1; c<COLS; c++) {
                g.drawLine(c*CELL_SIZE, 0, c*CELL_SIZE, HEIGHT);
            }
            
            //-- Draw players pieces.
            for (int r=0; r<ROWS; r++) {
                for (int c=0; c<COLS; c++) {
                    int x = c * CELL_SIZE;
                    int y = r * CELL_SIZE;
                    int who = gameLogic_.getPlayerAt(r, c);
                    if (who != gameLogic_.EMPTY) {
                        g.setColor(PLAYER_COLOR[who]);
                        g.fillOval(x+2, y+2, CELL_SIZE-4, CELL_SIZE-4);
                    }
                }
            }
        }//end paintComponent
        
        //======================================== listener mousePressed
        public void mousePressed(MouseEvent e) {
            //--- map x,y coordinates into a row and col.
            int col = e.getX()/CELL_SIZE;
            int row = e.getY()/CELL_SIZE;
            
            int currentOccupant = gameLogic_.getPlayerAt(row, col);
            if (!gameOver_ && currentOccupant == gameLogic_.EMPTY) {
                gameLogic_.move(row, col);
                switch (gameLogic_.getGameStatus()) {
                    case 1: // Player one wins.  Game over.
                            gameOver_ = true;
                            statusField_.setText("BLACK WINS");
                            break;
                    case 2: // Player two wins.  Game over.
                            gameOver_ = true;
                            statusField_.setText("WHITE WINS");
                            break;
                            
                    case FiveLogic.TIE:  // Tie game.  Game over.
                            gameOver_ = true;
                            statusField_.setText("TIE GAME");
                            break;
                            
                    default: showNextPlayer();
                }
                            
            } else {  // Not legal
                Toolkit.getDefaultToolkit().beep();
            }
            
            this.repaint();  // Show any updates to game.
        }//end mousePressed
        
        //========================================== ignore these events
        public void mouseClicked (MouseEvent e) {}
        public void mouseReleased(MouseEvent e) {}
        public void mouseEntered (MouseEvent e) {}
        public void mouseExited  (MouseEvent e) {}
    }//end inner class GraphicsPanel
    
    //======================================= untility method showNextPlayer
    private void showNextPlayer() {
       statusField_.setText(PLAYER_NAME[gameLogic_.getNextPlayer()] + " to play");
    }//end showNextPlayer
        
    
    ///////////////////////////////////////// inner class NewGameAction
    private class NewGameAction implements ActionListener {
        public void actionPerformed(ActionEvent e) {
            gameLogic_.reset();
            gameOver_ = false;
            showNextPlayer();
            boardDisplay_.repaint();
        }
    }//end inner class NewGameAction

}//end class FiveGUI

The logic class

  1 
  2