added comments
This commit is contained in:
1 parent
a22d20986e
commit
b9b720665f
2 files changed
+93
-21
No files matched your search
@@ -1,5 +1,19 @@
|
|||||||
package ca.bcit.comp2522.lab11;
|
package ca.bcit.comp2522.lab11;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a single quiz question containing a question prompt
|
||||||
|
* and one or more valid answers. A user-provided answer is considered
|
||||||
|
* correct if it matches any of the stored answers, ignoring case.
|
||||||
|
*
|
||||||
|
* This class performs validation to ensure question text and answer
|
||||||
|
* strings are never null or blank.
|
||||||
|
*
|
||||||
|
* @author Braeden Sowinski
|
||||||
|
* @author Nico Agostini
|
||||||
|
* @author Trishaan Shetty
|
||||||
|
* @author Calvin Arifianto
|
||||||
|
* @version 1.0.0
|
||||||
|
*/
|
||||||
public class Question
|
public class Question
|
||||||
{
|
{
|
||||||
private static final int MIN_ANSWERS = 1;
|
private static final int MIN_ANSWERS = 1;
|
||||||
@@ -7,6 +21,12 @@ public class Question
|
|||||||
private final String question;
|
private final String question;
|
||||||
private final String[] answers;
|
private final String[] answers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates that a string is not null or blank.
|
||||||
|
*
|
||||||
|
* @param str the string to validate
|
||||||
|
* @throws IllegalArgumentException if the string is null or blank
|
||||||
|
*/
|
||||||
private static void validateString(final String str)
|
private static void validateString(final String str)
|
||||||
{
|
{
|
||||||
if (str == null || str.isBlank())
|
if (str == null || str.isBlank())
|
||||||
@@ -15,6 +35,15 @@ public class Question
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a Question with a prompt and accepted answers.
|
||||||
|
*
|
||||||
|
* @param question the question text
|
||||||
|
* @param answers the list of valid answers
|
||||||
|
* @throws IllegalArgumentException if question is invalid,
|
||||||
|
* or if answers is empty,
|
||||||
|
* or if any individual answer is invalid
|
||||||
|
*/
|
||||||
public Question(
|
public Question(
|
||||||
final String question,
|
final String question,
|
||||||
final String[] answers
|
final String[] answers
|
||||||
@@ -35,16 +64,33 @@ public class Question
|
|||||||
this.answers = answers;
|
this.answers = answers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the question text.
|
||||||
|
*
|
||||||
|
* @return the question string
|
||||||
|
*/
|
||||||
public String getQuestion()
|
public String getQuestion()
|
||||||
{
|
{
|
||||||
return this.question;
|
return this.question;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the list of accepted answers.
|
||||||
|
*
|
||||||
|
* @return an array of valid answers
|
||||||
|
*/
|
||||||
public String[] getAnswers()
|
public String[] getAnswers()
|
||||||
{
|
{
|
||||||
return this.answers;
|
return this.answers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether a user's answer is correct.
|
||||||
|
* Matching is case-insensitive.
|
||||||
|
*
|
||||||
|
* @param userAnswer the answer provided by the user
|
||||||
|
* @return true if it matches one of the valid answers; false otherwise
|
||||||
|
*/
|
||||||
public boolean validateAnswer(final String userAnswer)
|
public boolean validateAnswer(final String userAnswer)
|
||||||
{
|
{
|
||||||
for (final String answer : this.answers)
|
for (final String answer : this.answers)
|
||||||
|
|||||||
@@ -22,6 +22,18 @@ import java.util.Collections;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A timed quiz application that loads questions from an external file
|
||||||
|
* and presents them to the user in randomized order. The user has a
|
||||||
|
* limited amount of time to answer a fixed number of questions.
|
||||||
|
* Final results are shown when time expires or all questions are answered.
|
||||||
|
*
|
||||||
|
* @author Braeden Sowinski
|
||||||
|
* @author Nico Agostini
|
||||||
|
* @author Trishaan Shetty
|
||||||
|
* @author Calvin Arifianto
|
||||||
|
* @version 1.0.0
|
||||||
|
*/
|
||||||
public class Quiz extends Application
|
public class Quiz extends Application
|
||||||
{
|
{
|
||||||
private static final int WIDTH = 800;
|
private static final int WIDTH = 800;
|
||||||
@@ -48,7 +60,6 @@ public class Quiz extends Application
|
|||||||
|
|
||||||
private Timeline timeline;
|
private Timeline timeline;
|
||||||
|
|
||||||
// UI
|
|
||||||
private VBox root;
|
private VBox root;
|
||||||
private Label questionLabel;
|
private Label questionLabel;
|
||||||
private Label feedbackLabel;
|
private Label feedbackLabel;
|
||||||
@@ -58,6 +69,11 @@ public class Quiz extends Application
|
|||||||
private Button startButton;
|
private Button startButton;
|
||||||
private Button playAgainButton;
|
private Button playAgainButton;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads and loads quiz questions from a file.
|
||||||
|
*
|
||||||
|
* @param path the path to the quiz data file
|
||||||
|
*/
|
||||||
private void readQuestions(final Path path)
|
private void readQuestions(final Path path)
|
||||||
{
|
{
|
||||||
if (!questions.isEmpty())
|
if (!questions.isEmpty())
|
||||||
@@ -74,7 +90,6 @@ public class Quiz extends Application
|
|||||||
final String[] parts = line.split(DELIMITER);
|
final String[] parts = line.split(DELIMITER);
|
||||||
if (parts.length < MIN_LENGTH)
|
if (parts.length < MIN_LENGTH)
|
||||||
{
|
{
|
||||||
// Skip lines
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,10 +112,14 @@ public class Quiz extends Application
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the UI and starts the JavaFX application.
|
||||||
|
*
|
||||||
|
* @param stage the primary stage
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void start(final Stage stage)
|
public void start(final Stage stage)
|
||||||
{
|
{
|
||||||
|
|
||||||
root = new VBox();
|
root = new VBox();
|
||||||
root.setPrefSize(WIDTH, HEIGHT);
|
root.setPrefSize(WIDTH, HEIGHT);
|
||||||
|
|
||||||
@@ -115,7 +134,6 @@ public class Quiz extends Application
|
|||||||
startButton = new Button("Start quiz");
|
startButton = new Button("Start quiz");
|
||||||
playAgainButton = new Button("Play again");
|
playAgainButton = new Button("Play again");
|
||||||
|
|
||||||
// Initial UI state: game not started yet
|
|
||||||
answerField.setDisable(true);
|
answerField.setDisable(true);
|
||||||
submitButton.setDisable(true);
|
submitButton.setDisable(true);
|
||||||
playAgainButton.setDisable(true);
|
playAgainButton.setDisable(true);
|
||||||
@@ -149,7 +167,6 @@ public class Quiz extends Application
|
|||||||
}
|
}
|
||||||
|
|
||||||
final Runnable submitAction = () -> {
|
final Runnable submitAction = () -> {
|
||||||
// If game is not running
|
|
||||||
if (current == null)
|
if (current == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@@ -174,18 +191,13 @@ public class Quiz extends Application
|
|||||||
wrongCount++;
|
wrongCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// One chance per question: move immediately to next
|
|
||||||
currentQuestionIndex++;
|
currentQuestionIndex++;
|
||||||
showNextQuestion();
|
showNextQuestion();
|
||||||
};
|
};
|
||||||
|
|
||||||
submitButton.setOnAction(event -> submitAction.run());
|
submitButton.setOnAction(event -> submitAction.run());
|
||||||
answerField.setOnAction(event -> submitAction.run());
|
answerField.setOnAction(event -> submitAction.run());
|
||||||
|
|
||||||
// Start quiz button
|
|
||||||
startButton.setOnAction(event -> startGame());
|
startButton.setOnAction(event -> startGame());
|
||||||
|
|
||||||
// Play again button (same as start, but different state)
|
|
||||||
playAgainButton.setOnAction(event -> startGame());
|
playAgainButton.setOnAction(event -> startGame());
|
||||||
|
|
||||||
stage.setScene(scene);
|
stage.setScene(scene);
|
||||||
@@ -193,13 +205,17 @@ public class Quiz extends Application
|
|||||||
stage.show();
|
stage.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts a new quiz round, resets counters, shuffles questions,
|
||||||
|
* and initializes the timer.
|
||||||
|
*/
|
||||||
private void startGame()
|
private void startGame()
|
||||||
{
|
{
|
||||||
|
|
||||||
correctCount = COUNTER_STARTER;
|
correctCount = COUNTER_STARTER;
|
||||||
wrongCount = COUNTER_STARTER;
|
wrongCount = COUNTER_STARTER;
|
||||||
remainingSeconds = START_TIME_SECS;
|
remainingSeconds = START_TIME_SECS;
|
||||||
currentQuestionIndex = COUNTER_STARTER;
|
currentQuestionIndex = COUNTER_STARTER;
|
||||||
|
|
||||||
feedbackLabel.setText("");
|
feedbackLabel.setText("");
|
||||||
questionLabel.setText("");
|
questionLabel.setText("");
|
||||||
|
|
||||||
@@ -211,7 +227,6 @@ public class Quiz extends Application
|
|||||||
quizQuestions = new ArrayList<>(quizQuestions.subList(COUNTER_STARTER, NUM_QUESTIONS));
|
quizQuestions = new ArrayList<>(quizQuestions.subList(COUNTER_STARTER, NUM_QUESTIONS));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Timer
|
|
||||||
if (timeline != null)
|
if (timeline != null)
|
||||||
{
|
{
|
||||||
timeline.stop();
|
timeline.stop();
|
||||||
@@ -237,13 +252,14 @@ public class Quiz extends Application
|
|||||||
playAgainButton.setDisable(true);
|
playAgainButton.setDisable(true);
|
||||||
playAgainButton.setVisible(false);
|
playAgainButton.setVisible(false);
|
||||||
|
|
||||||
// Start with first question
|
|
||||||
showNextQuestion();
|
showNextQuestion();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays the next question or ends the quiz if none remain.
|
||||||
|
*/
|
||||||
private void showNextQuestion()
|
private void showNextQuestion()
|
||||||
{
|
{
|
||||||
|
|
||||||
if (currentQuestionIndex >= quizQuestions.size())
|
if (currentQuestionIndex >= quizQuestions.size())
|
||||||
{
|
{
|
||||||
endGame("You answered all questions.");
|
endGame("You answered all questions.");
|
||||||
@@ -259,6 +275,9 @@ public class Quiz extends Application
|
|||||||
updateStatusLabel();
|
updateStatusLabel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the status label to show progress and remaining time.
|
||||||
|
*/
|
||||||
private void updateStatusLabel()
|
private void updateStatusLabel()
|
||||||
{
|
{
|
||||||
if (quizQuestions.isEmpty())
|
if (quizQuestions.isEmpty())
|
||||||
@@ -267,16 +286,22 @@ public class Quiz extends Application
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final int displayIndex = Math.min(currentQuestionIndex + ONE_SECOND, quizQuestions.size());
|
final int displayIndex =
|
||||||
|
Math.min(currentQuestionIndex + ONE_SECOND, quizQuestions.size());
|
||||||
|
|
||||||
statusLabel.setText(
|
statusLabel.setText(
|
||||||
displayIndex + "/" + quizQuestions.size()
|
displayIndex + "/" + quizQuestions.size()
|
||||||
+ " ::: " + remainingSeconds + "s remaining"
|
+ " ::: " + remainingSeconds + "s remaining"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ends the game, stops the timer, and displays the final score.
|
||||||
|
*
|
||||||
|
* @param reason explanation for ending (e.g., time expired)
|
||||||
|
*/
|
||||||
private void endGame(final String reason)
|
private void endGame(final String reason)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (timeline != null)
|
if (timeline != null)
|
||||||
{
|
{
|
||||||
timeline.stop();
|
timeline.stop();
|
||||||
@@ -284,9 +309,8 @@ public class Quiz extends Application
|
|||||||
|
|
||||||
submitButton.setDisable(true);
|
submitButton.setDisable(true);
|
||||||
answerField.setDisable(true);
|
answerField.setDisable(true);
|
||||||
current = null; // mark game as ended
|
current = null;
|
||||||
|
|
||||||
// Final score on screen
|
|
||||||
final String finalScore =
|
final String finalScore =
|
||||||
reason + "\n\nFinal score:"
|
reason + "\n\nFinal score:"
|
||||||
+ "\nCorrect: " + correctCount
|
+ "\nCorrect: " + correctCount
|
||||||
@@ -294,17 +318,19 @@ public class Quiz extends Application
|
|||||||
|
|
||||||
feedbackLabel.setText(finalScore);
|
feedbackLabel.setText(finalScore);
|
||||||
|
|
||||||
// Clear question + status, show restart UI
|
|
||||||
questionLabel.setText("Game over.");
|
questionLabel.setText("Game over.");
|
||||||
statusLabel.setText("");
|
statusLabel.setText("");
|
||||||
|
|
||||||
// Show "Play again" button
|
|
||||||
playAgainButton.setVisible(true);
|
playAgainButton.setVisible(true);
|
||||||
playAgainButton.setDisable(false);
|
playAgainButton.setDisable(false);
|
||||||
|
|
||||||
startButton.setVisible(false);
|
startButton.setVisible(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Standard Java entry point. Launches the JavaFX app.
|
||||||
|
*
|
||||||
|
* @param args CLI arguments
|
||||||
|
*/
|
||||||
public static void main(final String[] args)
|
public static void main(final String[] args)
|
||||||
{
|
{
|
||||||
launch(args);
|
launch(args);
|
||||||
|
|||||||
Reference in new issue
Block a user