diff --git a/src/main/java/TicTacToe/Cell.java b/src/main/java/TicTacToe/Cell.java new file mode 100644 index 0000000..b6c4e6b --- /dev/null +++ b/src/main/java/TicTacToe/Cell.java @@ -0,0 +1,60 @@ +package TicTacToe; + +import java.awt.Color; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.JButton; + +public class Cell extends JButton { + + public int playerID = 0; + private TicTacToeGame ttt; + + public Cell(TicTacToeGame _ttt) { + ttt = _ttt; + setBackground(new Color(0)); + + addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + OnMouseClick(); + } + }); + } + + protected void OnMouseClick() { + if (playerID == 0) { + playerID = ttt.playerID; + setEnabled(false); + ttt.endTurn(); + repaint(); + } + } + + @Override + protected void paintComponent(Graphics g) { + super.paintComponent(g); + Graphics2D g2 = (Graphics2D) g; + g2.setPaint(Color.white); + switch (playerID) { + case 1: + g2.drawLine(5, 5, 90, 90); + g2.drawLine(90, 5, 5, 90); + break; + case 2: + g2.drawOval(5, 5, 90, 90); + break; + } + } + + + protected void reset() { + playerID = 0; + setEnabled(true); + repaint(); + } + +} diff --git a/src/main/java/TicTacToe/Scoreboard.java b/src/main/java/TicTacToe/Scoreboard.java new file mode 100644 index 0000000..cbca4a2 --- /dev/null +++ b/src/main/java/TicTacToe/Scoreboard.java @@ -0,0 +1,45 @@ +package TicTacToe; + +import java.awt.Color; + +import javax.swing.JLabel; + +public class Scoreboard extends JLabel{ + + private static final long serialVersionUID = 1L; + + public int[] playerPoints; + + public Scoreboard(int _playerCount) { + playerPoints = new int[_playerCount]; + setForeground(Color.white); + updateScores(); + } + + public void addPoint(int playerID) { + playerPoints[playerID]++; + updateScores(); + } + + public void subPoint(int playerID) { + playerPoints[playerID]--; + updateScores(); + } + + public void updateScores() { + int gamesPlayed = 0; + for(int i = 0; i < playerPoints.length; i++){ + if(i == 0) { + setText("Draws: " + playerPoints[0]); + } else { + setText(getText() + " Player " + i + ": " + playerPoints[i]); + } + + gamesPlayed += playerPoints[i]; + } + setText(getText() + " Games played: " + gamesPlayed); + + } + + +} diff --git a/src/main/java/TicTacToe/TicTacToeGame.java b/src/main/java/TicTacToe/TicTacToeGame.java new file mode 100644 index 0000000..642f6e5 --- /dev/null +++ b/src/main/java/TicTacToe/TicTacToeGame.java @@ -0,0 +1,134 @@ +package TicTacToe; + +import java.awt.Color; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.geom.Line2D; + +import javax.swing.JFrame; +import javax.swing.JOptionPane; +import javax.swing.JPanel; + + +public class TicTacToeGame extends JPanel { + + private static final long serialVersionUID = 1L; + private static final int width = 600, height = 600; + private static final int maxPlayers = 3; + private static final int playFieldSize = 9; + + public Cell[] field; + public int playerID = 1; + public int turns = 0; + public Scoreboard scoreboard; + + public TicTacToeGame() { + this.setSize(width, height); + setBackground(Color.black); + setLayout(null); + initField(); + initScoreboard(); + } + + + public static void main(String[] args) { + JFrame f = new JFrame(); + TicTacToeGame ttt = new TicTacToeGame(); + + f.add(ttt); + f.setSize(width,height); + f.setLayout(null); + f.setVisible(true); + } + + public void initField() { + field = new Cell[playFieldSize]; + + for(int i = 0; i < field.length; i++) { + field[i] = new Cell(this); + add(field[i]); + } + + for(int i = 0; i < field.length; i++) { + if(i < 3) { + field[i].setBounds(150 + i*100, 150 , 100, 100); + } else if (i < 6) { + field[i].setBounds(150 + i%3*100, 250 , 100, 100); + } else { + field[i].setBounds(150 + i%3*100, 350 , 100, 100); + } + } + } + + private void initScoreboard() { + scoreboard = new Scoreboard(maxPlayers); + scoreboard.setBounds(150, 100, 300, 50); + add(scoreboard); + } + + @Override + protected void paintComponent(Graphics g) { + super.paintComponent(g); + Graphics2D g2 = (Graphics2D) g; + g2.setColor(Color.white); + + Line2D lin = new Line2D.Float(250, 150, 250, 450); + Line2D lin2 = new Line2D.Float(350, 150, 350, 450); + Line2D lin3 = new Line2D.Float(150, 250, 450, 250); + Line2D lin4 = new Line2D.Float(150, 350, 450, 350); + + g2.draw(lin); + g2.draw(lin2); + g2.draw(lin3); + g2.draw(lin4); + } + + public void endTurn() { + if(checkPlayfield() != 0) { + JOptionPane.showMessageDialog(getParent(),"Player: " + playerID + " Wins!"); + scoreboard.addPoint(playerID); + resetGame(); + } else { + turns++; + if(turns >= playFieldSize) { + JOptionPane.showMessageDialog(getParent(),"Draw!"); + scoreboard.addPoint(0); + resetGame(); + } + + playerID++; + if(playerID >= maxPlayers) { + playerID = 1; + } + } + + + } + + public int checkPlayfield() { + if ((field[0].playerID == playerID && field[1].playerID == playerID && field[2].playerID == playerID) + || (field[0].playerID == playerID && field[3].playerID == playerID && field[6].playerID == playerID) + || (field[8].playerID == playerID && field[5].playerID == playerID && field[2].playerID == playerID) + || (field[8].playerID == playerID && field[7].playerID == playerID && field[6].playerID == playerID) + || (field[0].playerID == playerID && field[4].playerID == playerID && field[8].playerID == playerID) + || (field[0].playerID == playerID && field[4].playerID == playerID && field[8].playerID == playerID) + || (field[2].playerID == playerID && field[4].playerID == playerID && field[6].playerID == playerID) + || (field[3].playerID == playerID && field[4].playerID == playerID && field[5].playerID == playerID) + || (field[1].playerID == playerID && field[4].playerID == playerID && field[7].playerID == playerID)) { + + return playerID; + } + + return 0; + } + + public void resetGame() { + for (Cell c : field) { + c.reset(); + } + playerID = 1; + turns = 0; + } + + +} \ No newline at end of file diff --git a/src/test/java/TicTacToe/TicTacToeGameTest.java b/src/test/java/TicTacToe/TicTacToeGameTest.java new file mode 100644 index 0000000..beaabde --- /dev/null +++ b/src/test/java/TicTacToe/TicTacToeGameTest.java @@ -0,0 +1,77 @@ +package TicTacToe; + +import static org.junit.jupiter.api.Assertions.*; +import java.util.stream.Stream; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + + +class TicTacToeGameTest { + + @ParameterizedTest + @MethodSource("testFieldsWinning") + void testGameEndWin(int[] _field, int _winner) { + TicTacToeGame ttt = new TicTacToeGame(); + + for(int i = 0; i < ttt.field.length; i++) { + ttt.field[i].playerID = _field[i]; + } + ttt.playerID = _winner; + int realWinner = ttt.checkPlayfield(); + + assertEquals(_winner, realWinner); + } + + @ParameterizedTest + @MethodSource("testFieldsDraw") + void testGameEndDraw(int[] _field) { + TicTacToeGame ttt = new TicTacToeGame(); + + for(int i = 0; i < ttt.field.length; i++) { + ttt.field[i].playerID = _field[i]; + } + + int noWinner = ttt.checkPlayfield(); + + assertEquals(0, noWinner); + } + + + private static Stream testFieldsWinning(){ + return Stream.of( + Arguments.of(new int[]{ 1,2,1, + 2,2,2, + 1,2,1}, 2), + Arguments.of(new int[]{ 2,1,2, + 2,2,1, + 1,1,1}, 1), + Arguments.of(new int[]{ 1,1,2, + 1,2,2, + 1,2,1}, 1), + Arguments.of(new int[]{ 2,1,1, + 1,2,1, + 1,1,2}, 2) + ); + } + + private static Stream testFieldsDraw(){ + return Stream.of( + Arguments.of(new int[]{ 2,1,1, + 2,2,2, + 1,2,1}), + Arguments.of(new int[]{ 2,1,2, + 2,2,1, + 1,2,1}), + Arguments.of(new int[]{ 2,1,2, + 1,2,2, + 1,2,1}), + Arguments.of(new int[]{ 2,1,1, + 1,2,2, + 2,1,1}) + ); + + + } +}