Skip to content

Commit

Permalink
Merge pull request #5 from BrianLusina/feat/game-logic
Browse files Browse the repository at this point in the history
Game logic & Game Loop
  • Loading branch information
BrianLusina authored Dec 2, 2023
2 parents 78d39cc + 26abd1b commit 396f4fe
Show file tree
Hide file tree
Showing 10 changed files with 113 additions and 92 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/dangerci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -49,5 +49,5 @@ jobs:
uses: danger/danger-js@9.1.8
env:
CI: true
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
DANGER_GITHUB_API_TOKEN: ${{ secrets.GH_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
DANGER_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ install: ## Installs dependencies
pipenv install

run: ## Runs application
hangman -a
python hangman

.PHONY: test
test: ## Runs tests
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,5 +49,7 @@ words.
To execute `hangman`, go ahead and run the below command:

```shell
hangman -a
python hangman
```

Which will run the game. Enjoy!
56 changes: 34 additions & 22 deletions hangman/__main__.py
Original file line number Diff line number Diff line change
@@ -1,35 +1,47 @@
"""
Entry point of the game
"""
import argparse
import sys
from typing import Set
from hangman.word_repository import select_word
from hangman.utils import build_guessed_word, join_guessed_letters
from hangman.game import game_over, MAX_INCORRECT_GUESSES
from hangman.draw import draw_hanged_man
from hangman.player_input import get_player_input


def main() -> None:
"""Entry point of the game. Gets the command line arguments and shows either all patterns of the game or a single
pattern based on the user input from the command line"""
args = get_command_line_args()
view = getattr(views, args.view)
target_word = select_word()
guessed_letters: Set[str] = set()
guessed_word = build_guessed_word(target_word, guessed_letters)
wrong_guesses = 0
print("Welcome to Hangman")

if args.all:
for pattern in patterns.get_all_patterns():
_show_pattern(view, pattern, args)
while not game_over(wrong_guesses, target_word, guessed_letters):
draw_hanged_man(wrong_guesses)
print(f"Your word is: {guessed_word}")
print(
f"Current guessed letters: word is: {join_guessed_letters(guessed_letters)}\n"
)

player_guess = get_player_input(guessed_letters)
if player_guess in target_word:
print("Great guess!")
else:
print("Sorry, it's not there.")
wrong_guesses += 1

guessed_letters.add(player_guess)
guessed_word = build_guessed_word(target_word, guessed_letters)

# game over
draw_hanged_man(wrong_guesses)
if wrong_guesses == MAX_INCORRECT_GUESSES:
print("Sorry, you lost!")
else:
_show_pattern(view, patterns.get_pattern(name=args.pattern), args)


def _show_pattern(
view: views.CursesView,
pattern: patterns.Pattern,
args: argparse.Namespace,
) -> None:
"""Shows the pattern given the view, pattern and arguments from the command line"""
try:
v = view(pattern=pattern, gen=args.gen, frame_rate=args.fps) # type: ignore[operator]
v.show()
# pylint: disable=broad-exception-caught
except Exception as error:
print(error, file=sys.stderr)
print("Congrats, You did it!")
print(f"Your word was {target_word}")


if __name__ == "__main__":
Expand Down
57 changes: 0 additions & 57 deletions hangman/cli.py

This file was deleted.

14 changes: 7 additions & 7 deletions hangman/draw.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
Contains draw utilities to draw the hangman
"""
_hanged_man = [
r"""
r"""
-----
| |
|
Expand All @@ -15,7 +15,7 @@
|
-------
""",
r"""
r"""
-----
| |
O |
Expand All @@ -28,7 +28,7 @@
|
-------
""",
r"""
r"""
-----
| |
O |
Expand All @@ -41,7 +41,7 @@
|
-------
""",
r"""
r"""
-----
| |
O |
Expand All @@ -54,7 +54,7 @@
|
-------
""",
r"""
r"""
-----
| |
O |
Expand All @@ -67,7 +67,7 @@
|
-------
""",
r"""
r"""
-----
| |
O |
Expand All @@ -80,7 +80,7 @@
|
-------
""",
r"""
r"""
-----
| |
O |
Expand Down
30 changes: 30 additions & 0 deletions hangman/game.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
"""
Contains the game logic
"""
from typing import Set

MAX_INCORRECT_GUESSES = 6


def game_over(wrong_guesses: int, target_word: str, guessed_letters: Set[str]) -> bool:
"""
Checks if the game is over based on the number of wrong guesses, target word and the guessed letters. It returns
True if the number of wrong guesses is equal to the maximum allowed incorrect guesses, which is defaulted to 6.
Also, it returns true if the set of the target word is a member of every letter in the guessed letters
Args:
wrong_guesses (int): number of incorrect guesses
target_word (str): the target word
guessed_letters (set): set of alredy guessed letters by the player.
Returns:
bool: True indicating the game is over, false indicating that the game is still ongoing
"""
if wrong_guesses >= MAX_INCORRECT_GUESSES:
return True

# checks if every item on the left-hand side set is a member of the right-hand side set. In other words, are the
# letters in the target word in the guessed letters set from the player?
if set(target_word) <= guessed_letters:
return True

return False
6 changes: 5 additions & 1 deletion hangman/player_input.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,8 @@ def validate_input(player_input: str, guessed_letters: Set[str]) -> bool:
Returns:
bool: True if the player input is valid, false otherwise
"""
return len(player_input) == 1 and player_input in string.ascii_lowercase and player_input not in guessed_letters
return (
len(player_input) == 1
and player_input in string.ascii_lowercase
and player_input not in guessed_letters
)
2 changes: 1 addition & 1 deletion hangman/word_repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@ def select_word(filename: Path = WORDS_FILE) -> str:
Return:
str: randomly selected word
"""
with open(filename, mode="r") as words:
with open(filename, mode="r", encoding="utf-8") as words:
word_list = words.readlines()
return choice(word_list).strip()
30 changes: 30 additions & 0 deletions tests/test_game.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import unittest
from hangman.game import game_over


class GameTestCase(unittest.TestCase):
def test_returns_true_for_incorrect_guesses(self):
"""should return True if the wrong guesses equals the maximum allowed wrong guesses"""
wrong_guesses = 6
actual = game_over(wrong_guesses, "airplane", {"a"})
self.assertTrue(actual)

def test_returns_true_if_target_word_is_in_guessed_letters(self):
"""should return True if the letters in the target word are in the guessed letters"""
wrong_guesses = 3
target_word = "airplane"
guessed_letters = {"a", "i", "r", "p", "l", "n", "e"}
actual = game_over(wrong_guesses, target_word, guessed_letters)
self.assertTrue(actual)

def test_returns_true_if_wrong_guesses_is_more_than_allowed_maximum(self):
"""should return True if the number of wrong guesses is more than allowed maximum"""
wrong_guesses = 7
target_word = "airplane"
guessed_letters = {"a", "i", "r", "p", "l", "n"}
actual = game_over(wrong_guesses, target_word, guessed_letters)
self.assertTrue(actual)


if __name__ == '__main__':
unittest.main()

0 comments on commit 396f4fe

Please sign in to comment.