Step 3
TirSystem/github-action: Sync GitHub mirror metadata / sync-metadata (push) Successful in 5s

Checking if the player has won
This commit is contained in:
2026-10-04 12:40:15 +08:00
parent 15d5f7134d
commit ce87f23314
6 changed files with 66 additions and 24 deletions
+4 -2
View File
@@ -17,8 +17,8 @@ A beginner-friendly Python program that lets you play Hangman in the terminal ag
Day 7 of Udemy's *100 Days of Code™: The Complete Python Pro Bootcamp*. The game is built in five steps that follow the course: Day 7 of Udemy's *100 Days of Code™: The Complete Python Pro Bootcamp*. The game is built in five steps that follow the course:
1. Picking a random word and checking answers 1. Picking a random word and checking answers
2. Replacing blanks with guesses *(this step)* 2. Replacing blanks with guesses
3. Checking if the player has won 3. Checking if the player has won *(this step)*
4. Keeping track of the player's lives 4. Keeping track of the player's lives
5. Improving the user experience 5. Improving the user experience
@@ -26,6 +26,8 @@ Day 7 of Udemy's *100 Days of Code™: The Complete Python Pro Bootcamp*. The ga
**Step 2:** the word is shown as blanks (`_ _ _ _ _`). After your guess every matching blank is replaced by the letter. **Step 2:** the word is shown as blanks (`_ _ _ _ _`). After your guess every matching blank is replaced by the letter.
**Step 3:** the game keeps asking for letters until every blank is filled, then prints "You win!". (There are no lives yet, so wrong guesses cost nothing.)
## 📋 Requirements ## 📋 Requirements
- Python 3.13 or newer - Python 3.13 or newer
+3
View File
@@ -23,3 +23,6 @@ WORD_LIST = [
"squirrel", "squirrel",
"tortoise", "tortoise",
] ]
## Message shown when the player wins.
MSG_WIN = "You win!"
+7
View File
@@ -58,3 +58,10 @@ class Game:
@return For example `"p _ n g _ i n"`. @return For example `"p _ n g _ i n"`.
""" """
return " ".join(c if c in self.guesses else BLANK for c in self.word) return " ".join(c if c in self.guesses else BLANK for c in self.word)
@property
def won(self) -> bool:
"""!
@brief True when every letter of the word has been guessed.
"""
return all(c in self.guesses for c in self.word)
+19 -9
View File
@@ -3,6 +3,7 @@
@brief Command-line interface for Hangman. @brief Command-line interface for Hangman.
""" """
from hangman.constants import MSG_WIN
from hangman.game import Game, choose_word from hangman.game import Game, choose_word
@@ -14,18 +15,27 @@ def say(message: str = "") -> None:
print(message) print(message)
def play(game: Game) -> None:
"""!
@brief Ask for letters until every blank is filled.
@param game The game to play.
"""
say(game.display())
while not game.won:
letter = input("Guess a letter: ").strip()
if game.guess(letter):
say(f"Right, '{letter.lower()}' is in the word.")
else:
say(f"Wrong, '{letter.lower()}' is not in the word.")
say(game.display())
say(MSG_WIN)
def main() -> None: def main() -> None:
"""! """!
@brief Entry point: show the blanks, take one guess and show the result. @brief Entry point: start a game with a random word.
""" """
game = Game(choose_word()) play(Game(choose_word()))
say(game.display())
letter = input("Guess a letter: ").strip()
if game.guess(letter):
say(f"Right, '{letter.lower()}' is in the word.")
else:
say(f"Wrong, '{letter.lower()}' is not in the word.")
say(game.display())
if __name__ == "__main__": if __name__ == "__main__":
+15
View File
@@ -30,3 +30,18 @@ def test_wrong_guess_keeps_blanks():
g = Game("cat") g = Game("cat")
assert g.guess("z") is False assert g.guess("z") is False
assert g.display() == "_ _ _" assert g.display() == "_ _ _"
def test_not_won_until_all_letters_guessed():
g = Game("hi")
assert not g.won
g.guess("h")
assert not g.won
g.guess("i")
assert g.won
def test_wrong_guesses_do_not_win():
g = Game("hi")
g.guess("x")
assert not g.won
+18 -13
View File
@@ -1,23 +1,28 @@
from hangman import main as cli from hangman import main as cli
from hangman.game import Game
def run(monkeypatch, capsys, word, letter): def run(monkeypatch, capsys, word, inputs):
monkeypatch.setattr(cli, "choose_word", lambda: word) it = iter(inputs)
monkeypatch.setattr("builtins.input", lambda _="": letter) monkeypatch.setattr("builtins.input", lambda _="": next(it))
cli.main() cli.play(Game(word))
return capsys.readouterr().out return capsys.readouterr().out
def test_right_guess_fills_blanks(monkeypatch, capsys): def test_play_until_won(monkeypatch, capsys):
out = run(monkeypatch, capsys, "camel", "a") out = run(monkeypatch, capsys, "hi", ["z", "h", "i"])
assert out.splitlines() == [ assert out.splitlines() == [
"_ _ _ _ _", "_ _",
"Right, 'a' is in the word.", "Wrong, 'z' is not in the word.",
"_ a _ _ _", "_ _",
"Right, 'h' is in the word.",
"h _",
"Right, 'i' is in the word.",
"h i",
"You win!",
] ]
def test_wrong_guess_keeps_blanks(monkeypatch, capsys): def test_repeated_letter_fills_all_blanks(monkeypatch, capsys):
out = run(monkeypatch, capsys, "camel", "z") out = run(monkeypatch, capsys, "aa", ["a"])
assert "Wrong" in out assert out.splitlines()[-2:] == ["a a", "You win!"]
assert out.splitlines()[-1] == "_ _ _ _ _"