Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified players.dat
Binary file not shown.
6 changes: 6 additions & 0 deletions src/main/java/co/ppg2/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,12 @@ public void start(Stage primaryStage) {

// Start the timer for Player X
gameTimer.startTimer(playerX.getUsername());

// add an exit for the application
primaryStage.setOnCloseRequest(event -> {
System.out.println("Game is closing...");
System.exit(0);
});
}


Expand Down
27 changes: 18 additions & 9 deletions src/main/java/co/ppg2/controllers/GameController.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,21 @@


public class GameController {
public GameController(String usernameX, String usernameO) {
if (usernameX == null || usernameX.trim().isEmpty() || usernameO == null || usernameO.trim().isEmpty()) {
throw new IllegalArgumentException("Both players must enter a valid username.");
} //makes sure the player must enter a username to proceed
this.playerX = new Player(usernameX);
this.playerO = new Player(usernameO);

}
private char whoseTurn = 'X';
private final CellBase[][] cells = new CellBase[3][3];
private final Player playerX;
private final Player playerO;
private GameTimer gameTimer;
private GameView gameView;
private final ArrayList<Player> players;
private ArrayList<Player> players = null;


public GameController(Player playerX, Player playerO) {
Expand All @@ -35,6 +43,9 @@ public Player getCurrentPlayer() {
}


/**
* Switches the turn to the other player and starts their timer
*/ //javadoc comment example
public void switchTurn() {
if (gameTimer != null) {
gameTimer.cancelTimer(); // Stop the timer for the current player
Expand Down Expand Up @@ -105,21 +116,18 @@ public void setGameView(GameView gameView) {




public GameView getGameView() {
return gameView;
}




public Player getWinner(char token) {
return (token == 'X') ? playerX : playerO;
}




public void updateLeaderboard(char token) {
Player winner = getWinner(token);
Player loser = (token == 'X') ? playerO : playerX;
Expand All @@ -137,12 +145,9 @@ public void updateLeaderboard(char token) {




PlayerDataController.savePlayers(players);




// Show leaderboard with average time per move
StringBuilder leaderboardDetails = new StringBuilder();
for (Player player : players) {
Expand All @@ -152,10 +157,14 @@ public void updateLeaderboard(char token) {
}




LeaderboardPopup.showLeaderboard(players);
}
//TODO: could make a basic utility method to check if a cell in the 2D array is empty

public boolean isCellEmpty(int row, int col) {
return cells[row][col] == null || cells[row][col].getToken() == ' ';
}
//TODO: suggestion: remove unnecessary blank lines to improve readability
}


Expand Down
14 changes: 10 additions & 4 deletions src/main/java/co/ppg2/controllers/PlayerDataController.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,16 @@ public static void savePlayers(ArrayList<Player> players) {

public static ArrayList<Player> loadPlayers() {
ArrayList<Player> players = new ArrayList<>();
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(FILE_NAME))) {
players = (ArrayList<Player>) ois.readObject();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
File file = new File(FILE_NAME);
//TODO: consider adding conditional to check if file exists
if (file.exists()) {
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(FILE_NAME))) {
players = (ArrayList<Player>) ois.readObject();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
} else {
System.out.println("Player file does not exist. Starting with an empty player list.");
}
return players;
}
Expand Down
11 changes: 10 additions & 1 deletion src/main/java/co/ppg2/model/Player.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
import java.io.Serializable;

public class Player implements Serializable {
private final String username;
private String username;
private int wins;
private int losses;

public Player(String username) {
setUsername(username);
this.username = username;
this.wins = 0;
this.losses = 0;
Expand All @@ -17,6 +18,14 @@ public String getUsername() {
return username;
}

public void setUsername(String username) {
//added to make sure username is not empty
if (username == null || username.trim().isEmpty()) {
throw new IllegalArgumentException("Username can't be empty. Please enter a valid username.");
}
this.username = username;
}

public int getWins() {
return wins;
}
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/co/ppg2/services/GameTimer.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public synchronized double getAverageTimePerMove(String playerName) {
int moves = playerMoves.getOrDefault(playerName, 0);
return moves == 0 ? 0.0 : (totalTime / (double) moves) / 1000.0; // Convert to seconds
}
//TODO: Could add a pause button to pause the timer and resume once the button is pressed again. Would need to add the button in GameView

@Override
public void run() {
Expand All @@ -50,6 +51,9 @@ public void run() {
Platform.runLater(() -> {
// Update GUI components if needed in future
});

// simple add to log loop status
System.out.println("Timer is running..."); // log message in each iteration
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
Expand Down
22 changes: 20 additions & 2 deletions src/main/java/co/ppg2/views/GameView.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import co.ppg2.controllers.PlayerDataController;
import co.ppg2.model.Player;
import javafx.scene.Scene;
import javafx.scene.control.Alert; // Importing Alert class
import javafx.scene.control.Alert.AlertType; // Importing AlertType class
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
Expand All @@ -19,10 +21,17 @@ public GameView(GameController gameController, Stage primaryStage) {
this.primaryStage = primaryStage;
}
public void launchGame() {
// Validate player usernames before launching the game
if (gameController.getCurrentPlayer().getUsername().isEmpty() ||
gameController.getWinner('O').getUsername().isEmpty()) {
showErrorPopup("Both players must enter a username to start the game.");
return; // Stop further execution if validation fails; popup to make sure plyer enters a name
}
GridPane gridPane = new GridPane();
gridPane.setGridLinesVisible(true);



for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
CellEmpty cell = new CellEmpty(gameController, this, i, j);
Expand All @@ -40,18 +49,26 @@ public void launchGame() {
borderPane.setBottom(labelInstructions);


Scene scene = new Scene(borderPane, 450, 170);
Scene scene = new Scene(borderPane, 800, 600); //changed dimensions of window
primaryStage.setTitle("TicTacToe");
primaryStage.setScene(scene);
primaryStage.show();
}

// Method to show the error popup
private void showErrorPopup(String message) {
Alert alert = new Alert(AlertType.ERROR);
alert.setTitle("Validation Error");
alert.setHeaderText(null);
alert.setContentText(message);
alert.showAndWait();
}

public void updateLabel(String text) {
labelInstructions.setText(text);
}


//TODO: Possibly make it so this message pops up in the middle of the screen or is larger
public void handleTie() {
updateLabel("It is a tie!");
LeaderboardPopup.showLeaderboard(PlayerDataController.loadPlayers());
Expand All @@ -68,3 +85,4 @@ public void handleGameOver(char token) {
}