Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TP1 correction partielle #11

Merged
merged 9 commits into from Mar 26, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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 imagine extraire chaque check dans une peitte fonction spécialisée:
LoicRiegel marked this conversation as resolved.
Show resolved Hide resolved
- 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
- ...
28 changes: 28 additions & 0 deletions TP1/Correction/count_words.py
@@ -0,0 +1,28 @@
"""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()
words_counter = Counter(text.split())
LoicRiegel marked this conversation as resolved.
Show resolved Hide resolved
return words_counter.get(word, 0)


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"
LoicRiegel marked this conversation as resolved.
Show resolved Hide resolved
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)
LoicRiegel marked this conversation as resolved.
Show resolved Hide resolved


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
Hi
Hello
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