Skip to content

Commit

Permalink
TP1 correction partielle (#11)
Browse files Browse the repository at this point in the history
  • Loading branch information
LoicRiegel committed Mar 26, 2024
1 parent 6f670a7 commit 2a8f0f1
Show file tree
Hide file tree
Showing 8 changed files with 211 additions and 1 deletion.
17 changes: 17 additions & 0 deletions TP1/Correction/README.md
@@ -0,0 +1,17 @@
# Correction

## Usage

Attention, je n'ai pas créé de package python. Il faut donc exécuter les scripts python **depuis ce dossier** avec le terminal:

```sh
cd correction
python guess_the_number.py
python count_words.py # then input testfiles/words.txt
```

Notez que la fonction `utils.get_int_from_user` est assez grande et a beaucoup de responsabilités. Si, dans le futur, nous voulons changer le comportement (ajouter des checks, ou en modifier...), on pourrait extraire chaque vérification dans une petite fonction spécialisée:
- une fonction qui vérifie la conversion en nombre
- une fonction qui vérifie qu'on a un int et pas un float
- une fonction qui vérifie le range
- ...
34 changes: 34 additions & 0 deletions TP1/Correction/count_words.py
@@ -0,0 +1,34 @@
"""Count the number of words in a file."""

from collections import Counter

import utils

DEFAULT_WORD_TO_SEARCH = "python"


def get_word_occurrence(text: str, word: str, case_sensitive: bool = False) -> int:
"""Return the number of times `word` appears in `text`."""
if not case_sensitive:
text = text.lower()
word = word.lower()

word_occurrence = 0
for line in text.split("\n"):
for word in line.split(" "):
if word == DEFAULT_WORD_TO_SEARCH:
word_occurrence += 1

return word_occurrence


def main(word_to_search: str) -> None:
"""Count the number of times a word is written in a text file provided by the user."""
path = utils.get_file_from_user("Path to file to search: ")
text = path.read_text()
word_occurrence = get_word_occurrence(text, word_to_search)
print(f"The word {word_to_search} appears {word_occurrence} times in {path.name}")


if __name__ == "__main__":
main(DEFAULT_WORD_TO_SEARCH)
26 changes: 26 additions & 0 deletions TP1/Correction/fizz_buzz.py
@@ -0,0 +1,26 @@
"""Implementation of the FizzBuzz game."""

import utils


def fizz_buzz(number: int) -> str:
"""Return Fizz if the number is divisible by 3, Buzz if divisible by 5
FizzBuzz if divisible by both 3 and 5. Otherwise returns the input number as a string.
"""
if number % 3 == 0 and number % 5 == 0:
return "FizzBuzz"
if number % 3 == 0:
return "Fizz"
if number % 5 == 0:
return "Buzz"
return str(number)


def main() -> None:
"""Implementation of the FizzBuzz game."""
number = utils.get_int_from_user("Enter any number: ")
print(fizz_buzz(number))


if __name__ == "__main__":
main()
43 changes: 43 additions & 0 deletions TP1/Correction/guess_the_number.py
@@ -0,0 +1,43 @@
"""Implementation of a "Guess the number" game"""

import random

import utils

NUMBER_TO_GUESS_MIN = 0
NUMBER_TO_GUESS_MAX = 100


def generate_rules(number_to_guess_min: int, number_to_guess_max: int) -> str:
"""Return the rules of the game."""
return f"""GUESS THE NUMBER
The computer will randomly pick a number between {number_to_guess_min} and {number_to_guess_max}
Try to guess the number, and the computer will tell you if you guess too high or too low.
The game ends when you guess correctly.
"""


def choose_number_to_guess(lower_limit: int, upper_limit: int) -> int:
"""Randomly choose a number and return it."""
return random.randint(lower_limit, upper_limit)


def main() -> None:
"""Entry point for the game"""
print(generate_rules(NUMBER_TO_GUESS_MIN, NUMBER_TO_GUESS_MAX))
number_to_guess = choose_number_to_guess(NUMBER_TO_GUESS_MIN, NUMBER_TO_GUESS_MAX)

while True:
player_guess = utils.get_int_from_user("Guess the number: ")
if player_guess == number_to_guess:
print("Correct!")
return

if player_guess < number_to_guess:
print("Your number is too low")
else:
print("Your number is too high")


if __name__ == "__main__":
main()
28 changes: 28 additions & 0 deletions TP1/Correction/harmonic_sum.py
@@ -0,0 +1,28 @@
"""Computation of the harmonic sum."""

from fractions import Fraction

import utils


def compute_harmonic_sum(n: int) -> Fraction:
"""Returns the harmonic sum computed of to the n-th term."""
if n <= 0:
raise ValueError(f"harmonic sum cannot be computed to a negative term! Got {n}")
if n == 1:
return Fraction(1)

return Fraction(1, n) + compute_harmonic_sum(n - 1)


def main() -> None:
"""Compute the harmonic sum to the n-th term."""
number_of_terms = utils.get_int_from_user("Enter a positive number: ", value_min=1)
harmonic_sum = compute_harmonic_sum(number_of_terms)
print(
f"Harmonic sum to the {number_of_terms}-th term is {harmonic_sum} ({float(harmonic_sum)})"
)


if __name__ == "__main__":
main()
9 changes: 9 additions & 0 deletions TP1/Correction/testfiles/words.txt
@@ -0,0 +1,9 @@
Hi
Hello
Python
Python
Python hello
Hello
Hi
Hello python something
Python
53 changes: 53 additions & 0 deletions TP1/Correction/utils.py
@@ -0,0 +1,53 @@
"""Some utils functions that are useful in many exercises."""

from pathlib import Path

CURRENT_DIR = Path.cwd().resolve()


def get_int_from_user(
prompt_msg: str,
value_min: int | None = None,
value_max: int | None = None,
max_attempts: int = 2,
) -> int:
"""Ask the user to enter a number in the console within the valid range if a range is provided.
Will raise a ValueError if the user enters an input that cannot be converted to an integer
`max_attempts` times.
"""
for _ in range(max_attempts):
user_input = input(prompt_msg)
try:
user_input_as_float = float(user_input)
except ValueError:
print(f"{user_input} is invalid: please enter a number!")
user_input_as_int = round(user_input_as_float)
if user_input_as_float != user_input_as_int:
print(f"{user_input} is invalid: please enter a non-floating point number")
continue

if value_min is not None and value_min > user_input_as_int:
print(f"{user_input_as_int} has to be greater than {value_min}")
continue
if value_max is not None and value_max < user_input_as_int:
print(f"{user_input_as_int} has to be smaller than {value_max}")
continue

return user_input_as_int

raise ValueError("User input cannot be converted to an integer")


def get_file_from_user(prompt_msg: str, max_attempts: int = 3) -> Path:
"""Ask the user to enter the path to a file from the current directly in the console.
Will raise a FileNotFoundError if the user enters an invalid path
`max_attempts` times.
"""
for _ in range(max_attempts):
user_input = input(prompt_msg)
path = CURRENT_DIR / user_input
if not path.exists() and not path.is_file():
print(f"{path} does not exist or is not a file. Please enter a valid path:")
else:
return path
raise FileNotFoundError("User input invalid path")
2 changes: 1 addition & 1 deletion TP1/README.md
Expand Up @@ -116,7 +116,7 @@ Détails :

## Partie 3 : utilisation d'un linter et d'un formatter formatter

1. installer ``black`` et `flake8` avec `pip`
1. installer ``black`` et ``flake8`` avec ``pip``
2. Executer black et flake8 sur le code écrit durant le TP

Documentations:
Expand Down

0 comments on commit 2a8f0f1

Please sign in to comment.