#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Pyromaths
# Un programme en Python qui permet de créer des fiches d'exercices types de
# mathématiques niveau collège ainsi que leur corrigé en LaTeX.
# Copyright (C) 2006 -- Jérôme Ortais (jerome.ortais@pyromaths.org)
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
import random
from ..outils import Affichage, Arithmetique
#import gettext
#_ = gettext.gettext
#===============================================================================
# Écrire un nombre en lettres ou en chiffres
#===============================================================================
def NombreEnLettres(n, France=True):
unite = {
1: "un",
2: 'deux',
3: 'trois',
4: 'quatre',
5: 'cinq',
6: 'six',
7: 'sept',
8: 'huit',
9: 'neuf',
10: 'dix',
11: 'onze',
12: 'douze',
13: 'treize',
14: 'quatorze',
15: 'quinze',
16: 'seize',
17: 'dix-sept',
18: 'dix-huit',
19: 'dix-neuf',
}
dizaineF = {2: 'vingt', 3: 'trente', 4: 'quarante', 5: 'cinquante',
6: 'soixante', 7: "", 8: 'quatre-vingt', 9: ""}
dizaineB = {2: 'vingt', 3: 'trente', 4: 'quarante', 5: 'cinquante',
6: 'soixante', 7: 'septante', 8: 'octante', 9: 'nonante'}
coefs = {0: 'cent', 1: 'mille', 2: 'million', 3: 'milliard'}
result = ""
# Cas particulier de zéro
if n == 0:
result = u'zéro'
else:
coef = 0
while n > 0:
# Récupération de l'unité du bloc de trois chiffres en cours
u = n % 10
n = n // 10
# Récupération de la dizaine du bloc de trois chiffres en cours
d = n % 10
n = n // 10
# Traitement des dizaines
temp = ""
# Passage sur la dizaine inférieure pour 10 à 19
# et pour 70-79 90-99 dans le cas de la France
if d == 1 or (d == 7 or d == 9) and France:
d = d - 1
u = u + 10
if d > 1:
if France:
if n:
temp = '-' + dizaineF[d]
else:
temp = dizaineF[d]
# Ajout du cas particulier de 'et' entre la dizaine et 1
if d < 8 and (u == 1 or u == 11):
temp = temp + '-et'
else:
if n:
temp = '-' + dizaineB[d]
else:
temp = dizaineB[d]
# Ajout du cas particulier de 'et' entre la dizaine et 1
if u == 1:
temp = temp + '-et'
# ajout du texte de l'unité
if u > 0 and (d or n):
temp = temp + '-' + unite[u]
elif u > 0:
temp = unite[u]
# ajout du 's' à Quatre-vingt si rien ne suit
#if (result == '') and (d == 8) and (u == 0) and France : result = 's'
if d == 8 and u == 0 and France:
temp = temp + 's'
result = temp + result
# Récupération de la centaine du bloc de trois chiffres en cours
c = n % 10
n = n // 10
if c > 0:
temp = ""
if c > 1 and n:
temp = '-' + unite[c]
elif c > 1:
temp = unite[c]
if c == 1 and not n:
temp = coefs[0]
else:
temp = temp + '-' + coefs[0]
# Traitement du cas particulier du 's' à cent si rien ne suit
if result == "" and c > 1:
result = 's'
result = temp + result
# Traitement du prochain groupe de 3 chiffres
if n > 0:
coef = coef + 1
i = n % 1000
if i > 1 and coef > 1:
result = 's' + result
# Traitement du cas particulier 'mille' ( non pas 'un mille' )
if i == 1 and coef == 1:
n = n - 1
result = coefs[coef] + result
elif i > 0:
result = '-' + coefs[coef] + result
return result
def NombreEnLettres_es(n):
unite = {
1: 'uno',
2: 'dos',
3: 'tres',
4: 'cuatro',
5: 'cinco',
6: 'seis',
7: 'siete',
8: 'ocho',
9: 'nueve',
10: 'diez',
11: 'once',
12: 'doce',
13: 'trece',
14: 'catorce',
15: 'quince',
16: u'dieciséis',
17: 'diecisiete',
18: 'dieciocho',
19: 'diecinueve',
20: 'veinte',
21: 'veintiun', #Está bien así, NO CORREGIR
22: u'veintidós',
23: u'veintitrés',
24: 'veinticuatro',
25: 'veinticinco',
26: u'veintiséis',
27: 'veintisiete',
28: 'veintiocho',
29: 'veintinueve',
}
dizaineE = {3: 'treinta', 4: 'cuarenta', 5: 'cincuenta',
6: 'sesenta', 7: 'setenta', 8: 'ochenta', 9: 'noventa'}
coefs = {0: 'cien', 1: 'mil', 2: 'mill', 3:'mil'}
coefc = {0: 'un', 1: 'ciento', 2: 'dosci', 3: 'tresci', 4:'cuatroci', 5:'quini',
6: 'seisci', 7: 'seteci', 8: 'ochoci', 9: 'noveci'}
result = ""
# Cas particulier de zéro
if n == 0:
result = u'cero'
else:
coef = 0
while n > 0:
# Récupération de l'unité du bloc de trois chiffres en cours
u = n % 10
n = n // 10
# Récupération de la dizaine du bloc de trois chiffres en cours
d = n % 10
n = n // 10
# Traitement des dizaines
temp = ""
# Passage sur la dizaine inférieure pour 10 à 19
# et pour 70-79 90-99 dans le cas de la France
if d == 1: # Escribe los nº del 10 al 19 de la tabla
d = d - 1
u = u + 10
if d == 2: # Escribe los nº del 20 al 21 de la tabla
d = d - 1
u = u + 20
if d > 2:
# Ajout du cas particulier de 'et' entre la dizaine et 1
if n: # Escribe el resto del 30 al 99
temp = ' ' + dizaineE[d] # Añade espacio si es > 100
else:
temp = dizaineE[d]
# ajout du texte de l'unité
if u > 0 and d > 2: # Añade "y" de los nº entre 30 a 99
if u == 1 and coef > 0: # Usa "un" en lugar de "uno"
temp = temp + ' y ' + coefc[0]
else:
temp = temp + ' y ' + unite[u]
elif u > 0 and n: # Añade espacio si es > 100
if u == 21 and coef == 0: # Usa "veintiuno" en lugar de "veintiun" si <1000
temp = temp + ' ' + unite[u] + 'o'
elif u == 1 and (coef > 0 and coef < 4): # Usa "un" en lugar de "uno"
if coef == 3:
temp = temp # Usa "mil millones" en lugar de "un mil"
else:
temp = ' ' + coefc[0]
else:
temp = temp + ' ' + unite[u]
elif u == 21 and d == 1 and coef == 0: # Usa "veintiuno" cuando es 21
temp = unite[u] + 'o'
elif u == 1 and d == 0 and coef > 0: # Usa "un" son numeros > 1000
temp = coefc[0]
elif u > 0:
temp = unite[u]
result = temp + result
# Récupération de la centaine du bloc de trois chiffres en cours
c = n % 10
n = n // 10
if c > 0:
temp = ""
if c == 1 and not d and not u: # Usa "cien" en lugar de "un cien"
temp = coefs[0]
elif c == 1: # Usa "ciento" para >100
temp = coefc[1]
else: # Compone los nº > 200
temp = coefc[c] + 'entos'
# Traitement du cas particulier du 's' à cent si rien ne suit
if n > 0 : # Añade espacio si es > 1000
result = ' ' + temp + result
else:
result = temp + result
# Traitement du prochain groupe de 3 chiffres
if n > 0:
coef = coef + 1
i = n % 1000
# Traitement du cas particulier 'mille' ( non pas 'un mille' )
if coef == 1 and i==1: # No añade espacio en "mil"
n = n - 1
if n == 0:
result = coefs[coef] + result
else:
result = ' ' + coefs[coef] + result
elif coef == 2: # Usa "millones" en lugar de "millón"
if i == 1 and n == 1:
result = ' ' + coefs[coef] + u'ón' + result
else:
result = ' ' + coefs[coef] + 'ones' + result
elif i == 1 and coef == 3: # No añade espacio en "mil millones"
result = coefs[coef] + result
elif i > 0:
result = ' ' + coefs[coef] + result
return result
def EcritNombreDecimal(n):
txt = ""
if n != int(n):
#n n'est pas un nombre entier
(e, d) = str(n).split('.')
(e, d) = (int(e), int(d))
else:
(e, d) = (int(n), 0)
if not d:
txt = NombreEnLettres(e)
elif e:
txt = NombreEnLettres(e)
if d:
partieDec = [u" dixième", u" centième", u" millième"]
if txt.rfind("un") == len(txt) - 2:
# le texte se finit par un. On l'accorde en genre avec unité
txt = txt + "e"
if e == 1:
txt = txt + u' unité et '
if e > 1:
txt = txt + u' unités et '
txt = txt + NombreEnLettres(d) + partieDec[len(str(n).split('.')[1]) -
1]
if d > 1:
txt = txt + 's'
return txt
def EcritNombreDecimal_es(n):
txt = ""
if n != int(n):
#n n'est pas un nombre entier
(e, d) = str(n).split('.')
(e, d) = (int(e), int(d))
else:
(e, d) = (int(n), 0)
if not d:
txt = NombreEnLettres_es(e)
elif e:
txt = NombreEnLettres_es(e)
if d:
partieDec = [u" décima", u" centésima", u" milésima"]
if e == 1:
txt = txt + u' unidad con '
if e > 1:
txt = txt + u' unidades con '
txt = txt + NombreEnLettres_es(d) + partieDec[len(str(n).split('.')[1]) -
1]
if d > 1:
txt = txt + 's'
txt = txt.replace("uno", "una") # Cambio a femenino para decimales
txt = txt.replace("un ", "una ") # Cambio a femenino para decimales
txt = txt.replace("tos", "tas") # Cambio a femenino para decimales
return txt
def NombreEnLettres_ca(n):
unite = {1: 'un',2: 'dos',3: 'tres',4: 'quatre',5: 'cinc',6: 'sis',7: 'set',
8: 'huit',9: 'nou',10: 'deu',11: 'onze',12: 'dotze',13: 'tretze',
14: 'catorze',15: 'quinze',16: 'setze',17: u'dèsset',18: 'dihuit',19: u'dènou'}
dizaineE = {2:'vint',3: 'trenta', 4: 'quaranta', 5: 'cinquanta',
6: 'seixanta', 7: 'setanta', 8: 'huitanta', 9: 'noranta'}
suffix_num = {0:[ ['',''] , [u'milió','milions'] , [u'bilió','bilions'] ],1:'mil'}
result = ""
loops = 0
# Cas particulier de zéro
if n == 0:
result = u'zero'
else:
while n > 0 :
c = n % 1000 // 100
d = n % 100 // 10
u = n % 10
n = n // 1000
aux_dec = ( d * 10 ) + u
aux_string = ''
aux_centesima = c*100+d*10+u
if c == 1 :
aux_string = 'cent'
elif c > 1:
aux_string = unite[c] + '-cents'
if aux_dec > 0 :
if aux_dec < 20:
if not (aux_dec == 1 and (loops % 2) == 1):
aux_string += ' ' + unite[aux_dec]
else:
aux_string += ' ' + dizaineE[d]
if u != 0:
if d == 2:
aux_string += '-i'
aux_string += '-' + unite[u]
if aux_centesima != 0:
if ( loops % 2 ) == 0:
if aux_centesima > 1:
aux_string += ' ' + suffix_num[0][loops//2][1]
else:
aux_string += ' ' + suffix_num[0][loops//2][0]
else:
aux_string += ' ' + suffix_num[1]
result = aux_string.strip() + ' ' + result
loops += 1
return result
def EcritNombreDecimal_ca(n):
txt = ""
if n != int(n):
#n n'est pas un nombre entier
(e, d) = str(n).split('.')
(e, d) = (int(e), int(d))
else:
(e, d) = (int(n), 0)
if not d:
txt = NombreEnLettres_ca(e)
elif e:
txt = NombreEnLettres_ca(e)
if d:
partieDec = [u"dècima", u"centèsima", u"mil·lèsima"]
if e == 1:
txt = txt + u'unitat amb '
if e > 1:
txt = txt + u'unitats amb '
txt = txt + NombreEnLettres_ca(d) + partieDec[len(str(n).split('.')[1]) - 1]
if d > 1:
txt = txt[:len(txt)-1] + 'es'
#txt = txt.replace("un", "una") # Cambio a femenino para decimales
txt = txt.replace("-un ", "-una ") # Cambio a femenino para decimales
txt = txt.replace("un ", "una ") # Cambio a femenino para decimales
txt = txt.replace("cents", "centes") # Cambio a femenino para decimales
return txt
def nombreATrouver():
"""a contient la liste des nombres à créer où il peut ne pas y avoir de
centaines, de centaines de milliers, d'unités ou de milliers"""
a = [random.randrange(100) + random.randrange(1000) * 10 ** 3,
random.randrange(1000) + random.randrange(100) * 10 ** 3,
random.randrange(1000) * 10 ** 3, random.randrange(1000)]
(lnb, list) = ([], [])
for i in range(4):
lnb.append(random.randrange(1, 1000) * 10 ** 6 + a[i])
for i in range(4):
n = a[i]
if n % 1000: # il y a des unités dans le nombre
e = random.randrange(1, 4)
lnb.append(n * 10 ** (-e))
else:
e = random.randrange(4, 7)
lnb.append(n * 10 ** (-e))
for i in range(8):
list.append(lnb.pop(random.randrange(len(lnb))))
return list
def EcritEnChiffre(exo, cor, lang = ""):
lnb = nombreATrouver()
quiz_txt = ""
for i in range(len(lnb)):
exo.append("\\item " + eval('EcritNombreDecimal'+lang+'(lnb[i])') +
_(" : \\dotfill"))
cor.append("\\item " + eval('EcritNombreDecimal'+lang+'(lnb[i])') +
" : ")
cor.append(Affichage.decimaux(lnb[i], 0) + '')
## Cambia a NUMERICAL cuando el bug de quiz se solucione, también el ,0 a ,1
quiz_txt += (u"$$%s) \\;$$"%(i+1) + eval('EcritNombreDecimal'+lang+'(lnb[i])'))
quiz_txt += u" {1:SHORTANSWER:%s100%s%s}
\n" %("%", "%", Affichage.decimaux_quiz(lnb[i],0))
return quiz_txt[0:(len(quiz_txt)-1)]
def EcritEnLettre(exo, cor, lang = ""):
lnb = nombreATrouver()
quiz_txt = ""
for i in range(8):
exo.append("\\item " + Affichage.decimaux(lnb[i], 0) +
_(" : \\dotfill"))
cor.append("\\item " + Affichage.decimaux(lnb[i], 0) +
" : ")
cor.append(eval('EcritNombreDecimal'+lang+'(lnb[i])') + '')
quiz_txt += (u"$$%s) \\; "%(i+1) + Affichage.decimaux_quiz(lnb[i]) + " $$")
quiz_txt += u" {1:SHORTANSWER:%s100%s%s}
\n" %("%", "%", eval('EcritNombreDecimal'+lang+'(lnb[i])'))
return quiz_txt[0:(len(quiz_txt)-1)]
def EcrireNombreLettre(langue):
if langue == "fr" or langue == "":
lang = ""
else:
lang = "_" + langue
try:
eval('EcritNombreDecimal'+lang+'(1)')
except NameError:
lang = ""
exo = ["\\exercice", "\\begin{enumerate}",
_(u'\\item Écrire en chiffres les nombres suivants.'),
'\\begin{enumerate}']
cor = ["\\exercice*", "\\begin{enumerate}",
_(u'\\item Écrire en chiffres les nombres suivants.'),
'\\begin{enumerate}']
quiz_EnChiffre = [u"cloze"]
quiz_nom = _(u"Nom d'un décimale: Engage")
quiz_exo_cor = _(u"Écrit en chiffres les suivants numéros.
\n")
quiz_exo_cor += EcritEnChiffre(exo, cor, lang)
quiz_EnChiffre.append([quiz_nom, quiz_exo_cor, ""])
exo.append('\\end{enumerate}')
exo.append(_(u'\\item Écrire en lettres les nombres suivants (sans utiliser le mot ``virgule").'))
exo.append('\\begin{enumerate}')
cor.append('\\end{enumerate}')
cor.append(_(u'\\item Écrire en lettres les nombres suivants (sans utiliser le mot ``virgule").'))
cor.append('\\begin{enumerate}')
quiz_EnLettre = [u"cloze"]
quiz_nom = _(u"Nom d'un décimale: Lecture")
quiz_exo_cor = _(u'Écrit avec le paroles les suivants numéros, (sans utiliser la parole \" virgule\").
\n')
quiz_exo_cor += EcritEnLettre(exo, cor, lang)
quiz_EnLettre.append([quiz_nom, quiz_exo_cor, ""])
exo.append('\\end{enumerate}')
exo.append('\\end{enumerate}')
cor.append('\\end{enumerate}')
cor.append('\\end{enumerate}')
return (exo, cor, [quiz_EnChiffre, quiz_EnLettre])
#===============================================================================
# Conversions
#===============================================================================
units = [_(u"L"), _(u"m"), _(u"g")]
division = [_(u"k"), _(u"h"), _(u"da"), "", _(u"d"), _(u"c"), _(u"m")]
#paramétrage des flèches : mofifie le paramétrage par défaut de PSTricks s'il n'est pas limité par un environnement ou {groupe}
## nodesepA = -1.5mm : décale le départ de la flèche
## linewidth = 0.6pt : épaisseur de la flèches
## linestyle = dotted : style pointillé
## vref = -0.8mm : décale la flèche vers le bas, sous les chiffres
PSSET_FLECHE = '\\psset{nodesepA = -1.5mm, linewidth = 0.6pt, linestyle = dotted, vref = -0.8mm}'
def Conversions(n):
if n == 1:#Conversions de L, m ou g
#le module sixiemes.sixiemes va appeler Conversions(1)()
return tex_units
#exo_conversion(exo, cor, 1) #le choix des valeurs prises, l'absence de grammes et litres ne rendent pas cette rédaction pertinente
else: #conversions de m² ou m³
return exo_conversion(n)
def valeurs_units():
"""
renvoie les valeurs pour les conversions d'unités
"""
a = Arithmetique.valeur_alea(101, 999)
p = random.randrange(-2, 0)
unit = random.randrange(3)
if unit:
#mètres ou grammes, on peut utiliser les k
imax = 7
else:
#Litres, donc pas de kL
imax = 6
div0 = random.randrange(imax + p)
while 1:
div1 = random.randrange(imax)
if div0 != div1:
break
if not unit: #Litres, donc pas de kL donc on décale d'un rang
div0, div1 = div0 + 1, div1 + 1
return (a, p, unit, div0, div1)
#101< a <999 ex a = 245
#p = {-2,-1} donne 2,45 ou 24,5
#unit = {0, 1, 2} => {L, m, g}
#div0 unité 0
#div1 unité converti
def tex_units():
"""
Écrit l'exercice sur les conversions d'unités et le corrigé au format
LaTeX
@param exo: fichier exercices
@param cor: fichier corrige
@param quiz: fichier quiz
"""
exo = ["\\exercice", _(u'Effectuer les conversions suivantes :'),
'\\begin{multicols}{3}\\noindent', '\\begin{enumerate}']
cor = ["\\exercice*",
#paramétrage des flèches, ce paramétrage est limité à l'exercice
# et ne modifie pas le paramétrage PSTricks du document car sa portée est limité par le groupe ouvert par "{"
"{",
PSSET_FLECHE,
_(u'Effectuer les conversions suivantes :'),
'\\begin{multicols}{2}\\noindent', '\\begin{enumerate}']
quiz = [u"cloze"]
quiz_nom = _(u"Conversion d\'unités")
quiz_exo_cor = _(u'Réalise les suivantes conversions :
\n')
quiz_exo_cor += u'
\n'
#Construit les 6 questions de l'exercice
for j in range(6):
(a, p, unit, div0, div1) = valeurs_units()
if unit:
u = tuple([units[unit] for i in range(7)])
else:
u = tuple([units[unit] for i in range(6)])
nb0 = Affichage.decimaux(a * 10 ** p, 0)
nb1 = Affichage.decimaux(a * 10 ** ((p + div1) - div0),
0)
nb2 = Affichage.decimaux_quiz(a * 10 ** p)
nb3 = Affichage.decimaux_quiz(a * 10 ** ((p + div1) - div0),1)
exo.append(_("\\item %s~%s%s=\dotfill~%s%s") % (nb0, division[div0],
units[unit], division[div1], units[unit]))
cor.append("\\item %s~%s%s=%s~%s%s\\par" % (nb0, division[div0],
units[unit], nb1, division[div1], units[unit]))
quiz_exo_cor += (u"$$%s) \\; %s\\quad~%s%s=$$" % (j+1, nb2, division[div0], units[unit]))
## Cambia a NUMERICAL cuando el bug de quiz se solucione, también el ,0 a ,1
quiz_exo_cor += (u" {1:SHORTANSWER:%s100%s%s} $$%s~%s$$ \n" % ("%", "%", Affichage.decimaux_quiz(nb3,0), division[div1], units[unit])) if (j+1) == 3: quiz_exo_cor += u" | \n" nblist = [nb0[i] for i in range(len(nb0))] if nblist.count(','): chf_unite = nblist.index(',') - 1 nblist.pop(chf_unite + 1) else: chf_unite = len(nblist) - 1 tex_tableau(cor, div0, div1, u, nblist, chf_unite) cor.append("\\end{tabular}") cor.append("\\ncline{->}{virg0}{virg1}") quiz_exo_cor += u" |
\n' #ajoute le ² ou ³ si nécessaire str_exposant=(u"^%s"%(exposant))*(exposant > 1) u = tuple([division[i]+"m%s"%str_exposant for i in range(7)]) entete_tableau = ((" \\multicolumn{%s}{c|}"%exposant +"{$\\rm %s$} &")*6 +"\\multicolumn{%s}{c}"%exposant+"{$\\rm %s$}" )%u ligne_tab = [] for i in range(6): #imprime la correction et sauvegarde la ligne et la flèche pour le tableau imprimé ensuite texte = tex_conversion(exo, cor, quiz, exposant, u) ligne_tab += texte[0] + ["\\ncline{->}{virg0}{virg1} \\\\"] quiz_exo_cor += (u"$$%s) \\; "%(i+1) + texte[1]) if (i+1) == 3: quiz_exo_cor += u" | \n" quiz_exo_cor += u" |
\n' for i in range(6): (nombre, puissance) = valeurs_frac() quiz_txt += u"$$%s) \\;"%(i+1) + choix_trou_frac(exo, cor, nombre, puissance) if (i+1) == 3: quiz_txt += u" | \n" quiz_txt += u" |
\n'
for i in range(6):
txt = '\\item $'
(chiffres, puissances) = valeurs_dec()
(v,p) = (chiffres, puissances)
txt_exo, txt_cor, txt_quiz = tex_decomposition(chiffres, puissances)
exo.append(txt + txt_exo)
cor.append(txt + txt_cor)
#quiz.append([u'Decimal de la decomposición',
# u'Halla el número decimal resultante de:\n$$' + txt_quiz,
# Affichage.decimaux_quiz(v[0] * 10 ** p[0] +
# v[1] * 10 ** p[1] + v[2] * 10 ** p[2],1)])
quiz_txt += u"$$%s) \\; "%(i+1) + txt_quiz + " \n" ## Cambia a NUMERICAL cuando el bug de quiz se solucione, también el ,0 a ,1 quiz_txt += (_(u"Réponse: ")+"{1:SHORTANSWER:%s100%s%s} \n" % ("%", "%", Affichage.decimaux_quiz(v[0] * 10 ** p[0] + v[1] * 10 ** p[1] + v[2] * 10 ** p[2],0))) if (i+1) == 3: quiz_txt += u" | \n" quiz_txt += u" |