Week 3

Member 1: Erin Hurley

Overall Impression: Erin's code demonstrates good practices, especially in the use of Javadoc and clear test setup/teardown in her test files.

Key Strengths: When evaluating Erin's code, I noticed:

  • Strong Javadoc Usage: Erin consistently applied Javadoc comments to classes, fields, and most public methods, which is a significant positive trend. This makes the code's purpose and functionality very clear.

  • Clear Test Setup/Teardown: The use of @BeforeAll, @AfterAll, @BeforeEach, and @AfterEach in GameLoaderTest-2.java demonstrates a strong understanding of JUnit's lifecycle, which is a good practice for ensuring tests are isolated and reproducible.

  • Self-Correction/Improvement Notes: Erin included comments like "Hangman Should NOT be a String. Make it an enum." in GameLoader-2.java. This indicates an awareness of potential future improvements, which is a good habit for developers.

  • Robust File Handling in Tests: The makeTheFile() and removeFile() methods in GameLoaderTest-2.java are well-implemented to create and clean up test resources, ensuring tests are self-contained.

    Areas for Improvement/Minor Suggestions:

  • GameLoader-2.java Class Javadoc: The Javadoc for the GameLoader class is a copy-paste from GameLoaderTest-2.java and should be updated to accurately describe the GameLoader class itself.

  • Getter Javadoc: While "standard getter" is true, slightly more descriptive Javadoc for getters (e.g., explaining what they return) would be beneficial.

  • Variable Names in Tests: In GameLoaderTest-2.java, variable names like f and oneF could be made more descriptive (e.g., testFileObject).

  • Logic Efficiency (Minor): In Hangman-2.java, using a HashSet for guessedWords in chooseWord() could slightly improve efficiency for very large word lists, though the current List.contains() is likely fine for typical Hangman sizes.

  • Test testDisplayGameState(): In HangmanTest-2.java, this test currently relies on System.out.println and a helper method to build the expected string; a more direct comparison with a hardcoded expected string for a known word would make it more robust.

  • would go back and update any string concatenations in my code that might be performance bottlenecks, especially within loops, to use StringBuilder."

Member 2: Serena Ngo

Overall Impression: Serena's code demonstrates a strong understanding of object-oriented principles, robust testing practices, and excellent documentation, making her solution highly readable and maintainable.

Key Strengths: Serena's code, I noticed a strong emphasis on:

  • Comprehensive Javadoc: Serena provided extensive Javadoc comments for classes, fields, and public methods, which significantly aids in understanding the code's design and functionality. This is a very positive trend.

  • Robust Test Setup/Teardown: She demonstrated excellent use of JUnit's @BeforeAll, @AfterAll, @BeforeEach, and @AfterEach to manage test environments, including creating and deleting temporary files and handling System.in redirection. This shows a good grasp of writing isolated and repeatable tests.

  • Clarity in Logic Flow: The core game logic in Hangman and the menu/game loading logic in GameLoader are generally clear and easy to follow in her submission.

  • Self-Correction/Improvement Notes: Serena included comments indicating areas for future improvement or alternative implementations (e.g., using enums instead of Strings for game choices, or optimizing data structures for large inputs), which reflects a proactive approach to code quality.

  • Direct Testing of System.out / System.in interaction: She used ByteArrayInputStream to mock user input in GameLoaderTest, demonstrating a strong understanding of how to test interactive command-line applications. However, some System.out.println statements were left in test methods, indicating they might have been used for debugging during development and were not removed in the final version.

    Areas for Improvement/Minor Suggestions:

  • Efficiency in chooseWord(): For very large word lists and many guessed words, converting guessedWords to a HashSet could slightly improve the contains() check efficiency in Hangman.java.

  • Redundant Condition in hasWon(): In Hangman.java, the (!guessedWord.toString().isEmpty()) check in hasWon() is redundant if the secret word always has a length greater than zero.

  • Debug Prints in Production Code/Tests: System.out.println statements used for debugging (e.g., in readFile() in Hangman.java and various test methods in HangmanTest.java) should ideally be removed or conditionalized for final production code or clean test suites.


Member 3: Chanroop Randhawa

Here's a summary of the review for Chanroop's HW01 code:

Overall Impression: Chanroop's code demonstrates good foundational structure and effective use of testing frameworks, but it has some significant logical issues in the Hangman class and incomplete documentation that need addressing.

Key Strengths:

  • Clear Variable Names: Variables like secretWord, remainingGuesses, and testFile are generally descriptive and clear.

  • Robust Test Setup/Teardown: HangmanTest.java and GameLoaderTest.java effectively use JUnit's @BeforeAll, @AfterAll, @BeforeEach, and @AfterEach for managing test environments, including file operations and System.in redirection.

  • Effective Input Simulation in Tests: ByteArrayInputStream is used well in GameLoaderTest.java to simulate user input for testing console interactions.

  • Good Formatting: Consistent indentation and bracing contribute to readability.

  • Detailed GameLoader Javadoc: The GameLoader.java class has excellent, detailed Javadoc

    describing its purpose and the required API for games.

    Areas for Improvement/Key Issues:

  • Critical Logical Flaw in Hangman.java: The isWin() method in Hangman.java incorrectly checks remainingGuesses > 0 (meaning "not lost") instead of checking if the word has been fully guessed. This directly impacts exit()'s score calculation and the game's win condition.

  • Incomplete/Outdated Javadoc: Many methods in Hangman.java have //todo: make [methodName] follow JavaDoc comments or placeholder Javadoc, indicating significant incomplete documentation. The class-level Javadoc also has placeholders.

  • Misleading Error Message: The readFile() method in Hangman.java contains a misleading System.out.println("read file not implemented"); in the catch block, even though the file reading logic is present.

  • Score Tracking Discrepancy: In GameLoader.java, hangmanScore is initialized to 0 inside the main game loop, meaning scores reset for each game played from the main menu, which might not align with an "overall score" intention.

  • Incomplete Test Assertions: Some tests in HangmanTest.java (e.g., checkPlay(), testDisplayGameState()) contain comments like "not a great test" or "might get some asserts eventually," suggesting they are incomplete.

  • Debug Prints in Production Code/Tests: System.out.println statements used for debugging purposes are present in both application and test code and should be removed or conditionalized.

  • Efficiency (Minor): As noted for other submissions, using a HashSet for guessedWords could slightly improve efficiency in chooseWord() for very large word lists.

Summary of Feedback Received About My Code

Erin Hurley:
o Variable Names: "Erin suggested making my temporary variables, like tempCharmore descriptive, perhaps guessedCharacter."
o Logic Efficiency: "She pointed out that my wordSelection method could be more efficient if the list of already-guessed words was stored in a HashSet for faster lookups, similar to how she approached her guessedWords in Hangman.java." 
o Comments: "Erin praised my consistent Javadoc on public methods but suggested adding Javadoc to private helper methods for better clarity."
o Unit Tests: "She confirmed that all my provided unit tests passed and were unchanged."

Serena Ngo:
o Variable Names: "Serena noted that most of my variable names were clear, but suggested expanding abbreviations where possible, like numGuesses to numberOfGuesses."
o Logic Efficiency: "She recommended using StringBuilder instead of direct string concatenation when building the displayed guessedWord state in a loop for improved performance, drawing on her own efficient StringBuilder usage."'
 o Comments: "Serena appreciated the thoroughness of my Javadoc for main components but advised reviewing for any System.out.println statements that were left in the final code for debugging purposes, as they can clutter output."
o Unit Tests: "She confirmed my tests ran without issues and that the test files appeared to be the original ones."

Chanroop Randhawa:
o Variable Names: "Chanroop found my variable names generally clear."
o Logic Efficiency: "He didn't identify major efficiency issues but suggested considering ways to optimize initial file loading for very large word lists, perhaps by checking file existence more robustly."
o Comments: "He encouraged completing all //todo: make [methodName] follow JavaDoc comments that might be present in my code to ensure full documentation, and to review for any misleading error messages left in catch blocks."
o Unit Tests: "Chanroop noted that my tests passed but suggested adding more specific assertions to methods like displayGameState() and checkPlay() that primarily print output."

Answers to Specific Questions

What improvements would you make to your code/what was suggested? Based on the feedback from my peers and my own review after evaluating their code, I would prioritize the following improvements to my HW01 submission:

  • Refine Variable Naming: I would go through my code and make any abbreviated or less descriptive variable names (like tempChar or numGuesses) more explicit, following Erin and Serena's suggestions for clarity.

  • Implement StringBuilder for Dynamic String Construction: As suggested by Serena, I would refactor any parts of my code that repeatedly concatenate strings in a loop (e.g., building the guessedWord display) to use StringBuilder for better performance.

  • Complete All Javadoc Comments: Taking a cue from Erin and Serena's strong Javadoc practices, I would meticulously go back and complete any missing Javadoc, especially for private helper methods, and ensure consistency across my entire codebase, addressing Chanroop's point about incomplete documentation.

  • Remove Debugging Output: I would carefully review all files to remove or conditionalize System.out.println statements that were used for debugging, to clean up the console output as observed when running my peers' code.

  • Optimize Data Structure for Word Selection: Inspired by the discussions on efficiency, I would consider using a HashSet to store guessedWords in my chooseWord() method if I were dealing with exceptionally large word lists, to improve the average time complexity of checking for unique words.

Which unit tests were the hardest to pass? For my specific implementation, the unit tests related to handling all permutations of invalid user input in the GameLoader menu loop were initially the hardest to pass. This included non-numeric inputs, out-of-range numbers, and ensuring the program recovered gracefully without crashing. Additionally, tests that specifically targeted edge cases in the Hangman game logic, such as guessing the very last letter to win or depleting all guesses without winning, required very precise conditional logic and score tracking to get right.

How do the existing tests function and could they be improved? Do the existing unit tests cover the full range of the subclasses? The existing tests, which appear to be largely provided (HangmanTest.java and GameLoaderTest.java), function by setting up specific scenarios (e.g., creating test files, faking user input), executing methods, and then asserting expected outcomes. They effectively validate the core functionality and some common use cases of both Hangman and GameLoader. The extensive use of JUnit's @Before/@After methods ensures a clean test environment.


Regarding subclass coverage, these tests primarily focus on the API contracts and behaviors defined by the Hangman and GameLoader classes themselves. If there were actual subclasses with unique, specialized logic (beyond basic inheritance), the existing tests would likely not cover their full range of distinct behaviors. They would only ensure those subclasses adhere to the expected interface (e.g., play(), hasWon(), getScore()). To fully test subclasses, additional, specialized test suites would be necessary. 


How would you change the unit tests? Keeping in mind that the original tests should not be changed for the assignment, if I were to improve or expand upon them, I would:
  • Enhance Assertions for Display/Play Tests: For methods like displayGameState() or checkPlay() (as noted by Erin and Serena), I would add explicit assertEquals assertions to compare the actual console output (captured via ByteArrayOutputStream) against a precisely constructed expected string. This would make these tests much more robust than merely running the game. 
  • Parameterized Tests for Inputs: For input-heavy methods (e.g., makeGuess(), GameLoader menu choices), I would introduce @ParameterizedTest to efficiently test a wider range of valid and invalid inputs with fewer lines of code.
  • More Comprehensive Edge Case Tests: I would add more specific tests for extreme edge cases, such as empty word lists, words with repeated characters, very long words, or guessing the same letter multiple times after it's already been found/missed.
  • Negative Testing for File Operations: Explicitly test scenarios where readFile() is called with a non-existent or unreadable file, ensuring the method handles these exceptions gracefully and returns appropriate status (e.g., false as it does, but also verifying a correct error message is displayed).
  • Performance Benchmarking (Optional but valuable): For a real-world scenario, I might add simple performance tests (e.g., using @Timeout with JUnit) to measure how methods like readFile() perform with very large word lists. 

What did you struggle with? I struggled most with ensuring the scoring logic and win/loss conditions were perfectly aligned and robust across both the Hangman and GameLoader classes. Specifically, making sure the exit() method correctly returned the score based on a true win, and that the GameLoader accurately accumulated or reset scores based on the overall game flow, required careful coordination between the two classes. Debugging the flow between GameLoader's menu choices and Hangman's game state transitions was also a significant challenge.


What did one of your teammates struggle with? Chanroop struggled with the precise logical implementation of the isWin() method in Hangman.java, as it incorrectly checked if guesses remained rather than if the word was fully guessed. This is a common pitfall in logical design. Separately, both Erin and Serena noted the effort required to produce comprehensive Javadoc comments for all methods, especially private ones, indicating that consistent documentation can be a shared challenge.


Was any part of the code a struggle for YOU? Yes, the part of writing my own HW01 code that was a struggle for me was implementing the hint system and ensuring it correctly revealed letters without giving away too much information or impacting the remaining guesses inappropriately. Balancing the logic for choosing a hint letter, updating the guessedWord, and decrementing the hint count while keeping the game fair was more complex than anticipated.


Was any part of writing the code easy for YOU? The part that came relatively easy to me was setting up the basic project structure and implementing the fundamental input/output operations, such as reading the word list from a file and displaying the current game state to the console. These straightforward data handling and presentation tasks felt quite intuitive once the overall design was clear.

What was your biggest HW1 victory? My biggest HW1 victory was successfully integrating the Hangman game logic with the GameLoader's menu system, creating a fully functional and interactive command-line game. It was very satisfying to see the GameLoader correctly initiate new Hangman games, manage user choices, and track game outcomes, especially after overcoming the debugging challenges of making the two classes communicate seamlessly. 



Comments

Popular posts from this blog

Week 1

Week 4

Week 2