Add timed mode, a hint system, and length-based tries#256
Conversation
There was a problem hiding this comment.
Pull request overview
This PR extends the Hangman web UI and backend with optional gameplay mechanics (timed mode, hints, and length-based allowed failures), updates the word list and i18n strings, and refreshes the Selenide/Selenium UI test suites and Gradle tasks to reflect the new UI flow.
Changes:
- Add mode selection (timed/untimed), countdown timer, keyboard shortcuts, and a How-to-play modal in the web UI.
- Add hint UI/logic and length-based
maxErrorsin the model + API responses. - Expand the dictionary and update unit/UI tests and Gradle UI-test tasks.
Reviewed changes
Copilot reviewed 16 out of 17 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| test/uitest/selenium_page_objects/HangmanWithPageObjectTest.java | Updates Selenium UI tests for hint + mode selection flow (currently assumes deterministic words). |
| test/uitest/selenium_page_objects/HangmanPage.java | Updates Selenium page object to support mode selection and hint elements. |
| test/uitest/selenide/HangmanSpec.java | Updates/extends Selenide specs for hint/timer/how-to UI (currently assumes deterministic words). |
| test/uitest/selenide_page_objects/HangmanSpec.java | Updates Selenide page-object specs for new flow (currently assumes deterministic words). |
| test/uitest/selenide_page_objects/HangmanPage.java | Adds page-object actions for mode selection and hint. |
| test/ee/era/hangman/model/HangmanTest.java | Adds unit tests for length-based maxErrors. |
| src/words.001.csv | Expands word/topic inventory (increases randomness/variation for UI tests). |
| src/webapp/js/hangman.js | Implements mode select, timer, hint lock/unlock, keyboard input, and updated failure rendering. |
| src/webapp/index.html | Adds mode select UI, hint UI, SVG hangman, and How-to-play modal markup. |
| src/webapp/css/hangman.css | Styles new toolbar/mode buttons/timer/hint UI and modal. |
| src/messages_ru.properties | Adds i18n strings for hint/mode/how-to-play. |
| src/messages_et.properties | Adds i18n strings for hint/mode/how-to-play. |
| src/messages_en.properties | Adds i18n strings for hint/mode/how-to-play. |
| src/ee/era/hangman/model/Hangman.java | Introduces length-based maxErrors and exposes it via getMaxErrors(). |
| src/ee/era/hangman/actions/Guess.java | Includes maxErrors in guess response JSON. |
| src/ee/era/hangman/actions/Game.java | Includes maxErrors in start-game response JSON. |
| build.gradle | Refactors UI test tasks to parameterize browser selection and scope to uitest/**. |
Comments suppressed due to low confidence (1)
test/uitest/selenium_page_objects/HangmanWithPageObjectTest.java:55
- These Selenium page-object tests assume the started game always uses the same word length ("____") and topic ("house"), but
/gamepicks a random word fromsrc/words.001.csvand max errors now depend on word length. With multiple words/topics per language, the assertions (and the win/lose flows that assume the word is "sofa" and 6 tries) become nondeterministic/flaky. Consider adding a deterministic word selection hook for UI tests (seeded RNG or test-only fixed word/topic parameter) and update the tests to use it.
@Test
public void showsMaskedWord() {
assertThat(hangmanPage.wordInWork.getText()).isEqualTo("____");
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| function revealHint() { | ||
| if (!isPlaying || elements.hintButton.disabled) return; | ||
| elements.topic.style.visibility = 'visible'; | ||
| elements.hintButton.style.display = 'none'; | ||
| elements.hintLocked.textContent = ''; |
| </button> | ||
| </div> | ||
|
|
||
| <div id="howToPlayModal" style="display: none;"> |
| public void revealHint() { | ||
| $("#hintButton").click(); | ||
| } |
| public void showsMaskedWordAndLockedHintAtTheBeginning() { | ||
| $("#wordInWork").shouldHave(text("____")); | ||
| $("#hintButton").shouldBe(disabled); | ||
| $("#topic").shouldNotBe(visible); | ||
| } |
| @Test | ||
| public void showsTopicAndMaskedWordAtTheBeginning() { | ||
| page.shouldHaveTopic("house"); | ||
| public void showsMaskedWordAtTheBeginning() { | ||
| page.shouldHaveWord("____"); | ||
| } |
| updateHintLock(); | ||
|
|
Extend the game with several new mechanics: - Mode select: a start screen to choose Timed or Untimed. In timed mode a countdown (a base allowance plus a few seconds per letter) runs while you guess, and running out loses the round. - Hints: reveal one letter of the target word, unlocked only after a number of wrong guesses. Until then a locked label counts down how many more wrong guesses are needed. - Length-based tries: the number of allowed wrong guesses now scales with word length (6 + one per letter beyond five) instead of a fixed six, so longer words are fairer. - Keyboard input for letters, a "How to play" panel, and a "Play again" flow, with restyled board, timer and hint UI. New message strings for all of the above in English, Estonian and Russian. Adds model unit tests for the length-based try count and extends the Selenide UI specs and page objects to cover the new controls.
90b7045 to
643c657
Compare
|
@shayanmohd All good, thank you for the contribution!
The long word is probably easier to guess. Because every letter player tries has greater chance to occur in the word.
|
Add timed mode, a hint system, and length-based tries
Extends the game with a few optional mechanics, all reachable from the UI. The classic flow (untimed, six tries) still works; the new pieces are opt-in from the start screen.
Mode select
A start screen to choose Timed or Untimed. In timed mode a countdown (a base allowance plus a few seconds per letter) runs while you guess; running out loses the round.
Hints
Reveal one letter of the target word, unlocked only after a number of wrong guesses. Until then a locked label counts down how many more wrong guesses are needed.
Length-based tries
Allowed wrong guesses now scale with word length (
6 + one per letter beyond five) instead of a fixed six, so longer words are fairer. Covered by newHangmanTestcases.Also
Checks
./gradlew checkpasses locally (compile + unit tests). Theuitest_chrome/uitest_firefoxjobs need a browser and weren't run on my machine, but the UI test sources compile.Since this repo is primarily a Selenide example, happy to trim the scope (e.g. land just the UI-test additions, or split the gameplay features out) if that fits the project better. Just let me know.