Tic-Tac-Toe Game in Java using MVC
Below is a simple implementation of the classic Tic-Tac-Toe game in Java, structured using the Model-View-Controller (MVC) design pattern.
Model:
public class Model { private int moves; private String symbol; private int xScore = 0; private int oScore = 0; public Model() { moves = 0; } public void setChoice() { if (moves % 2 == 0 ) symbol = "X"; else symbol = "O"; } public void addMoves() { moves++; } public String getSymbol() { return symbol; } public int getMoves() { return moves; } public int getXScore() { xScore++; return xScore; } public int getOScore() { oScore++; return oScore; } public void setMoves() { moves = 0; } }
View:
import java.awt.*; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.plaf.metal.MetalButtonUI; import javax.swing.JButton; class View extends JFrame { JButton[] buttons; Controller controller; boolean gameEnd; JLabel textField = new JLabel(); JLabel xScore = new JLabel(); JLabel oScore = new JLabel(); JPanel textPanel = new JPanel(); JPanel buttonPanel = new JPanel(); public View(Controller controller) { super("TicTacToe"); this.controller = controller; buttons = new JButton[9]; buttonPanel.setPreferredSize(new Dimension(500, 500)); this.setLayout(new BorderLayout()); this.setSize(500,600); this.setDefaultCloseOperation(EXIT_ON_CLOSE); addComponentListener(new java.awt.event.ComponentAdapter() { public void componentResized(java.awt.event.ComponentEvent evt) { formComponentResized(evt); } }); textField.setForeground(Color.BLACK); textField.setFont(new Font("Serif", Font.PLAIN, 20)); textField.setHorizontalAlignment(JLabel.CENTER); textField.setText("It´s X's turn!"); xScore.setForeground(Color.BLACK); xScore.setFont(new Font("Serif", Font.PLAIN, 20)); xScore.setHorizontalAlignment(JLabel.RIGHT); xScore.setText("Player X Score: 0"); oScore.setForeground(Color.BLACK); oScore.setFont(new Font("Serif", Font.PLAIN, 20)); oScore.setText("Player O Score: 0"); textPanel.setBounds(0, 0, 600, 100); textPanel.setLayout(new BorderLayout()); textPanel.setBackground(Color.white); buttonPanel.setLayout(new GridLayout(3, 3)); for (int i = 0; i < buttons.length; i++) { buttons[i] = new JButton(); buttons[i].getPreferredSize(); buttonPanel.add(buttons[i]); buttons[i].setFont(new Font("Serif", Font.PLAIN, 110)); buttons[i].setFocusable(false); buttons[i].setBackground(Color.white); } this.add(buttonPanel); for (int i = 0; i < buttons.length; i++) { buttons[i].setActionCommand(String.valueOf(i)); buttons[i].addActionListener(controller); } textPanel.add(oScore, BorderLayout.WEST); textPanel.add(textField, BorderLayout.CENTER); textPanel.add(xScore, BorderLayout.EAST); this.add(textPanel, BorderLayout.NORTH); pack(); this.setVisible(true); gameEnd = false; } public boolean checkForWinner() { if ((buttons[0].getText()=="X") && (buttons[1].getText()=="X") && (buttons[2].getText()=="X")) { xWins(0,1,2); return true; } if ((buttons[3].getText()=="X") && (buttons[4].getText()=="X") && (buttons[5].getText()=="X")) { xWins(3,4,5); return true; } if ((buttons[6].getText()=="X") && (buttons[7].getText()=="X") && (buttons[8].getText()=="X")) { xWins(6,7,8); return true; } if ((buttons[0].getText()=="X") && (buttons[3].getText()=="X") && (buttons[6].getText()=="X")) { xWins(0,3,6); return true; } if ((buttons[1].getText()=="X") && (buttons[4].getText()=="X") && (buttons[7].getText()=="X")) { xWins(1,4,7); return true; } if ((buttons[2].getText()=="X") && (buttons[5].getText()=="X") && (buttons[8].getText()=="X")) { xWins(2,5,8); return true; } if ((buttons[0].getText()=="X") && (buttons[4].getText()=="X") && (buttons[8].getText()=="X")) { xWins(0,4,8); return true; } if ((buttons[2].getText()=="X") && (buttons[4].getText()=="X") && (buttons[6].getText()=="X")) { xWins(2,4,6); return true; } if ((buttons[0].getText()=="O") && (buttons[1].getText()=="O") && (buttons[2].getText()=="O")) { oWins(0,1,2); return true; } if ((buttons[3].getText()=="O") && (buttons[4].getText()=="O") && (buttons[5].getText()=="O")) { oWins(3,4,5); return true; } if ((buttons[6].getText()=="O") && (buttons[7].getText()=="O") && (buttons[8].getText()=="O")) { oWins(6,7,8); return true; } if ((buttons[0].getText()=="O") && (buttons[3].getText()=="O") && (buttons[6].getText()=="O")) { oWins(0,3,6); return true; } if ((buttons[1].getText()=="O") && (buttons[4].getText()=="O") && (buttons[7].getText()=="O")) { oWins(1,4,7); return true; } if ((buttons[2].getText()=="O") && (buttons[5].getText()=="O") && (buttons[8].getText()=="O")) { oWins(2,5,8); return true; } if ((buttons[0].getText()=="O") && (buttons[4].getText()=="O") && (buttons[8].getText()=="O")) { oWins(0,4,8); return true; } if ((buttons[2].getText()=="O") && (buttons[4].getText()=="O") && (buttons[6].getText()=="O")) { oWins(2,4,6); return true; } return false; } public void updateGame() { if(checkForWinner() == true) { Object[] option={"Ok","Exit"}; int n=JOptionPane.showOptionDialog(this, "Play Again?","Message",JOptionPane.YES_NO_CANCEL_OPTION,JOptionPane.QUESTION_MESSAGE,null,option,option[0]); if(n==0){ textField.setText("It´s X's turn!"); gameEnd = false; for (int i = 0; i < buttons.length; i++) { buttons[i].setEnabled(true); buttons[i].setText(""); buttons[i].setBackground(Color.white); controller.setMoves(); } } else{ gameEnd = true; } } else if (controller.getMoves() == 9) { textField.setText("Match tie!"); JOptionPane.showMessageDialog(this, "Match tie!","Message", JOptionPane.INFORMATION_MESSAGE); Object[] option={"Ok","Exit"}; int n=JOptionPane.showOptionDialog(this, "Play Again?","Message",JOptionPane.YES_NO_CANCEL_OPTION,JOptionPane.QUESTION_MESSAGE,null,option,option[0]); if(n==0){ textField.setText("It´s X's turn!"); gameEnd = false; for (int i = 0; i < buttons.length; i++) { buttons[i].setEnabled(true); buttons[i].setText(""); buttons[i].setBackground(Color.white); controller.setMoves(); } } else{ gameEnd = true; } } } public void endGame() { for (int i = 0; i < buttons.length; i++) buttons[i].setEnabled(false); } public void xWins(int pos1, int pos2, int pos3) { buttons[pos1].setBackground(Color.LIGHT_GRAY); buttons[pos2].setBackground(Color.LIGHT_GRAY); buttons[pos3].setBackground(Color.LIGHT_GRAY); textField.setText("X wins!"); xScore.setText("Player X Score: " + controller.getXScore() + ""); JOptionPane.showMessageDialog(this, "Player X won the game!","Message", JOptionPane.INFORMATION_MESSAGE); } public void oWins(int pos1, int pos2, int pos3) { buttons[pos1].setBackground(Color.LIGHT_GRAY); buttons[pos2].setBackground(Color.LIGHT_GRAY); buttons[pos3].setBackground(Color.LIGHT_GRAY); textField.setText("O wins!"); oScore.setText("Player O Score: " + controller.getOScore() + ""); JOptionPane.showMessageDialog(this, "Player O won the game!","Message", JOptionPane.INFORMATION_MESSAGE); } private void formComponentResized(java.awt.event.ComponentEvent evt) { for(int i=0;i<9;i++) { buttons[i].setFont(buttons[i].getFont().deriveFont((float)(buttons[i].getWidth()/2))); } } public void setText(String symbol, int i) { if(symbol == "X") { if (buttons[i].getText() == "") { buttons[i].setUI(new MetalButtonUI() { protected Color getDisabledTextColor() { return Color.red; } }); buttons[i].setText(symbol); textField.setText("It´s O's turn!"); } } else { if (buttons[i].getText() == "") { buttons[i].setUI(new MetalButtonUI() { protected Color getDisabledTextColor() { return Color.blue; } }); buttons[i].setText(symbol); textField.setText("It´s X´s turn!"); } } buttons[i].setEnabled(false); } }
Controller:
import java.awt.event.ActionEvent; import java.awt.event.ActionListener; class Controller implements ActionListener { private View view; private Model model; public Controller(Model model) { this.model = model; } @Override public void actionPerformed(ActionEvent e) { if (view.gameEnd == false) { model.setChoice(); if (e.getActionCommand() != "") { int button = Integer.parseInt(e.getActionCommand()); view.setText(model.getSymbol(), button); model.addMoves(); } } } public void setView(View view) { this.view = view; } public int getMoves() { return model.getMoves(); } public int getXScore() { return model.getXScore(); } public int getOScore() { return model.getOScore(); } public void setMoves() { model.setMoves(); } }
TicTacToe (main):
public class TicTacToe { public static void main(String[] args) { Model model = new Model(); Controller controller = new Controller(model); View view = new View(controller); controller.setView(view); boolean run = true; while (run) { view.updateGame(); if (view.gameEnd == true) { view.endGame(); run = false; } } System.exit(0); } }