244 lines
8.5 KiB
Python
244 lines
8.5 KiB
Python
#!/usr/bin/env python3
|
|
import random
|
|
import sys
|
|
import subprocess
|
|
import os
|
|
from fpdf import FPDF
|
|
|
|
|
|
class MathExercisesPDF(FPDF):
|
|
def header(self):
|
|
self.set_font("Helvetica", "B", 16)
|
|
self.cell(
|
|
0,
|
|
10,
|
|
"Exercices de Multiplication et Division",
|
|
0,
|
|
1,
|
|
"C",
|
|
new_x="LMARGIN",
|
|
new_y="NEXT",
|
|
)
|
|
self.ln(10)
|
|
|
|
|
|
def generate_exercises(min_table, max_table, num_exercises=15):
|
|
"""Génère des exercices de multiplication et division aléatoires mélangés sans doublons"""
|
|
exercises = []
|
|
used_operations = set() # Pour éviter les doublons
|
|
|
|
# Générer le nombre exact d'exercices demandé
|
|
attempts = 0
|
|
max_attempts = num_exercises * 10 # Limite pour éviter une boucle infinie
|
|
|
|
while len(exercises) < num_exercises and attempts < max_attempts:
|
|
attempts += 1
|
|
|
|
# Choisir deux nombres aléatoires entre min_table et max_table
|
|
a = random.randint(min_table, max_table)
|
|
b = random.randint(min_table, max_table)
|
|
result = a * b
|
|
|
|
# Choisir aléatoirement le type d'exercice (seulement multiplication ou division)
|
|
exercise_type = random.choice(["multiplication", "division"])
|
|
|
|
if exercise_type == "multiplication":
|
|
# Exercice de multiplication
|
|
operation_key = f"mult_{a}_{b}" # Clé unique pour cette opération
|
|
if operation_key not in used_operations:
|
|
exercise = f"{a} · {b} = ____"
|
|
exercises.append(exercise)
|
|
used_operations.add(operation_key)
|
|
else: # division
|
|
# Exercice de division
|
|
divisor = random.choice([a, b])
|
|
operation_key = f"div_{result}_{divisor}" # Clé unique pour cette opération
|
|
if operation_key not in used_operations:
|
|
exercise = f"{result} : {divisor} = ____"
|
|
exercises.append(exercise)
|
|
used_operations.add(operation_key)
|
|
|
|
# Si nous n'avons pas pu générer suffisamment d'exercices uniques,
|
|
# compléter avec des variations
|
|
if len(exercises) < num_exercises:
|
|
remaining = num_exercises - len(exercises)
|
|
for _ in range(remaining):
|
|
# Générer des variations avec des nombres légèrement différents
|
|
a = random.randint(min_table, max_table)
|
|
b = random.randint(min_table, max_table)
|
|
result = a * b
|
|
|
|
# Choisir aléatoirement le type d'exercice
|
|
exercise_type = random.choice(["multiplication", "division"])
|
|
|
|
if exercise_type == "multiplication":
|
|
exercise = f"{a} · {b} = ____"
|
|
else: # division
|
|
divisor = random.choice([a, b])
|
|
exercise = f"{result} : {divisor} = ____"
|
|
|
|
exercises.append(exercise)
|
|
|
|
return exercises
|
|
|
|
|
|
def create_math_exercises_pdf(min_table, max_table, num_exercises=15):
|
|
"""Crée un fichier PDF avec des exercices de mathématiques mélangés en 3 colonnes"""
|
|
pdf = MathExercisesPDF()
|
|
pdf.add_page()
|
|
pdf.set_font("Helvetica", "", 12)
|
|
|
|
# Ajouter des informations sur la plage de tables
|
|
if min_table == max_table:
|
|
table_info = f"Tables de multiplication et division pour {min_table}"
|
|
else:
|
|
table_info = (
|
|
f"Tables de multiplication et division de {min_table} à {max_table}"
|
|
)
|
|
|
|
pdf.cell(0, 10, table_info, 0, 1, "C", new_x="LMARGIN", new_y="NEXT")
|
|
pdf.ln(5)
|
|
|
|
# Générer les exercices
|
|
exercises = generate_exercises(min_table, max_table, num_exercises)
|
|
|
|
# Pas d'en-têtes de colonnes
|
|
|
|
# Répartir les exercices en 3 colonnes
|
|
num_per_column = (num_exercises + 2) // 3 # Arrondi vers le haut
|
|
col1_exercises = exercises[:num_per_column]
|
|
col2_exercises = exercises[num_per_column : num_per_column * 2]
|
|
col3_exercises = exercises[num_per_column * 2 :]
|
|
|
|
# Ajouter les exercices numérotés de 1 à n dans les colonnes
|
|
max_rows = max(len(col1_exercises), len(col2_exercises), len(col3_exercises))
|
|
|
|
for i in range(max_rows):
|
|
# Colonne 1
|
|
if i < len(col1_exercises):
|
|
exercise_num = i + 1
|
|
col1_text = f"{exercise_num}. {col1_exercises[i]}"
|
|
else:
|
|
col1_text = ""
|
|
|
|
# Colonne 2
|
|
if i < len(col2_exercises):
|
|
exercise_num = i + 1 + len(col1_exercises)
|
|
col2_text = f"{exercise_num}. {col2_exercises[i]}"
|
|
else:
|
|
col2_text = ""
|
|
|
|
# Colonne 3
|
|
if i < len(col3_exercises):
|
|
exercise_num = i + 1 + len(col1_exercises) + len(col2_exercises)
|
|
col3_text = f"{exercise_num}. {col3_exercises[i]}"
|
|
else:
|
|
col3_text = ""
|
|
|
|
# Ajouter la ligne
|
|
pdf.cell(60, 10, col1_text, 0, 0, "L", new_x="RIGHT", new_y="TOP")
|
|
pdf.cell(60, 10, col2_text, 0, 0, "L", new_x="RIGHT", new_y="TOP")
|
|
pdf.cell(60, 10, col3_text, 0, 1, "L", new_x="LMARGIN", new_y="NEXT")
|
|
|
|
# Sauvegarder le PDF
|
|
if min_table == max_table:
|
|
filename = (
|
|
f"exercices_mathematiques_table_{min_table}_{num_exercises}_exercices.pdf"
|
|
)
|
|
else:
|
|
filename = f"exercices_mathematiques_tables_{min_table}_a_{max_table}_{num_exercises}_exercices.pdf"
|
|
pdf.output(filename)
|
|
return filename
|
|
|
|
|
|
def open_pdf(filename):
|
|
"""Ouvre le fichier PDF avec la commande système appropriée"""
|
|
try:
|
|
if sys.platform == "darwin": # macOS
|
|
subprocess.run(["open", filename], check=True)
|
|
elif sys.platform == "win32": # Windows
|
|
os.startfile(filename)
|
|
else: # Linux et autres
|
|
subprocess.run(["xdg-open", filename], check=True)
|
|
return True
|
|
except (subprocess.CalledProcessError, FileNotFoundError, OSError):
|
|
return False
|
|
|
|
|
|
def main():
|
|
"""Fonction principale"""
|
|
# Vérifier les arguments de ligne de commande
|
|
if len(sys.argv) < 3:
|
|
print(
|
|
"Usage: python generate_math_exercises.py <min_table> <max_table> [num_exercises] [--open]"
|
|
)
|
|
print("Exemple: python generate_math_exercises.py 4 7 15")
|
|
print(
|
|
" python generate_math_exercises.py 4 7 15 --open (pour ouvrir automatiquement le PDF)"
|
|
)
|
|
print(
|
|
" python generate_math_exercises.py 5 5 10 (pour seulement la table de 5)"
|
|
)
|
|
sys.exit(1)
|
|
|
|
# Vérifier si l'option --open est présente
|
|
open_after_creation = "--open" in sys.argv
|
|
if open_after_creation:
|
|
sys.argv.remove("--open") # Retirer l'option de la liste des arguments
|
|
|
|
try:
|
|
min_table = int(sys.argv[1])
|
|
max_table = int(sys.argv[2])
|
|
if min_table < 1 or max_table < 1:
|
|
raise ValueError("Les tables doivent être supérieures à 0")
|
|
if min_table > max_table:
|
|
raise ValueError(
|
|
"La table minimale doit être inférieure ou égale à la table maximale"
|
|
)
|
|
except ValueError as e:
|
|
print(f"Erreur: {e}")
|
|
sys.exit(1)
|
|
|
|
# Nombre d'exercices (par défaut 15)
|
|
num_exercises = 15
|
|
if len(sys.argv) > 3:
|
|
try:
|
|
num_exercises = int(sys.argv[3])
|
|
if num_exercises < 1:
|
|
raise ValueError("Le nombre d'exercices doit être supérieur à 0")
|
|
except ValueError as e:
|
|
print(f"Erreur: {e}")
|
|
sys.exit(1)
|
|
|
|
# Créer le PDF
|
|
try:
|
|
filename = create_math_exercises_pdf(min_table, max_table, num_exercises)
|
|
print(f"Fichier PDF '{filename}' créé avec succès !")
|
|
if min_table == max_table:
|
|
print(f"- Exercices pour la table de {min_table}")
|
|
else:
|
|
print(f"- Exercices pour les tables de {min_table} à {max_table}")
|
|
print(
|
|
f"- {num_exercises} exercices MÉLANGÉS générés aléatoirement et numérotés de 1 à {num_exercises}"
|
|
)
|
|
print("- Types d'exercices : multiplications (·) et divisions (:) uniquement")
|
|
print("- Présentés en 3 colonnes pour économiser l'espace")
|
|
print("- Aucune opération en double (quand c'est possible)")
|
|
|
|
# Ouvrir le PDF si demandé
|
|
if open_after_creation:
|
|
if open_pdf(filename):
|
|
print("\nPDF ouvert automatiquement avec succès !")
|
|
else:
|
|
print(
|
|
"\nImpossible d'ouvrir automatiquement le PDF. Vous pouvez l'ouvrir manuellement."
|
|
)
|
|
|
|
except Exception as e:
|
|
print(f"Erreur lors de la création du PDF: {e}")
|
|
sys.exit(1)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|