/* globals UI */
import { texteParPosition } from './2d.js'
import { fraction } from './fractions.js'
import Algebrite from 'algebrite'
import { equal, evaluate, format, Fraction, gcd, isInteger, isPrime, matrix, parse, round } from 'mathjs'
import { loadScratchblocks } from './loaders.js'
import { context } from './context.js'
import { setReponse } from './gestionInteractif.js'
import { getVueFromUrl } from './gestionUrl.js'
import FractionX from './FractionEtendue.js'
import Decimal from 'decimal.js'
export const tropDeChiffres = 'Trop de chiffres'
export const epsilon = 0.000001
const math = { format, evaluate }
/**
* Fonctions diverses pour la création des exercices
* @module
*/
export function interactivite (exercice) {
if (context.isHtml) {
if (exercice.interactif) return 'I-html'
else return 'html'
} else if (context.isAmc) return 'AMC'
else if (exercice.interactif) return 'I-latex'
else return 'latex'
}
/**
* Affecte les propriétés contenu et contenuCorrection (d'après les autres propriétés de l'exercice)
* @param {Exercice} exercice
*/
export function listeQuestionsToContenu (exercice) {
if (context.isHtml) {
exercice.contenu = htmlConsigne(exercice.consigne) + htmlParagraphe(exercice.introduction) + htmlEnumerate(exercice.listeQuestions, exercice.spacing, 'question', `exercice${exercice.numeroExercice}Q`, exercice.tailleDiaporama)
if ((exercice.interactif && exercice.interactifReady) || getVueFromUrl() === 'eval') {
exercice.contenu += `<button class="ui blue button checkReponses" type="submit" style="margin-bottom: 20px; margin-top: 20px" id="btnValidationEx${exercice.numeroExercice}-${exercice.id}">Vérifier les réponses</button>`
}
exercice.contenuCorrection = htmlParagraphe(exercice.consigneCorrection) + htmlEnumerate(exercice.listeCorrections, exercice.spacingCorr, 'correction', `correction${exercice.numeroExercice}Q`, exercice.tailleDiaporama)
} else {
let vspace = ''
if (exercice.vspace) {
vspace = `\\vspace{${exercice.vspace} cm}\n`
}
if (!context.isAmc) {
if (document.getElementById('supprimer_reference').checked === true) {
exercice.contenu = texConsigne(exercice.consigne) + vspace + texIntroduction(exercice.introduction) + texMulticols(texEnumerate(exercice.listeQuestions, exercice.spacing), exercice.nbCols)
} else {
exercice.contenu = texConsigne(exercice.consigne) + `\n\\marginpar{\\footnotesize ${exercice.id}}` + vspace + texIntroduction(exercice.introduction) + texMulticols(texEnumerate(exercice.listeQuestions, exercice.spacing), exercice.nbCols)
}
}
exercice.contenuCorrection = texConsigne('') + texIntroduction(exercice.consigneCorrection) + texMulticols(texEnumerate(exercice.listeCorrections, exercice.spacingCorr), exercice.nbColsCorr)
exercice.contenuCorrection = exercice.contenuCorrection.replace(/\\\\\n*/g, '\\\\\n')
exercice.contenu = exercice.contenu.replace(/\\\\\n*/g, '\\\\\n')
}
}
export function exerciceSimpleToContenu (exercice) {
const listeQuestions = []
const listeCorrections = []
for (let i = 0, cpt = 0; i < exercice.nbQuestions & cpt < 50; cpt++) {
if (exercice.questionJamaisPosee(i, exercice.question)) {
if (context.isAmc) {
listeQuestions.push(exercice.question + '<br>')
listeCorrections.push(exercice.correction)
} else {
listeQuestions.push(exercice.question)
listeCorrections.push(exercice.correction)
}
if (context.isAmc && exercice.amcType === 'AMCNum') {
setReponse(exercice, i, exercice.reponse, {
digits: nombreDeChiffresDe(exercice.reponse),
decimals: nombreDeChiffresDansLaPartieDecimale(exercice.reponse),
signe: exercice.reponse < 0,
approx: 0
})
}
exercice.nouvelleVersion()
i++
}
}
exercice.listeQuestions = listeQuestions
exercice.listeCorrections = listeCorrections
listeQuestionsToContenu(exercice)
}
/**
* À documenter
* @param {Exercice} exercice
*/
export function listeDeChosesAImprimer (exercice) {
if (context.isHtml) {
exercice.contenu = htmlLigne(exercice.listeQuestions, exercice.spacing)
exercice.contenuCorrection = ''
} else {
// let vspace = ''
// if (exercice.vspace) {
// vspace = `\\vspace{${exercice.vspace} cm}\n`
// }
if (document.getElementById('supprimer_reference').checked === true) {
exercice.contenu = texMulticols(texParagraphe(exercice.listeQuestions, exercice.spacing), exercice.nbCols)
} else {
exercice.contenu = `\n\\marginpar{\\footnotesize ${exercice.id}}` + texMulticols(texParagraphe(exercice.listeQuestions, exercice.spacing), exercice.nbCols)
}
exercice.contenuCorrection = ''
}
}
/**
* Utilise liste_questions et liste_corrections pour remplir contenu et contenuCorrection
* La liste des questions devient une liste HTML ou LaTeX avec html_ligne() ou tex_paragraphe()
* @param {Exercice} exercice
* @author Rémi Angot
*/
export function listeQuestionsToContenuSansNumero (exercice, retourCharriot = true) {
// En vue diapCorr, les questions doivent toujours être numérotées car venant d'exercices différents
if (context.vue === 'diapCorr') {
listeQuestionsToContenu(exercice, retourCharriot = true)
} else {
if (context.isHtml) {
exercice.contenu = htmlConsigne(exercice.consigne) + htmlParagraphe(exercice.introduction) + htmlEnumerate(exercice.listeQuestions, exercice.spacing, 'question', `exercice${exercice.numeroExercice}Q`, exercice.tailleDiaporama, 'sansNumero')
if ((exercice.interactif && exercice.interactifReady) || getVueFromUrl() === 'eval') {
exercice.contenu += `<button class="ui blue button checkReponses" type="submit" style="margin-bottom: 20px; margin-top: 20px" id="btnValidationEx${exercice.numeroExercice}-${exercice.id}">Vérifier les réponses</button>`
}
exercice.contenuCorrection = htmlParagraphe(exercice.consigneCorrection) + htmlEnumerate(exercice.listeCorrections, exercice.spacingCorr, 'correction', `correction${exercice.numeroExercice}Q`, exercice.tailleDiaporama, 'sansNumero')
} else {
if (document.getElementById('supprimer_reference').checked === true) {
exercice.contenu = texConsigne(exercice.consigne) + texIntroduction(exercice.introduction) + texMulticols(texParagraphe(exercice.listeQuestions, exercice.spacing, retourCharriot), exercice.nbCols)
} else {
exercice.contenu = texConsigne(exercice.consigne) + `\n\\marginpar{\\footnotesize ${exercice.id}}` + texIntroduction(exercice.introduction) + texMulticols(texParagraphe(exercice.listeQuestions, exercice.spacing, retourCharriot), exercice.nbCols)
}
// exercice.contenuCorrection = texConsigne(exercice.consigneCorrection) + texMulticols(texEnumerateSansNumero(exercice.listeCorrections,exercice.spacingCorr),exercice.nbColsCorr)
exercice.contenuCorrection = texConsigne(exercice.consigneCorrection) + texMulticols(texParagraphe(exercice.listeCorrections, exercice.spacingCorr, retourCharriot), exercice.nbColsCorr)
}
}
}
/**
* Utilise liste_questions et liste_corrections pour remplir contenu et contenuCorrection
*
* Uniquement en version LaTeX
* La liste des questions devient une liste HTML ou LaTeX avec html_ligne() ou tex_paragraphe()
* @param {Exercice} exercice
* @author Rémi Angot
*/
export function listeQuestionsToContenuSansNumeroEtSansConsigne (exercice) {
if (document.getElementById('supprimer_reference').checked === true) {
exercice.contenu = texMulticols(texParagraphe(exercice.listeQuestions, exercice.spacing), exercice.nbCols)
} else {
exercice.contenu = `\n\\marginpar{\\footnotesize ${exercice.id}` + texMulticols(texParagraphe(exercice.listeQuestions, exercice.spacing), exercice.nbCols)
}
// exercice.contenuCorrection = texConsigne(exercice.consigneCorrection) + texMulticols(texEnumerateSansNumero(exercice.listeCorrections,exercice.spacingCorr),exercice.nbColsCorr)
exercice.contenuCorrection = texMulticols(texParagraphe(exercice.listeCorrections, exercice.spacingCorr), exercice.nbColsCorr)
}
/**
* Renvoie le html ou le latex qui mets les 2 chaines de caractères fournies sur 2 colonnes différentes
* @author Rémi Angot
* @param {string} cont1 - Contenu de la première colonne
* @param {string} cont2 - Contenu de la deuxième colonne
* @param {number} [largeur1=50] Largeur de la première colonne
* @return {string}
*/
export function deuxColonnes (cont1, cont2, largeur1 = 50) {
if (context.isHtml) {
return `
<div>
<div class="question" style="float:left;max-width: ${largeur1}%;margin-right: 30px">
${cont1}
</div>
<div style="float:left; max-width: ${90 - largeur1}%">
${cont2}
</div>
<div style="clear:both"></div>
<div class="ui hidden divider"></div>
</div>
`
} else {
return `\\begin{minipage}{${largeur1 / 100}\\linewidth}
${cont1.replaceAll('<br>', '\\\\\n')}
\\end{minipage}
\\begin{minipage}{${(100 - largeur1) / 100}\\linewidth}
${cont2.replaceAll('<br>', '\\\\\n')}
\\end{minipage}
`
}
}
/**
* Renvoie le html ou le latex qui mets les 2 chaines de caractères fournies sur 2 colonnes différentes
* Si en sortie html, il n'y a pas assez de places alors on passe en momocolonne!
* @author Mickael Guironnet
* @param {string} cont1 - Contenu de la première colonne
* @param {string} cont2 - Contenu de la deuxième colonne
* @param {{eleId: string, largeur1: number, widthmincol1: number, widthmincol2: number}} options
* eleId : identifiant ID pour retrouver la colonne
* largeur1 : largeur de la première colonne en latex en pourcentage
* widthmincol1 : largeur de la première minimum en html en px
* widthmincol2 : largeur de la deuxième minimum en html en px
* ex : deuxColonnesResp (enonce, correction, {eleId : '1_1', largeur1:50, widthmincol1: 400px, widthmincol2: 200px})
* @return {string}
*/
export function deuxColonnesResp (cont1, cont2, options) {
if (options === undefined) {
options = { largeur1: 50 }
} else if (typeof options === 'number') {
options = { largeur1: options }
}
if (options.largeur1 === undefined) {
options.largeur1 = 50
}
if (options.stylecol1 === undefined) {
options.stylecol1 = ''
}
if (options.stylecol2 === undefined) {
options.stylecol2 = ''
}
if (options.widthmincol1 === undefined) {
options.widthmincol1 = '0px'
}
if (options.widthmincol2 === undefined) {
options.widthmincol2 = '0px'
}
if (context.isHtml) {
return `
<style>
.cols-responsive {
max-width: 1200px;
margin: 0 auto;
display: grid;
grid-gap: 1rem;
}
/* Screen larger than 900px? 2 column */
@media (min-width: 900px) {
.cols-responsive { grid-template-columns: repeat(2, 1fr); }
}
</style>
<div class='cols-responsive'>
<div id='cols-responsive1-${options.eleId}'style='min-width:${options.widthmincol1};${options.stylecol1}' >
${cont1}
</div>
<div id='cols-responsive2-${options.eleId}' style='min-width:${options.widthmincol2};${options.stylecol2}' >
${cont2}
</div>
</div>
`
} else {
return `\\begin{minipage}{${options.largeur1 / 100}\\linewidth}
${cont1.replaceAll('<br>', '\\\\\n')}
\\end{minipage}
\\begin{minipage}{${(100 - options.largeur1) / 100}\\linewidth}
${cont2.replaceAll('<br>', '\\\\\n')}
\\end{minipage}
`
}
}
/**
*
* @param {string} texte
* @returns le texte centré dans la page selon le contexte.
* @author Jean-Claude Lhote
*/
export function centrage (texte) {
return context.isHtml ? `<center>${texte}</center>` : `\\begin{center}\n\t${texte}\n\\end{center}\n`
}
/**
* Contraint une valeur à rester dans un intervalle donné. Si elle est trop petite, elle prend la valeur min, si elle est trop grande elle prend la valeur max
* @author Jean-Claude Lhote à partir du code de Eric Elter
* @param {number} min borne inférieure
* @param {number} max borne supérieure
* @param {number} valeur la valeur à contraindre
* @param {number} defaut valeur par défaut si non entier
*/
export function contraindreValeur (min, max, valeur, defaut) {
return !(Number.isNaN(valeur)) ? (Number(valeur) < min) ? min : (Number(valeur) > max) ? max : Number(valeur) : defaut
}
/** Retourne un nombre décimal entre a et b, sans être trop près de a et de b
* @param {number} min borne inférieure
* @param {number} max borne supérieure
* @author Eric Elter
* @returns {number}
*/
export function entreDeux (a, b) {
if (a < b) return arrondi(a + (b - a) * randint(10, 90) / 100, 2)
else return arrondi(b + (a - b) * randint(10, 90) / 100, 2)
}
/**
* Compare deux nombres (pour les nombres en virgule flottante afin d'éviter les effets de la conversion en virgule flottante).
* @author Jean-Claude Lhote
* @param {number} a premier nombre
* @param {number} b deuxième nombre
* @param {number} [tolerance=0.000001] seuil positif en dessous duquel une valeur est considérée comme nulle
* @return {boolean}
*/
export function egal (a, b, tolerance = epsilon) {
return (Math.abs(a - b) < tolerance)
}
/**
* Retourne true si a > b
* @param {number} a premier nombre
* @param {number} b deuxième nombre
* @param {number} [tolerance=0.000001] seuil positif en dessous duquel une valeur est considérée comme nulle
* @return {boolean}
*/
export function superieur (a, b, tolerance = epsilon) {
return (a - b > tolerance)
}
/**
* Retourne true si a < b
* @param {number} a premier nombre
* @param {number} b deuxième nombre
* @param {number} [tolerance=0.000001] seuil positif en dessous duquel une valeur est considérée comme nulle
* @return {boolean}
*/
export function inferieur (a, b, tolerance = epsilon) {
return (b - a > tolerance)
}
/**
* Retourne true si a ≥ b
* @param {number} a premier nombre
* @param {number} b deuxième nombre
* @param {number} [tolerance=0.000001] seuil positif en dessous duquel une valeur est considérée comme nulle
* @return {boolean}
*/
export function superieurouegal (a, b, tolerance = epsilon) {
return (a - b > tolerance || egal(a, b, tolerance))
}
/**
* Retourne true si a ≤ b
* @param {number} a premier nombre
* @param {number} b deuxième nombre
* @param {number} [tolerance=0.000001] seuil positif en dessous duquel une valeur est considérée comme nulle
* @return {boolean}
*/
export function inferieurouegal (a, b, tolerance = epsilon) {
return (b - a > tolerance || egal(a, b, tolerance))
}
/**
* Retourne true si a est entier ou "presque" entier
* @param {number} a premier nombre
* @param {number} [tolerance=0.000001] seuil positif en dessous duquel une valeur est considérée comme nulle
* @return {boolean}
*/
export function estentier (a, tolerance = epsilon) {
return (Math.abs(a - round(a)) < tolerance)
}
/**
* Retourne le quotient entier (donc sans le reste) de a/b si a & b sont entiers, false sinon
* @param {number} a
* @param {number} b
* @return {boolean|number}
*/
export function quotientier (a, b) {
if (estentier(a) && estentier(b)) return Math.floor(a / b)
return false
}
/**
* Renvoie le PPCM de deux nombres
* @author Rémi Angot
*/
export const ppcm = (a, b) => {
return parseInt(Algebrite.run(`lcm(${a},${b})`))
}
/**
* Retourne true si x est un carré parfait (à epsilon près)
* @param {number} x
* @return {boolean}
*/
export function carreParfait (x) {
if (estentier(Math.sqrt(x))) return true
else return false
}
// Petite fonction pour écrire des nombres avec Mathalea2d en vue de poser des opérations...
export function ecrireNombre2D (x, y, n) {
const nString = nombreAvecEspace(n)
const nombre2D = []
for (let k = 0; k < nString.length; k++) {
nombre2D.push(texteParPosition(nString[k], x + k * 0.8, y))
}
return nombre2D
}
/**
* Créé tous les couples possibles avec un élément de E1 et un élément de E2.
* L'ordre est pris en compte, donc on pourra avoir (3,4) et (4,3).
* Si le nombre de couples possibles est inférieur à nombreDeCouplesMin alors
* on concatène 2 fois la même liste mais avec des ordres différents.
* @param {string[]} E1 - Liste
* @param {string[]} E2 - Liste
* @param {int} nombreDeCouplesMin=10 - Nombre de couples souhaités
* @author Rémi Angot
*/
export function creerCouples (E1, E2, nombreDeCouplesMin = 10) {
let result = []; let temp = []
for (const i in E1) {
for (const j in E2) {
result.push([E1[i], E2[j]])
}
}
temp = shuffle(result).slice(0) // créer un clone du tableau result mélangé
result = temp.slice(0)
while (result.length < nombreDeCouplesMin) {
result = result.concat(shuffle(temp))
}
return result
}
// Fonctions mathématiques
/**
* Choisit un nombre au hasard entre min et max sans appartenir à liste\_a\_eviter.
* @param {int} min
* @param {int} max
* @param {int[]} liste - Tous les éléments que l'on souhaite supprimer
* @return {int} Nombre au hasard entre min et max non compris dans la listeAEviter
*
* @example
* // Renvoie 1, 2 ou 3
* randint (1,3)
* @example
* // Renvoie -1 ou 1
* randint(-1,1,[0])
* @example
* Renvoie 0 ou 1 ou 4 ou 6 ou 8 ou 9
* randint(0,9, '2357') // même résultat avec randint(0,9, ['2','3','5','7']) ou randint(0,9, [2,3,5,7])
* @author Rémi Angot
* @Source https://gist.github.com/pc035860/6546661
*/
export function randint (min, max, listeAEviter = []) {
// Source : https://gist.github.com/pc035860/6546661
if (!Number.isInteger(min) || !Number.isInteger(max)) {
window.notify('Les min et max de randint doivent être entiers', { min, max })
min = Math.floor(min)
max = Math.ceil(max)
if (max - min < 1) max = min + 1
}
const range = max - min
let rand = Math.floor(Math.random() * (range + 1))
if (typeof listeAEviter === 'string') {
listeAEviter = listeAEviter.split('')
}
if (typeof listeAEviter === 'number') {
if (Number.isInteger(listeAEviter)) {
listeAEviter = [listeAEviter]
} else {
window.notify('Le nombre fourni à randint en exclusion n\'est pas un entier', { listeAEviter })
listeAEviter = [listeAEviter] // ce n'est pas grave de mettre un nombre non entier, randint ne choisit que des entiers
}
}
if (Array.isArray(listeAEviter)) {
listeAEviter = listeAEviter.map(Number).filter(el => Math.round(el) === el) // on filtre les non nombres et les non-entiers
} else {
window.notify('La liste d\'exclusion de randint n\'est pas d\'un type pris en compte', { listeAEviter })
listeAEviter = []
}
if (listeAEviter.length > 0) {
while (listeAEviter.includes(min + rand)) {
rand = Math.floor(Math.random() * (range + 1))
}
}
return min + rand
}
/**
* Créé un string aléatoire
*
* strRandom({
* includeUpperCase: true,
* includeNumbers: true,
* length: 5,
* startsWithLowerCase: true
* });
*
* // renvoie par exemple : "iL0v3"
*
* @Source https://www.equinode.com/blog/article/generer-une-chaine-de-caracteres-aleatoire-avec-javascript
*/
export function strRandom (o) {
let a = 10
const b = 'abcdefghijklmnopqrstuvwxyz'
let c = ''
let d = 0
let e = '' + b
if (o) {
if (o.startsWithLowerCase) {
c = b[Math.floor(Math.random() * b.length)]
d = 1
}
if (o.length) {
a = o.length
}
if (o.includeUpperCase) {
e += b.toUpperCase()
}
if (o.includeNumbers) {
e += '1234567890'
}
}
for (; d < a; d++) {
c += e[Math.floor(Math.random() * e.length)]
}
return c
}
/**
* Enlève toutes les occurences d'un élément d'un tableau donné
* @param liste
* @param element
*
* @author Rémi Angot
*/
export function enleveElement (array, item) {
//
for (let i = array.length - 1; i >= 0; i--) {
if (typeof item === 'number') {
if (egal(array[i], item)) {
array.splice(i, 1)
}
} else {
if (array[i] === item) {
array.splice(i, 1)
}
}
}
}
/**
*
* Compte les occurences d'un item dans un tableau
* @param {array} array
* @param item
* @Author Rémi Angot
*/
export function compteOccurences (array, value) {
let cpt = 0
array.forEach((v) => (v === value && cpt++))
return cpt
}
/**
* Enlève toutes les occurences d'un élément d'un tableau donné mais sans modifier le tableau en paramètre et renvoie le tableau modifié
* @author Rémi Angot & Jean-Claude Lhote
*/
export function enleveElementBis (array, item = undefined) {
const tableaucopie = []
for (let i = 0; i < array.length; i++) {
tableaucopie.push(array[i])
}
for (let i = tableaucopie.length - 1; i >= 0; i--) {
if (tableaucopie[i] === item) {
tableaucopie.splice(i, 1)
}
}
return tableaucopie
}
/**
* Enlève l'élément index d'un tableau
* @author Jean-Claude Lhote
*/
export function enleveElementNo (array, index) {
array.splice(index, 1)
}
/**
* Enlève l'élément index d'un tableau sans modifier le tableau et retourne le résultat
* @author Jean-Claude Lhote
*/
export function enleveElementNoBis (array, index) {
const tableaucopie = []
for (let i = 0; i < array.length; i++) {
tableaucopie.push(array[i])
}
tableaucopie.splice(index, 1)
return tableaucopie
}
/**
* Retourne un élément au hasard de la liste sans appartenir à une liste donnée
* @param {liste}
* @param {listeAEviter}
*
* @example
* // Renvoie 1, 2 ou 3
* choice([1,2,3])
* @example
* // Renvoie Rémi ou Léa
* choice(['Rémi','Léa'])
*
* @author Rémi Angot
*/
export function choice (liste, listeAEviter = []) {
// copie la liste pour ne pas y toucher (ce n'est pas le but de choice)
if (!Array.isArray(listeAEviter)) {
listeAEviter = [listeAEviter]
}
const listebis = liste.slice()
// Supprime les éléments de liste à éviter
for (let i = 0; i < listeAEviter.length; i++) {
enleveElement(listebis, listeAEviter[i])
}
const index = Math.floor(Math.random() * listebis.length)
return listebis[index]
}
/**
* Retourne une liste des entiers de 0 à max sans appartenir à une liste donnée
* @param {max}
* @param {listeAEviter}
*
* @example
* // Renvoie [0,1,4,5,6,7,8,9,10]
* range(10,[2,3])
*
* @author Rémi Angot
*/
export function range (max, listeAEviter = []) {
// Créer un tableau avec toutes les valeurs de 0 à max sauf celle de la liste à éviter
const nbMax = parseInt(max, 10)
const liste = [...Array(nbMax + 1).keys()]
for (let i = 0; i < listeAEviter.length; i++) {
enleveElement(liste, listeAEviter[i])
}
return liste
}
/**
* Retourne une liste entre 2 bornes sans appartenir à une liste donnée (par défaut des entiers mais on peut changer le pas)
* @param {min}
* @param {max}
* @param {listeAEviter}
*
* @example
* // Renvoie [6,7,10]
* range(6,10,[8,9])
*
* @author Rémi Angot
*/
export function rangeMinMax (min, max, listeAEviter = [], step = 1) {
// Créer un tableau avec toutes les valeurs de 0 à max sauf celle de la liste à éviter
const liste = []
for (let i = min; i <= max; i = i + step) {
liste.push(i)
}
for (let i = 0; i < listeAEviter.length; i++) {
enleveElement(liste, listeAEviter[i])
}
return liste
}
/**
* Créé un tableau avec toutes les valeurs de 1 à max sauf celle de la liste à éviter
*
*
* @param {int} max
* @param {liste} liste valeurs à éviter
* @author Rémi Angot
*/
export function range1 (max, listeAEviter = []) {
const nbMax = parseInt(max, 10)
const liste = []
for (let i = 1; i <= nbMax; i++) {
liste.push(i)
}
for (let i = 0; i < listeAEviter.length; i++) {
enleveElement(liste, listeAEviter[i])
}
return liste
}
/**
* Fonction de comparaison à utiliser avec tableau.sort(compareFractions)
*
* Le tableau doit être du type `[[num,den],[num2,den2]]`
*
* @author Rémi Angot
*/
export function compareFractions (a, b) {
if ((a[0] / a[1]) > (b[0] / b[1])) { return 1 }
if ((a[0] / a[1]) < (b[0] / b[1])) { return -1 }
// Sinon il y a égalité
return 0
}
/**
* Fonction de comparaison à utiliser avec tableau.sort(compareNombres)
*
*
* @author Rémi Angot
*/
export function compareNombres (a, b) {
return a - b
}
/**
*
* Copié sur https://delicious-insights.com/fr/articles/le-piege-de-array-sort/
*/
export function numTrie (arr) {
return arr.sort(function (a, b) {
return a - b
})
}
/**
* retourne un tableau dans lequel les doublons ont été supprimés s'il y en a MAIS SANS TRI
* @param {array} arr Tableau duquel ont veut supprimer les doublons numériques
* @param {number} tolerance La différence minimale entre deux valeurs pour les considérer comme égales
* @author Jean-Claude Lhote
**/
export function enleveDoublonNum (arr, tolerance = 0) {
let k = 0
while (k < arr.length - 1) {
let kk = k + 1
while (kk < arr.length - 1) {
if (egal(arr[k], arr[kk], tolerance)) {
arr[k] = (arr[k] + arr[kk]) / 2 // On remplace la valeur dont on a trouvé un double par la moyenne des deux valeurs
arr.splice(kk, 1) // on supprime le doublon.
}
kk++
}
k++
}
return arr
}
/**
* fonction qui retourne une chaine construite en concaténant les arguments
* Le rôle de cette fonction est de construire un identifiant unique de question
* afin de contrôler que l'aléatoire ne produit pas deux questions identiques.
* @author Jean-Claude Lhote
*/
export function checkSum (...args) {
let checkString = ''
for (let i = 0; i < args.length; i++) {
if (typeof args[i] === 'number') {
checkString += Number(args[i]).toString()
} else {
checkString += args[0]
}
}
return checkString
}
/**
* Mélange les items d'un tableau, sans modifier le tableau passé en argument
*
* @Example
* tableau_melange = shuffle (tableau_origine)
* @Source https://stackoverflow.com/questions/2450954/how-to-randomize-shuffle-a-javascript-array
*/
export function shuffle (array) {
let currentIndex = array.length; let temporaryValue; let randomIndex
// While there remain elements to shuffle...
const arrayBis = array.slice()
while (currentIndex !== 0) {
// Pick a remaining element...
randomIndex = Math.floor(Math.random() * currentIndex)
currentIndex -= 1
// And swap it with the current element.
temporaryValue = arrayBis[currentIndex]
arrayBis[currentIndex] = arrayBis[randomIndex]
arrayBis[randomIndex] = temporaryValue
}
return arrayBis
}
export function shuffleJusqua (array, indice) {
if (indice > array.length || indice < 0 || indice === undefined) {
return shuffle(array)
} else {
const tableau1 = array.slice(0, indice)
const tableau2 = array.slice(indice)
return [...shuffle(tableau1), ...tableau2]
}
}
/**
* Mélange les lettres d'un string
*
* @Example
* motMelange = shuffleLettres (mot)
* @Source https://stackoverflow.com/questions/2450954/how-to-randomize-shuffle-a-javascript-array
*/
export function shuffleLettres (txt) {
const array = txt.split('')
return shuffle(array).join('')
}
/**
* Mélange les items de deux tableaux de la même manière
*
*
* @Source https://stackoverflow.com/questions/18194745/shuffle-multiple-javascript-arrays-in-the-same-way
*/
export function shuffle2tableaux (obj1, obj2) {
let index = obj1.length
let rnd, tmp1, tmp2
while (index) {
rnd = Math.floor(Math.random() * index)
index -= 1
tmp1 = obj1[index]
tmp2 = obj2[index]
obj1[index] = obj1[rnd]
obj2[index] = obj2[rnd]
obj1[rnd] = tmp1
obj2[rnd] = tmp2
}
}
/**
* Trie un dictionnaire suivant ses clés
*
* @Example
* dictionnaire_tri = tridictionnaire(dictionnaire)
* @Source https://stackoverflow.com/questions/10946880/sort-a-dictionary-or-whatever-key-value-data-structure-in-js-on-word-number-ke
*/
export function tridictionnaire (dict) {
const sorted = []
for (const key in dict) {
sorted[sorted.length] = key
}
sorted.sort()
const tempDict = {}
for (let i = 0; i < sorted.length; i++) {
tempDict[sorted[i]] = dict[sorted[i]]
}
return tempDict
}
/**
* Filtre un dictionnaire suivant les premiers caractères de ses clés
*
* @Example
* filtreDictionnaire(dict,'6N') renvoie un dictionnaire où toutes les clés commencent par 6N
* @author Rémi Angot
*/
export function filtreDictionnaire (dict, sub) {
return Object.assign({}, ...Object.entries(dict).filter(([k]) => k.substring(0, sub.length) === sub).map(([k, v]) => ({ [k]: v }))
)
}
/**
* Polyfill Object.fromEntries
*
* @Source : https://gitlab.com/moongoal/js-polyfill-object.fromentries/
*/
if (!Object.fromEntries) {
Object.defineProperty(Object, 'fromEntries', {
value (entries) {
if (!entries || !entries[Symbol.iterator]) { throw new Error('Object.fromEntries() requires a single iterable argument') }
const o = {}
Object.keys(entries).forEach((key) => {
const [k, v] = entries[key]
o[k] = v
})
return o
}
})
}
/**
* Filtre un dictionnaire suivant la valeur d'une clé
*
* @Example
* filtreDictionnaireValeurCle(dict,'annee',2020) renvoie un dictionnaire où toutes les clés annee seront égales à 2020
* @author Rémi Angot
*/
export function filtreDictionnaireValeurCle (dict, key, val) {
return Object.fromEntries(Object.entries(dict).filter(([k, v]) => v[key] === val))
}
/**
* Filtre un dictionnaire si une valeur appartient à une clé de type tableau
*
* @Example
* filtreDictionnaireValeurCle(dict,'annee',2020) renvoie un dictionnaire où toutes les clés annee seront égales à 2020
* @author Rémi Angot
*/
export function filtreDictionnaireValeurTableauCle (dict, key, val) {
return Object.fromEntries(Object.entries(dict).filter(([k, v]) => cleExisteEtContient(v[key], val)))
}
function cleExisteEtContient (v, val) {
if (v !== undefined) {
return v.includes(val)
} else {
return false
}
}
/**
* Concatène liste à elle-même en changeant l'ordre à chaque cycle
*
*
* @Example
* combinaisonListes([A,B,C],7)
* // [B,C,A,C,B,A,A,B,C]
*
* @author Rémi Angot
*/
export function combinaisonListes (liste, tailleMinimale) {
if (liste.length === 0) return []
let l = shuffle(liste)
while (l.length < tailleMinimale) {
l = l.concat(shuffle(liste))
}
return l
}
/**
* Concatène liste à elle-même en imposant à la nouvelle liste de contenir au moins tous les élements
* de la liste initiale mais sans gestion de nombre de doublons au final.
* @Example
* combinaisonListes2([A,B,C],7)
* // [B,C,B,B,C,A,B]
* combinaisonListes2([A,B,C,D],6)
* // [B,C,D,B,C,A,B]
* @author Eric Elter
*/
export function combinaisonListes2 (liste, tailleMinimale) {
if (liste.length === 0) return []
let l = liste
while (l.length < tailleMinimale) {
l = l.concat(choice(liste))
}
return shuffle(l)
}
export function combinaisonListesSansChangerOrdre (liste, tailleMinimale) {
// Concatène liste à elle même en changeant
while (liste.length < tailleMinimale) {
liste = liste.concat(liste)
}
return liste
}
/** Renvoie une liste exhaustive de tableaux contenant les mêmes élèments que tab mais jamais dans le même ordre
* Fonction fort utile quand reponse est une suite de nombres par exemple. Voir ligne 111 Exercice 3A10-6.
* Gros défaut : Si tab contient plus de 6 éléments, cette fonction est chronophage. A ne pas utiliser
* @example reponse = diversesReponsesPossibles([3,4,5]) renvoie [[3,4,5],[3,5,4],[4,3,5],[4,5,3],[5,3,4],[5,4,3]]
* et ensuite pour les tous les i : reponse[i]=reponse[i].join(';') et reponse contient alors toutes les réponses possibles
* @author Eric Elter
* Septembre 2022
*/
export function diversesReponsesPossibles (tab) {
let tab2, tab3
const rep = []
if (tab.length === 1) return (tab)
for (let ee = 0; ee < tab.length; ee++) {
tab2 = tab.slice()
tab2.splice(ee, 1)
tab3 = diversesReponsesPossibles(tab2)
for (let k = 0; k < tab3.length; k++) {
rep.push([tab[ee]].concat(tab3[k]))
}
}
return rep
}
/**
* N'écrit pas un nombre s'il est égal à 1
* @Example
* //rienSi1(1)+'x' -> x
* //rienSi1(-1)+'x' -> -x
* @author Rémi Angot et Jean-Claude Lhote pour le support des fractions
*/
export function rienSi1 (a) {
if (equal(a, 1)) return ''
if (equal(a, -1)) return '-'
if (a instanceof Fraction || a instanceof FractionX) return a.toLatex()
if (Number(a) || a === 0) return stringNombre(a) // on retourne 0 ce sera pas joli, mais Number(0) est false !!!
window.notify('rienSi1 : type de valeur non prise en compte : ', { a })
}
/**
* Gère l'écriture de l'exposant en mode text (ne doit pas s'utiliser entre $ $)
* Pour le mode maths (entre $ $) on utilisera tout simplement ^3 pour mettre au cube ou ^{42} pour la puissance 42.
* @Example
* // 'dm'+texteExposant(3)
* @author Rémi Angot
*/
export function texteExposant (texte) {
if (context.isHtml) {
return `<sup>${texte}</sup>`
} else {
return `\\up{${texte}}`
}
}
/**
* Gère l'écriture de l'indice en mode text (ne doit pas s'utiliser entre $ $)
* Pour le mode maths (entre $ $) on utilisera tout _3 pour mettre un indice 3 ou _{42} pour l'indice 42.
* @param {string} texte
* @Example
* // `(d${texteIndice(3)})`
* @author Jean-Claude Lhote
*/
export function texteIndice (texte) {
if (context.isHtml) {
return `<sub>${texte}</sub>`
} else {
return `\\textsubscript{${texte}}`
}
}
/**
* Ajoute les parenthèses et le signe
* @Example
* //(+3) ou (-3)
* @author Rémi Angot
*/
export function ecritureNombreRelatif (a) {
let result = ''
if (a > 0) {
result = '(+' + a + ')'
} else if (a < 0) {
result = '(' + a + ')'
} else { // ne pas mettre de parenthèses pour 0
result = '0'
}
return result
}
/**
* Idem ecritureNombreRelatif avec le code couleur : vert si positif, rouge si négatif, noir si nul
* @param {number} a
*/
export function ecritureNombreRelatifc (a) {
let result = ''
if (a > 0) {
result = miseEnEvidence('(+' + texNombrec(a) + ')', 'blue')
} else if (a < 0) {
result = miseEnEvidence('(' + texNombrec(a) + ')')
} else { // ne pas mettre de parenthèses pour 0
result = miseEnEvidence('0', 'black')
}
return result
}
/**
* Ajoute le + devant les nombres positifs
* @Example
* //+3 ou -3
* @author Rémi Angot et Jean-claude Lhote pour le support des fractions
*/
export function ecritureAlgebrique (a) {
if (a instanceof Fraction || a instanceof FractionX) return fraction(a).ecritureAlgebrique
else if (typeof a === 'number') {
if (a >= 0) {
return '+' + stringNombre(a)
} else {
return stringNombre(a)
}
} else if (a instanceof Decimal) {
if (a.isPos()) {
return '+' + stringNombre(a)
} else {
return stringNombre(a)
}
} else window.notify('rienSi1 : type de valeur non prise en compte')
}
/**
* Ajoute le + devant les nombres positifs, n'écrit rien si 1
* @Example
* //+3 ou -3
* @author Rémi Angot et Jean-Claude Lhote pour le support des fractions
*/
export function ecritureAlgebriqueSauf1 (a) {
if (equal(a, 1)) return '+'
else if (equal(a, -1)) return '-'
else if (a instanceof Fraction || a instanceof FractionX) return fraction(a).ecritureAlgebrique
else if (typeof a === 'number') return ecritureAlgebrique(a)
else window.notify('rienSi1 : type de valeur non prise en compte')
}
/**
* Idem ecritureAlgebrique mais retourne le nombre en couleur (vert si positif, rouge si négatif et noir si nul)
* @param {number} a
*/
export function ecritureAlgebriquec (a) {
let result = ''
if (a > 0) {
result = miseEnEvidence('+' + texNombrec(a), 'blue')
} else if (a < 0) {
result = miseEnEvidence(texNombrec(a))
} else result = miseEnEvidence(texNombrec(a), 'black')
return result
}
/**
* @param {number} r Un nombre relatif
* @param {number} precision nombre de chiffres maximum après la virgule pour texNombre.
* @returns {string} met en évidence le signe - si r < 0
*/
export function signeMoinsEnEvidence (r, precision = 0) {
if (r < 0) return miseEnEvidence('-') + texNombre(Math.abs(r), precision)
else return texNombre(Math.abs(r), precision)
}
/**
* Ajoute des parenthèses aux nombres négatifs
* @Example
* // 3 ou (-3)
* @author Rémi Angot
*/
export function ecritureParentheseSiNegatif (a) {
let result = ''
if (a instanceof Decimal) {
if (a.gte(0)) return texNombre(a, 8) // On met 8 décimales, mais cette fonctions s'utilise presque exclusivement avec des entiers donc ça ne sert à rien
else return `(${texNombre(a, 8)})`
} else {
if (a >= 0) {
result = texNombre(a, 8) // j'ai passé a dans texNombre, car la fonction ne prenait pas en compte l'écriture décimale !
} else {
result = `(${texNombre(a, 8)})`
}
return result
}
}
/**
* Ajoute des parenthèses si une expression commence par un moins
* @Example
* // (-3x)
* @author Rémi Angot
*/
export function ecritureParentheseSiMoins (expr) {
if (expr[0] === '-') return `(${expr})`
else return expr
}
/**
*
* @author Jean-claude Lhote
* @param {numero} 1=A, 2=B ..
* @param {etapes} tableau de chaines comportant les expressions à afficher dans le membre de droite.
*/
export function calculAligne (numero, etapes) {
let script = `$\\begin{aligned}${miseEnEvidence(lettreDepuisChiffre(numero))}&=${etapes[0]}`
for (let i = 1; i < etapes.length - 1; i++) {
script += `\\\\&=${etapes[i]}`
}
script += `\\\\${miseEnEvidence(lettreDepuisChiffre(numero) + '&=' + etapes[etapes.length - 1])}$`
return script
}
/**
* Renvoie la valeur du chiffre (8->8, A->10, B->11...)
*
* @author Rémi Angot
*/
export function valeurBase (n) {
switch (n) {
case 'A': return 10
case 'B': return 11
case 'C': return 12
case 'D': return 13
case 'E': return 14
case 'F': return 15
default: return parseInt(n)
}
}
export function baseValeur (n) {
switch (n) {
case 10: return 'A'
case 11: return 'B'
case 12: return 'C'
case 13: return 'D'
case 14: return 'E'
case 15: return 'F'
default: return Number(n).toString()
}
}
/**
* Convertit une chaine correspondant à un nombre écrit en base b en un nombre entier en base 10.
* @param {} nombre
* @param {number} b la base de départ
*/
export function baseNVersBase10 (stringNombre, b) {
let result = 0
if (typeof stringNombre === 'number') {
stringNombre = stringNombre.toString()
} else if (stringNombre instanceof Decimal) {
stringNombre = stringNombre.toNumber().toString()
}
for (let i = 0; i < stringNombre.length; i++) {
result += b ** i * valeurBase(stringNombre.charAt(stringNombre.length - 1 - i))
}
return result
}
export function base10VersBaseN (nombre, b) {
// let puissanceMax = 0
// let chiffre
// let valeur
// let code = ''
// while (b ** (puissanceMax + 1) < nombre) {
// puissanceMax++
// }
// for (let i = puissanceMax; i >= 0; i--) {
// chiffre = 0
// do {
// valeur = chiffre * b ** i
// chiffre++
// } while (valeur + b ** i <= nombre)
// chiffre--
// code += baseValeur(chiffre)
// nombre -= chiffre * b ** i
// }
// return code
if (nombre instanceof Decimal) return nombre.toNumber().toString(b).toUpperCase()
else return nombre.toString(b).toUpperCase()
// Il y avait un probleme avec 3 = (3)_3
}
/**
*
* @param {array} matrice M tableau 3x3 nombres
* @param {array} vecteur A tableau 3 nombres
* Fonction pouvant être utilisée en 2d avec des coordonnées homogènes
* elle retourne le vecteur [x,y,z] résultat de M.A
* @author Jean-Claude Lhote
*/
export function produitMatriceVecteur3x3 (matrice, vecteur) { // matrice est un tableau 3x3 sous la forme [[ligne 1],[ligne 2],[ligne 3]] et vecteur est un tableau de 3 nombres [x,y,z]
const resultat = [0, 0, 0]
for (let j = 0; j < 3; j++) { // Chaque ligne de la matrice
for (let i = 0; i < 3; i++) { // On traite la ligne i de la matrice -> résultat = coordonnée i du vecteur résultat
resultat[j] += matrice[j][i] * vecteur[i]
}
}
return resultat
}
/**
*
* @param {array} matrice1 Matrice A
* @param {array} matrice2 Matrice B
* retourne la matrice A.B
* @author Jean-Claude Lhote
*/
export function produitMatriceMatrice3x3 (matrice1, matrice2) { // les deux matrices sont des tableaux 3x3 [[ligne 1],[ligne 2],[ligne 3]] et le résultat est de la même nature.
const resultat = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
for (let j = 0; j < 3; j++) {
for (let i = 0; i < 3; i++) {
for (let k = 0; k < 3; k++) { resultat[j][i] += matrice1[j][k] * matrice2[k][i] }
}
}
return resultat
}
/**
*
* @param {array} point
* calcule les coordonnées d'un point donné par ses coordonnées en repère orthonormal en repère (O,I,J) tel que IOJ=60°
* @author Jean-Claude Lhote
*/
export function changementDeBaseOrthoTri (point) {
if (point.length === 2) point.push(1)
return produitMatriceVecteur3x3([[1, -Math.cos(Math.PI / 3) / Math.sin(Math.PI / 3), 0], [0, 1 / Math.sin(Math.PI / 3), 0], [0, 0, 1]], point)
}
/**
*
* @param {array} point
* Changement de base inverse de la fonction précédente
* @author Jean-CLaude Lhote
*/
export function changementDeBaseTriOrtho (point) {
if (point.length === 2) point.push(1)
return produitMatriceVecteur3x3([[1, Math.cos(Math.PI / 3), 0], [0, Math.sin(Math.PI / 3), 0], [0, 0, 1]], point)
}
/**
*
* @param {number} transformation Entier déterminant la transformation voulue
** 1=symétrie / passant par O
**2=symétrie \ passant par O
**3=symétrie _ passant par O
**4=symétrie | passant par O
**5= rotation 90° anti-horaire centre O
**6= rotation 90° horaire centre O
**7= symétrie centrale centre O
**11= rotation 60° anti-horaire centre O
**12= rotation 60° horaire centre O
**13= rotation 120° anti-horaire centre O
**14= rotation 120° horaire centre O
**8= translation coordonnées de O = vecteur de translation
**9= homothétie. centre O rapport k
**10= homothétie. centre O rapport 1/k
* @param {array} pointA Point dont on cherche l'image
* @param {array} pointO Centre du repère local pour les symétries, centre pour les rotations et les homothéties
* @param {array} vecteur Vecteur de la translation
* @param {number} rapport rapport d'homothétie
* @author Jean-Claude Lhote
*/
export function imagePointParTransformation (transformation, pointA, pointO, vecteur = [], rapport = 1) { // pointA,centre et pointO sont des tableaux de deux coordonnées
// on les rends homogènes en ajoutant un 1 comme 3ème coordonnée)
// nécessite d'être en repère orthonormal...
// Point O sert pour les rotations et homothéties en tant que centre (il y a un changement d'origine du repère en O pour simplifier l'expression des matrices de transformations.)
const matriceSymObl1 = matriceCarree([[0, 1, 0], [1, 0, 0], [0, 0, 1]]) // x'=y et y'=x
const matriceSymxxprime = matriceCarree([[1, 0, 0], [0, -1, 0], [0, 0, 1]]) // x'=x et y'=-y
const matriceSymYyPrime = matriceCarree([[-1, 0, 0], [0, 1, 0], [0, 0, 1]]) // x'=-x et y'=y
const matriceSymObl2 = matriceCarree([[0, -1, 0], [-1, 0, 0], [0, 0, 1]]) // x'=-y et y'=-x
const matriceQuartDeTourDirect = matriceCarree([[0, -1, 0], [1, 0, 0], [0, 0, 1]]) // x'=-y et y'=x
const matriceQuartDeTourIndirect = matriceCarree([[0, 1, 0], [-1, 0, 0], [0, 0, 1]]) // x'=y et y'=-x
const matriceSymCentrale = matriceCarree([[-1, 0, 0], [0, -1, 0], [0, 0, 1]]) // x'=-x et y'=-y
const matriceRotation60Direct = matriceCarree([[0.5, -Math.sin(Math.PI / 3), 0], [Math.sin(Math.PI / 3), 0.5, 0], [0, 0, 1]])
const matriceRotation60Indirect = matriceCarree([[0.5, Math.sin(Math.PI / 3), 0], [-Math.sin(Math.PI / 3), 0.5, 0], [0, 0, 1]])
const matriceRotation120Direct = matriceCarree([[-0.5, -Math.sin(Math.PI / 3), 0], [Math.sin(Math.PI / 3), -0.5, 0], [0, 0, 1]])
const matriceRotation120Indirect = matriceCarree([[-0.5, Math.sin(Math.PI / 3), 0], [-Math.sin(Math.PI / 3), -0.5, 0], [0, 0, 1]])
let pointA1 = [0, 0, 0]
let pointA2 = [0, 0, 0]
if (pointA.length === 2) pointA.push(1)
const x2 = pointO[0] // Point O' (origine du repère dans lequel les transformations sont simples (centre des rotations et point d'intersection des axes))
const y2 = pointO[1]
const u = vecteur[0] // (u,v) vecteur de translation.
const v = vecteur[1]
const k = rapport // rapport d'homothétie
const matriceChangementDeRepere = matriceCarree([[1, 0, x2], [0, 1, y2], [0, 0, 1]])
const matriceChangementDeRepereInv = matriceCarree([[1, 0, -x2], [0, 1, -y2], [0, 0, 1]])
const matriceTranslation = matriceCarree([[1, 0, u], [0, 1, v], [0, 0, 1]])
const matriceHomothetie = matriceCarree([[k, 0, 0], [0, k, 0], [0, 0, 1]])
const matriceHomothetie2 = matriceCarree([[1 / k, 0, 0], [0, 1 / k, 0], [0, 0, 1]])
let matrice
switch (transformation) {
case 1:
matrice = matriceSymObl1.multiplieMatriceCarree(matriceChangementDeRepereInv)
break
case 2:
matrice = matriceSymObl2.multiplieMatriceCarree(matriceChangementDeRepereInv)
break
case 3:
matrice = matriceSymxxprime.multiplieMatriceCarree(matriceChangementDeRepereInv)
break
case 4:
matrice = matriceSymYyPrime.multiplieMatriceCarree(matriceChangementDeRepereInv)
break
case 5:
matrice = matriceQuartDeTourDirect.multiplieMatriceCarree(matriceChangementDeRepereInv)
break
case 6:
matrice = matriceQuartDeTourIndirect.multiplieMatriceCarree(matriceChangementDeRepereInv)
break
case 7:
matrice = matriceSymCentrale.multiplieMatriceCarree(matriceChangementDeRepereInv)
break
case 11:
matrice = matriceRotation60Direct.multiplieMatriceCarree(matriceChangementDeRepereInv)
break
case 12:
matrice = matriceRotation60Indirect.multiplieMatriceCarree(matriceChangementDeRepereInv)
break
case 13:
matrice = matriceRotation120Direct.multiplieMatriceCarree(matriceChangementDeRepereInv)
break
case 14:
matrice = matriceRotation120Indirect.multiplieMatriceCarree(matriceChangementDeRepereInv)
break
case 8:
matrice = matriceTranslation.multiplieMatriceCarree(matriceChangementDeRepereInv)
break
case 9:
matrice = matriceHomothetie.multiplieMatriceCarree(matriceChangementDeRepereInv)
break
case 10:
matrice = matriceHomothetie2.multiplieMatriceCarree(matriceChangementDeRepereInv)
break
}
pointA1 = matrice.multiplieVecteur(pointA)
pointA2 = matriceChangementDeRepere.multiplieVecteur(pointA1)
return pointA2
}
/**
* Retourne le signe d'un nombre
* @Example
* // + ou -
* @author Rémi Angot
*/
export function signe (a) { // + ou -
let result = ''
if (a > 0) {
result = '+'
} else {
result = '-'
}
return result
}
/**
*
* @param {number} a
* -1 si a est négatif, 1 sinon.
* @author Jean-Claude Lhote
*/
export function unSiPositifMoinsUnSinon (a) {
if (a < 0) return -1
else return 1
}
/**
* Retourne la somme des chiffres (ou d'un tableau de chiffres) d'un nombre en valeur et sous forme de String [valeur, String]
* @Example
* sommeDesChiffres(123)
* // [ 6, '1+2+3']
* @author Rémi Angot (Rajout Tableau par EE)
*/export function sommeDesChiffres (n) {
let nString
if (Array.isArray(n)) nString = n.join('').toString()
else nString = n.toString()
let somme = 0
let sommeString = ''
for (let i = 0; i < nString.length - 1; i++) {
if (['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'].indexOf(nString[i] !== -1)) {
sommeString += nString[i] + '+'
somme += Number(nString[i])
}
}
if (['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'].indexOf(nString[nString.length - 1] !== -1)) {
sommeString += nString[nString.length - 1]
somme += Number(nString[nString.length - 1])
}
return [somme, sommeString]
}
/**
* Retourne l'arrondi (par défaut au centième près)
* @author Rémi Angot
* @param {number} nombre
* @param {number} precision
* @return {number}
*/
export function arrondi (nombre, precision = 2) {
if (isNaN(nombre)) {
window.notify('Le nombre à arrondir n\'en est pas un, ça retourne NaN', { nombre, precision })
return NaN
} else {
return round(nombre, precision)
}
}
/**
* Retourne la troncature signée de nombre.
* @author Jean-Claude Lhote
*/
export function troncature (nombre, precision) {
const tmp = Math.pow(10, precision)
const absolu = new Decimal(nombre).abs()
const tronc = absolu.mul(tmp).floor().div(tmp)
if (nombre < 0) return tronc.mul(-1).toNumber()
else return tronc.toNumber()
}
/**
* Renvoie la valeur absolue
* @author Rémi Angot + ajout du support des décimaux par Jean-Claude Lhote
*/
export function abs (a) {
if (a instanceof Decimal) return a.abs()
return Math.abs(a)
}
/**
* Retourne un arrondi sous la forme d'un string avec une virgule comme séparateur décimal
* @author Rémi Angot Fonction rendue inutile par Jean-Claude Lhote : lui substituer texNombre ou stringNombre selon le contexte.
*/
// export function arrondiVirgule (nombre, precision = 2) { //
// const tmp = Math.pow(10, precision)
// return String(round(nombre, precision)).replace('.', ',')
// }
/**
* Retourne égal si la valeur égal l'arrondi souhaité ou environ égal si ce n'est pas le cas
* le nombre a est comparé à son arrondi à précision près. Si la différence est inférieure à epsilon, alors on retourne '=' sinon '\\approx'
* fonctionne aussi si a est une fraction : permet de finir un calcul par la valeur décimale si on veut.
* @author Jean-Claude Lhote
*/
export function egalOuApprox (a, precision) {
if (typeof a === 'object' && ['Fraction', 'FractionX'].indexOf(a.type) !== -1) {
return egal(a.n / a.d, arrondi(a.n / a.d, precision)) ? '=' : '\\approx'
} else if (a instanceof Decimal) {
return a.eq(a.toDP(precision)) ? '=' : '\\approx'
} else if (!isNaN(a) && !isNaN(precision)) return egal(a, round(a, precision), 10 ** (-precision - 2)) ? '=' : '\\approx'
else {
window.notify('egalOuApprox : l\'argument n\'est pas un nombre', { a, precision })
return 'Mauvais argument (nombres attendus).'
}
}
/**
* Renvoie le PGCD de deux nombres
* @author Rémi Angot
*/
export function pgcd (...args) {
return gcd(...args)
}
/**
* Retourne le numérateur et le dénominateur de la fraction passée en argument sous la forme (numérateur,dénominateur)réduite au maximum dans un tableau [numérateur,dénominateur]
* * **ATTENTION Fonction clonée dans la classe FractionX()**
* @author Rémi Angot
*/
export function fractionSimplifiee (n, d) {
const p = pgcd(n, d)
let ns = n / p
let ds = d / p
if (ns < 0 && ds < 0) {
[ns, ds] = [-ns, -ds]
}
if (ns > 0 && ds < 0) {
[ns, ds] = [-ns, -ds]
}
return [ns, ds]
}
/**
* Retourne le code LaTeX d'une fraction simplifiée ou d'un nombre entier
* @author Rémi Angot
*/
export function texFractionReduite (n, d) {
if (Math.abs(n) % Math.abs(d) === 0) {
return n / d
} else {
return texFractionSigne(fractionSimplifiee(n, d)[0], fractionSimplifiee(n, d)[1])
}
}
/**
* produitDeDeuxFractions(num1,den1,num2,den2) retourne deux chaines :
* la première est la fraction résultat, la deuxième est le calcul mis en forme Latex avec simplification éventuelle
* Applique une simplification si le numérateur de l'une est égal au dénominateur de l'autre.
*/
export function produitDeDeuxFractions (num1, den1, num2, den2) {
let num, den, texProduit
if (num1 === den2) {
texProduit = `\\dfrac{\\cancel{${num1}}\\times ${ecritureParentheseSiNegatif(num2)}}{${den1}\\times\\cancel{${ecritureParentheseSiNegatif(den2)}}}`
num = num2
num1 = 1
den2 = 1
den = den1
} else if (num2 === den1) {
texProduit = `\\dfrac{${num1}\\times \\cancel{${ecritureParentheseSiNegatif(num2)}}}{\\cancel{${den1}}\\times${ecritureParentheseSiNegatif(den2)}}`
num = num1
num2 = 1
den1 = 1
den = den2
} else {
num = num1 * num2
den = den1 * den2
texProduit = `\\dfrac{${num1}\\times ${ecritureParentheseSiNegatif(num2)}}{${den1}\\times${ecritureParentheseSiNegatif(den2)}}`
}
return [texFraction(num, den), texProduit, [num1, den1, num2, den2]]
}
/**
*
* Simplifie une fraction en montrant les étapes
* Le résultat est un string qui doit être entouré de $ pour le mode mathématiques
* @author Rémi Angot
*/
export function simplificationDeFractionAvecEtapes (num, den) {
let result = '='
if (num === 0) {
return '=0'
}
const signe = num * den < 0 ? '-' : ''
const numAbs = Math.abs(num)
const denAbs = Math.abs(den)
// Est-ce que le résultat est simplifiable ?
const s = pgcd(numAbs, denAbs)
if (s !== 1) {
if (numAbs % denAbs === 0) { // si le résultat est entier
result += `${num / den}`
} else {
result += `${signe}${texFraction(numAbs / s + miseEnEvidence('\\times' + s), denAbs / s + miseEnEvidence('\\times' + s))}=${texFractionSigne(num / s, den / s)}`
}
} else if (num < 0 || den < 0) {
result += `${texFractionSigne(num, den)}`
} else return ''
return result
}
/**
* Retourne l'égalité des produits en croix à partir d'un tableau contenant les deux fractions [[a,b],[c,d]] pour a/b=c/d retourne ad=bc
* Le résultat est un string en mode maths inline
* @author Jean-Claude Lhote
*/
export function produitsEnCroix ([[a, b], [c, d]]) { // écrit une chaine pour a*d=b*c
let result = ''
result += `$${a}\\times${d}=${b}\\times${c}$`
return result
}
/**
* Retourne la quatrième proportionnelle de 3 nombres en fonction d'une précision demandée
* Le résultat est un string qui doit être entouré de $ pour le mode mathématiques
* @author Jean-Claude Lhote
*/
export function quatriemeProportionnelle (a, b, c, precision) { // calcul de b*c/a
let result = ''
if ((typeof a) === 'number' && (typeof b) === 'number' && (typeof c) === 'number') {
if (a === 0) {
result = '=erreur : division par zéro'
return result
}
const p4 = new Decimal(b).mul(c).div(a)
result += `\\dfrac{${texNombrec(b)}\\times${texNombrec(c)}}{${texNombrec(a)}}`
if (p4.eq(p4.toDP(precision))) result += '='
else result += '\\approx'
result += `${texNombre(p4, precision)}`
return result
} else {
return `\\dfrac{${b} \\times${c}}{${a}}`
}
}
/**
* renvoie une chaine correspondant à l'écriture réduite de ax+b selon les valeurs de a et b
* La lettre par défaut utilisée est 'x' mais peut être tout autre chose.
* @author Jean-Claude Lhote
* @param {number} a
* @param {number} b
*/
export function reduireAxPlusB (a, b) {
if (!(a instanceof Decimal)) a = new Decimal(a)
if (!(b instanceof Decimal)) b = new Decimal(b)
let result = ''
if (!a.isZero()) {
if (a.eq(1)) result = 'x'
else if (a.eq(-1)) result = '-x'
else result = `${stringNombre(a)}x`
}
if (!b.isZero()) {
if (!a.isZero()) result += `${ecritureAlgebrique(b)}`
else result = stringNombre(b)
} else if (a.isZero()) result = '0'
return result
}
/**
* renvoie une chaine correspondant à l'écriture réduite de ax^3+bx^2+cx+d selon les valeurs de a,b,c et d
* @author Jean-Claude Lhote
*/
export function reduirePolynomeDegre3 (a, b, c, d, x = 'x') {
let result = ''
if (a !== 0) {
switch (a) {
case 1:
result += `${x}^3`
break
case -1:
result += `-${x}^3`
break
default:
result += `${a}${x}^3`
break
}
if (b !== 0) {
switch (b) {
case 1:
result += `+${x}^2`
break
case -1:
result += `-${x}^2`
break
default:
result += `${ecritureAlgebrique(b)}${x}^2`
break
}
}
if (c !== 0) {
switch (c) {
case 1:
result += `+${x}`
break
case -1:
result += `-${x}`
break
default:
result += `${ecritureAlgebrique(c)}${x}`
break
}
}
if (d !== 0) {
result += `${ecritureAlgebrique(d)}`
}
} else { // degré 2 pas de degré 3
if (b !== 0) {
switch (b) {
case 1:
result += `${x}^2`
break
case -1:
result += `-${x}^2`
break
default:
result += `${b}${x}^2`
break
}
if (c !== 0) {
switch (c) {
case 1:
result += `+${x}`
break
case -1:
result += `-${x}`
break
default:
result += `${ecritureAlgebrique(c)}${x}`
break
}
}
if (d !== 0) {
result += `${ecritureAlgebrique(d)}`
}
} else // degré 1 pas de degré 2 ni de degré 3
if (c !== 0) {
switch (c) {
case 1:
result += `${x}`
break
case -1:
result += `-${x}`
break
default:
result += `${c}${x}`
break
}
if (d !== 0) {
result += `${ecritureAlgebrique(d)}`
}
} else { // degré 0 a=0, b=0 et c=0
result += `${d}`
}
}
return result
}
/**
* Donne la liste des facteurs premiers d'un nombre
* @param { number } n - Nombre à décomposer
* @returns {number[]} - Liste des facteurs premiers
*/
export function obtenirListeFacteursPremiers (n) {
const facteurs = []
for (let i = 2; i <= n; i++) {
while (n % i === 0) {
facteurs.push(i)
n /= i
}
}
return facteurs
}
/**
*
* @param {Entier} n
* Retourne la factorisation d'un entier sous la forme [[a0,n0],[a1,n1],...] où a0,a1 sont les facteurs premiers et n0, n1 sont les exposants de ces facteurs.
* @author Jean-Claude Lhote
*/
export function factorisation (n) {
const liste = obtenirListeFacteursPremiers(n)
const facto = []; let index = 0
for (let i = 0; i < liste.length;) {
if (liste[i] === 0) i++
else {
facto.push([liste[i], 1])
index++
for (let j = i + 1; j < liste.length; j++) {
if (liste[j] === liste[i]) {
facto[index - 1][1]++
liste[j] = 0
}
}
i++
}
}
return facto
}
/**
*
* @param {number} n
* @param {boolean} puissancesOn
* @returns {string} texFacto
*/
export function texFactorisation (n, puissancesOn = true) {
let texFacto = ''
let facto = []
if (puissancesOn) {
facto = factorisation(n)
for (let i = 0; i < facto.length - 1; i++) {
texFacto += `${facto[i][0]}${facto[i][1] > 1 ? '^{' + facto[i][1] + '}\\times ' : '\\times '}`
}
texFacto += `${facto[facto.length - 1][0]}${facto[facto.length - 1][1] > 1 ? '^{' + facto[facto.length - 1][1] + '}' : ''}`
} else {
facto = obtenirListeFacteursPremiers(n)
for (let i = 0; i < facto.length - 1; i++) {
texFacto += `${facto[i][0]}\\times `
}
texFacto += `${facto[facto.length - 1][0]}`
}
return texFacto
}
/**
*
* @param {Entier} n
* Extrait le plus grand nombre possible de la racine carrée de n
* retourne le résulat [a,b] pour a²b=n
* @author Jean-Claude Lhote
*/
export function extraireRacineCarree (n) {
const facto = factorisation(n)
let radical = 1; let facteur = 1
for (let i = 0; i < facto.length; i++) {
if (facto[i][1] % 2 === 0) {
facteur *= facto[i][0] ** (facto[i][1] >> 1)
} else if (facto[i][1] > 1) {
facteur *= facto[i][0] ** ((facto[i][1] - 1) >> 1)
radical *= facto[i][0]
} else radical *= facto[i][0]
}
return [facteur, radical]
}
/**
*
* @param {Entier} n
* retourne le code Latex de la racine carrée de n "réduite"
* @author Jean-CLaude Lhote
*/
export function texRacineCarree (n) {
const result = extraireRacineCarree(n)
if (result[1] === 1) return `${result[0]}`
else if (result[0] === 1) return `\\sqrt{${result[1]}}`
else return `${result[0]}\\sqrt{${result[1]}}`
}
/**
*
* @param {'string | array'} expression ou tableau d'expressions à évaluer avec XCas
* @returns string
* @author Rémi Angot
*/
export function xcas (expression) {
const sortie = (txt) => UI.eval(`latex(${txt})`).replaceAll('\\cdot ', '~').replaceAll('\\frac', '\\dfrac').replaceAll('"', '')
if (typeof expression === 'string') return sortie(expression)
else {
const result = []
for (const txt of expression) {
result.push(sortie(txt))
}
return result
}
}
/**
* Utilise un arrondi au millionième pour éviter les flottants à rallonge (erreurs d'arrondis des flottants)
* Le 2e argument facultatif permet de préciser l'arrondi souhaité : c'est le nombre max de chiffres après la virgule souhaités
* @author Rémi Angot modifié par Jean-Claude Lhote
*/
export function calcul (x, arrondir = 6) {
const sansPrecision = (arrondir === undefined)
// if (sansPrecision) arrondir = 6
if (typeof x === 'string') {
window.notify('Calcul : Reçoit une chaine de caractère et pas un nombre', { x })
x = parseFloat(evaluate(x))
}
if (sansPrecision && !egal(x, arrondi(x, arrondir), 10 ** (-arrondir - 1))) window.notify('calcul : arrondir semble avoir tronqué des décimales sans avoir eu de paramètre de précision', { x, arrondir })
return parseFloat(x.toFixed(arrondir))
}
/**
* Utilise Algebrite pour s'assurer qu'il n'y a pas d'erreur dans les calculs avec des décimaux
* Le 2e argument facultatif permet de préciser l'arrondi souhaité
* @author Rémi Angot
*/
export function nombreDecimal (expression, arrondir = false) {
if (!arrondir) {
return stringNombre(new Decimal(expression), 15)
} else {
return stringNombre(new Decimal(expression), arrondir)
}
}
/**
* Utilise Algebrite pour s'assurer qu'il n'y a pas d'erreur dans les calculs avec des décimaux et retourne un string avec la virgule comme séparateur décimal
* @author Rémi Angot
* texNombrec n'apportant rien, je la shinte.
*/
export function texNombrec (expression, precision) {
// return texNombre(parseFloat(Algebrite.eval(expression)))
return texNombre(expression, precision)
}
/**
* Formattage pour une sortie LaTeX entre $$
* formatFraction = false : si l'expression est un objet fraction du module mathjs alors elle peut donner l'écriture fractionnaire
* Pour une fraction négative la sortie est -\dfrac{6}{7} au lieu de \dfrac{-6}{7}
* @author Frédéric PIOU
*/
export function texNum (expression, formatFraction = false) {
if (typeof expression === 'object') {
const signe = expression.s === 1 ? '' : '-'
if (formatFraction === true) {
expression = expression.d !== 1 ? signe + texFraction(expression.n, expression.d) : signe + expression.n
} else {
expression = texNombre(evaluate(format(expression)))
}
expression = expression.replace(',', '{,}').replace('{{,}}', '{,}')
} else {
expression = texNombre(parseFloat(Algebrite.eval(expression)))
}
return expression
}
/**
* renvoie le résultat de l'expression en couleur (vert=positif, rouge=négatif, noir=nul)
* @param {string} expression l'expression à calculer
*/
export function texNombreCoul (nombre, positif = 'green', negatif = 'red', nul = 'black') {
if (nombre > 0) return miseEnEvidence(texNombrec(nombre), positif)
else if (nombre < 0) return miseEnEvidence(texNombrec(nombre), negatif)
else return miseEnEvidence(texNombrec(0), nul)
}
/**
* prend une liste de nombres relatifs et la retourne avec les positifs au début et les négatifs à la fin.
* @param {array} liste la liste de nombres à trier
*/
export function triePositifsNegatifs (liste) {
const positifs = []
const negatifs = []
for (let i = 0; i < liste.length; i++) {
if (liste[i] > 0) positifs.push(liste[i])
else negatifs.push(liste[i])
}
return positifs.concat(negatifs)
}
/**
* Renvoie un tableau (somme des termes positifs, somme des termes négatifs)
* @author Rémi Angot
*/
export function sommeDesTermesParSigne (liste) {
let sommeDesPositifs = 0; let sommeDesNegatifs = 0
for (let i = 0; i < liste.length; i++) {
if (liste[i] > 0) {
sommeDesPositifs += liste[i]
} else {
sommeDesNegatifs += liste[i]
}
}
return [sommeDesPositifs, sommeDesNegatifs]
}
/**
* Créé un string de nbsommets caractères dans l'ordre alphabétique et en majuscule qui ne soit pas dans la liste donnée en 2e argument
* @param {integer} nbsommets
* @param {string[]} listeAEviter
* @author Rémi Angot
* Ajout des while pour s'assurer de bien avoir des lettres majuscules le 08/05/2022 par Guillaume Valmont
**/
export function creerNomDePolygone (nbsommets, listeAEviter = []) {
let premiersommet = randint(65, 90 - nbsommets)
let polygone = ''
if (listeAEviter === undefined) listeAEviter = []
for (let i = 0; i < nbsommets; i++) {
let augmentation = i
while (premiersommet + augmentation > 90) augmentation -= 26
while (premiersommet + augmentation < 65) augmentation += 26
polygone += String.fromCharCode(premiersommet + augmentation)
}
if (listeAEviter.length < 26 - nbsommets - 1) { // On évite la liste à éviter si elle n'est pas trop grosse sinon on n'en tient pas compte
let cpt = 0
while (possedeUnCaractereInterdit(polygone, listeAEviter) && cpt < 20) {
polygone = ''
premiersommet = randint(65, 90 - nbsommets)
for (let i = 0; i < nbsommets; i++) {
polygone += String.fromCharCode(premiersommet + i)
}
cpt++ // Au bout de 20 essais on laisse tomber la liste à éviter
}
} else {
console.log('Trop de questions donc plusieurs polygones peuvent avoir le même nom')
}
return polygone
}
/**
* Vérifie dans un texte si un de ses caractères appartient à une liste à éviter
* @author Rémi Angot
*/
export function possedeUnCaractereInterdit (texte, listeAEviter) {
let result = false
for (const motAeviter of listeAEviter) {
for (let i = 0; i < motAeviter.length; i++) {
if (texte.indexOf(motAeviter[i]) > -1) {
result = true
}
}
}
return result
}
/**
* retourne une liste de combien de nombres compris entre m et n (inclus) en évitant les valeurs de listeAEviter
* toutes la liste des nombres est retournée si combien est supérieur à l'effectif disponible
* les valeurs sont dans un ordre aléatoire.
* @author Jean-Claude Lhote
*
*/
export function choisitNombresEntreMetN (m, n, combien, listeAEviter = []) {
let t
if (m > n) {
t = m
m = n
n = t
} else if (m === n) { return [n] }
if (combien > n - m) combien = n - m
let index = rangeMinMax(m, n, listeAEviter)
index = shuffle(index)
index = index.slice(0, combien)
return index
}
/**
* retourne une liste de lettres majuscules (ou minuscule si majuscule=false)
* il y aura nombre lettres dans un ordre aléatoire
* les lettres à éviter sont données dans une chaine par exemple : 'QXY'
* @author Jean-Claude Lhote
*/
export function choisitLettresDifferentes (nombre, lettresAeviter = '', majuscule = true) {
const listeAEviter = []; const lettres = []
for (const l of lettresAeviter) {
listeAEviter.push(l.charCodeAt(0) - 64)
}
const index = choisitNombresEntreMetN(1, 26, nombre, listeAEviter)
for (const n of index) {
if (majuscule) lettres.push(lettreDepuisChiffre(n))
else lettres.push(lettreMinusculeDepuisChiffre(n))
}
return lettres
}
export function cesar (word, decal) {
let mot = ''; let code = 65
for (let x = 0; x < word.length; x++) {
code = word.charCodeAt(x) % 65
code = (code + decal) % 26 + 65
mot += String.fromCharCode(code)
}
return mot
}
export function codeCesar (mots, decal) {
const motsCodes = []
for (let x = 0; x < mots.length; x++) {
motsCodes.push(cesar(mots[x], decal))
}
return motsCodes
}
/**
* Renvoie une lettre majuscule depuis un nombre compris entre 1 et 702
* Le 2e paramètre est un booléen qui permet d'éviter la lettre D (et donc décale tout d'une lettre après le C) en vue du bug de MathLive
* @author Rémi Angot
*@Example
* // 0 -> @ 1->A ; 2->B...
* // 27->AA ; 28 ->AB ...
*/
export function lettreDepuisChiffre (i, saufD = false) {
let result = ''
if (i <= 26) {
result = String.fromCharCode(64 + i)
if (saufD && i >= 4) result = String.fromCharCode(64 + i + 1)
} else {
if (i % 26 === 0) {
result = String.fromCharCode(64 + Math.floor(i / 26) - 1)
result += String.fromCharCode(64 + 26)
} else {
result = String.fromCharCode(64 + Math.floor(i / 26))
result += String.fromCharCode(64 + i % 26)
}
}
return result
}
/**
* Renvoie une lettre minuscule depuis un nombre compris entre 1 et 702
* @author Rémi Angot
*@Example
* // 0 -> @ 1->a ; 2->b...
* // 27->aa ; 28 ->ab ...
*/
export function lettreMinusculeDepuisChiffre (i) {
return lettreDepuisChiffre(i).toLowerCase()
}
/**
* Renvoie une lettre majuscule (éventuellement indicée) depuis un nombre compris entre 1 et... sans limite.
* @author Eric Elter
*@Example
* // 0 -> @ 1->A ; 2->B...
* // 27->A_1 ; 28 ->A_2 ...
*/
export function lettreIndiceeDepuisChiffre (i) {
const indiceLettre = quotientier(i - 1, 26) === 0 ? '' : quotientier(i - 1, 26)
return String.fromCharCode(64 + (i - 1) % 26 + 1) + (i > 26 ? `_{${indiceLettre}}` : '')
}
/**
* Renvoie une lettre minuscule (éventuellement indicée) depuis un nombre compris entre 1 et... sans limite.
* @author EricElter
*@Example
* // 0 -> @ 1->a ; 2->b...
* // 27->a_1 ; 28 ->a_2 ...
*/
export function lettreIndiceeMinusculeDepuisChiffre (i) {
return lettreIndiceeDepuisChiffre(i).toLowerCase()
}
/**
* @author Rémi Angot
* @Example
* //0h24 est accepté
*/
export function minToHoraire (minutes) {
let nbHour = parseInt(minutes / 60)
if (nbHour > 23) {
nbHour = nbHour - 24
}
const nbminuteRestante = (minutes % 60)
if (nbminuteRestante > 9) {
return (nbHour + sp() + 'h' + sp() + nbminuteRestante)
} else {
return (nbHour + sp() + ' h' + sp() + '0' + nbminuteRestante)
}
}
/**
* @author Rémi Angot
* @Example
* //on écrira 24 minutes plutôt que 0h24
*/
export function minToHour (minutes) {
let nbHour = parseInt(minutes / 60)
if (nbHour > 23) {
nbHour = nbHour - 24
}
const nbminuteRestante = (minutes % 60)
if (nbHour === 0) {
return (nbminuteRestante + sp() + 'min')
} else {
if (nbminuteRestante > 9) {
return (nbHour + sp() + 'h' + sp() + nbminuteRestante)
} else {
return (nbHour + sp() + ' h' + sp() + '0' + nbminuteRestante)
}
}
}
/**
* Renvoie un tableau de deux valeurs : le nombre d'heures dans un paquet de minutes ainsi que le nombre de minutes restantes.
* @author Eric Elter
* @example minToHeuresMinutes (127) renvoie [2,7] car 127min = 2h7min
* @example minToHeuresMinutes (300) renvoie [5,0] car 300min = 6h
* @example minToHeuresMinutes (1456) renvoie [24,16] car 1456min = 24h16min
*
*/
export function minToHeuresMinutes (minutes) {
return [parseInt(minutes / 60), (minutes % 60)]
}
/**
* Renvoie un prénom féminin au hasard
* @author Rémi Angot
*/
export function prenomF (n = 1) {
if (n === 1) {
return choice(['Aude', 'Béatrice', 'Carine', 'Corinne', 'Dalila', 'Elsa', 'Farida', 'Julie', 'Karole', 'Léa', 'Lisa', 'Manon', 'Marina', 'Magalie', 'Nadia', 'Nawel', 'Teresa', 'Vanessa', 'Yasmine'])
} else {
return shuffle(['Aude', 'Béatrice', 'Carine', 'Corinne', 'Dalila', 'Elsa', 'Farida', 'Julie', 'Karole', 'Léa', 'Lisa', 'Manon', 'Marina', 'Magalie', 'Nadia', 'Nawel', 'Teresa', 'Vanessa', 'Yasmine']).slice(0, n)
}
}
/**
* Renvoie un prénom masculin au hasard
* @author Rémi Angot
*/
export function prenomM (n = 1) {
if (n === 1) {
return choice(['Arthur', 'Benjamin', 'Bernard', 'Christophe', 'Cyril', 'David', 'Fernando', 'Guillaume', 'Jean-Claude', 'Joachim', 'José', 'Kamel', 'Karim', 'Laurent', 'Mehdi', 'Nacim', 'Pablo', 'Rémi', 'Victor', 'Yazid'])
} else {
return shuffle(['Arthur', 'Benjamin', 'Bernard', 'Christophe', 'Cyril', 'David', 'Fernando', 'Guillaume', 'Jean-Claude', 'Joachim', 'José', 'Kamel', 'Karim', 'Laurent', 'Mehdi', 'Nacim', 'Pablo', 'Rémi', 'Victor', 'Yazid']).slice(0, n)
}
}
/**
* Renvoie un prénom au hasard
* @author Rémi Angot
*/
export function prenom (n = 1) {
if (n === 1) {
return choice([prenomF(), prenomM()])
} else {
return shuffle(['Aude', 'Béatrice', 'Carine', 'Corinne', 'Dalila', 'Elsa', 'Farida', 'Julie', 'Karole', 'Léa', 'Lisa', 'Manon', 'Marina', 'Magalie', 'Nadia', 'Nawel', 'Teresa', 'Vanessa', 'Yasmine', 'Arthur', 'Benjamin', 'Bernard', 'Christophe', 'Cyril', 'David', 'Fernando', 'Guillaume', 'Jean-Claude', 'Joachim', 'José', 'Kamel', 'Karim', 'Laurent', 'Mehdi', 'Nacim', 'Pablo', 'Rémi', 'Victor', 'Yazid']).slice(0, n)
}
}
/**
* Renvoie un petit objet féminin au hasard
* @author Mireille Gain
*/
export function objetF () {
return choice(['boîtes', 'bougies', 'cartes de voeux', 'gommes', 'photos', 'petites peluches'])
}
/**
* Renvoie un petit objet masculin au hasard
* @author Mireille Gain
*/
export function objetM () {
return choice(['stickers', 'gâteaux', 'cahiers', 'livres', 'stylos', 'crayons'])
}
/**
* Renvoie un petit objet au hasard
* @author Mireille Gain
*/
export function objet () {
return choice(['billes', 'bonbons', 'bougies', 'cartes de voeux', 'crayons', 'gâteaux', 'gommes', 'photos', 'stickers', 'cahiers'])
}
/**
* Définit l'objet personne
* @author Jean-Claude Lhote
* le 14/03/2021
*/
class Personne {
constructor ({ prenom = '', genre = '', pronom = '', Pronom = '' } = {}) {
let choix
this.prenom = ''
this.genre = ''
this.pronom = ''
this.Pronom = ''
if (prenom === '' || ((typeof prenom) === 'undefined')) { // On le/la baptise
choix = prenomPronom()
this.prenom = choix[0]
this.pronom = choix[1]
} else if (pronom === '') { // le pronom n'est pas précisé
this.pronom = 'on'
this.Pronom = 'On'
}
if (genre === '') {
if (this.pronom === 'il') {
this.Pronom = 'Il'
this.genre = 'masculin'
} else if (this.pronom === 'elle') {
this.Pronom = 'Elle'
this.genre = 'féminin'
} else this.genre = 'neutre'
}
}
}
/**
* crée une instance de la classe Personne
* @author Jean-Claude Lhote
* le 14/03/2021
*/
export function personne ({ prenom = '', genre = '', pronom = '' } = {}) {
return new Personne({ prenom, genre, pronom })
}
/**
* Crée un tableau de n objet de la classe Personne
* @author Jean-Claude Lhote
* le 14/03/2021
*/
export function personnes (n) {
const liste = []; let essai; let trouve
for (let i = 0; i < n;) {
essai = personne()
trouve = false
for (let j = 0; j < liste.length; j++) {
if (liste[j].prenom === essai.prenom) {
trouve = true
break
}
}
if (trouve === false) {
liste.push(essai)
i++
}
}
return liste
}
/**
* Renvoie un couple [prénom,pronom] où pronom='il' ou 'elle'
* @author Jean-Claue Lhote
*/
export function prenomPronom () {
if (choice([true, false])) {
return [prenomM(1), 'il']
} else {
return [prenomF(1), 'elle']
}
}
/**
* Renvoie un tableau avec les résultats des tirages successifs
* @param nombreTirages Combien de tirages ?
* @param nombreFaces Pour spécifier le type de dés
* @param nombreDes Combien de dés à chaque tirage ?
* @author Jean-Claude Lhote
*/
export function tirerLesDes (nombreTirages, nombreFaces, nombreDes) {
const tirages = []
for (let i = 0; i <= (nombreFaces - 1) * nombreDes; i++) tirages.push([i + nombreDes, 0])
for (let i = 0, resultat; i < nombreTirages; i++) {
resultat = 0
for (let j = 0; j < nombreDes; j++) resultat += randint(1, nombreFaces)
tirages[resultat - nombreDes][1]++
}
return tirages
}
/**
* Renvoie un tableau de nombres
* @param nombreNotes
* @param noteMin
* @param noteMax
* @param distincts Si distincts === true, les notes de la liste seront toutes distinctes
* @author Jean-Claude Lhote et Guillaume Valmont
*/
export function listeDeNotes (nombreNotes, noteMin = 0, noteMax = 20, distincts = false) {
const notes = []
let candidat, present, limite // nombre candidat, est-ce qu'il est déjà présent, une limite d'itérations pour éviter les boucles infinies
limite = 0
for (let i = 0; i < nombreNotes;) {
limite += 1
if (distincts && limite < 100) { // Si les nombres doivent être tous distincts et que la limite d'itérations n'est pas encore atteinte,
candidat = randint(noteMin, noteMax) // on tire au sort un nombre candidat,
present = false
for (let j = 0; j < notes.length; j++) { // on vérifie s'il est présent,
if (candidat === notes[j]) {
present = true
break
}
}
if (!present) { // s'il n'est pas présent, on le push.
notes.push(candidat)
i++
}
} else { // Si les nombres n'ont pas tous à être distincts, on push directement.
notes.push(randint(noteMin, noteMax))
i++
}
}
return notes
}
/**
* Renvoie le nombre de jour d'un mois donné
* @param n quantième du mois (janvier=1...)
* @author Jean-Claude Lhote
*/
export function joursParMois (n, annee = 2022) {
const joursMois = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
if (n === 2) {
if (((annee % 4 === 0) && (annee % 100 !== 0)) || (annee % 400 === 0)) return 29 // années bissextiles.
else return 28
} else return joursMois[n - 1]
}
/**
* Renvoie un tableau de températures
* @param base température médiane
* @mois quantième du mois (janvier=1...)
* @annee pour déterminer si elle est bissextile ou non
* @author Jean-Claude Lhote
*/
export function unMoisDeTemperature (base, mois, annee) {
const temperatures = []
let nombreJours = joursParMois(mois)
if (mois === 2) {
if (((annee % 4 === 0) && (annee % 100 !== 0)) || (annee % 400 === 0)) nombreJours = 29 // années bissextiles.
else nombreJours = 28
}
temperatures.push(randint(-3, 3) + base)
for (let i = 1; i < nombreJours; i++) temperatures.push(temperatures[i - 1] + randint(-2, 2))
return temperatures
}
/**
* Renvoie le nom du mois
* @param n quantième du mois
* @author Jean-Claude Lhote
*/
export function nomDuMois (n) {
const mois = ['janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre']
return mois[n - 1]
}
/**
* Renvoie le nom du jour
* @param n quantième du jour
* @author Mireille Gain
*/
export function nomDuJour (n) {
const jour = ['lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi', 'dimanche']
return jour[n - 1]
}
/**
* Renvoie le nom d'un jour au hasard
* @param n quantième du jour
* @author Mireille Gain
*/
export function jour () {
return choice(['lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi', 'dimanche'])
}
// Fonctions LaTeX
/**
* * Retourne un environnement LaTeX enumerate à partir d'une liste.
* * `<br>`est remplacé par un saut de paragraphe
* * `<br><br>` est remplacé par un saut de paragraphe et un medskip
* * L'espacement est généré avec spacing
* @author Rémi Angot
*/
export function texEnumerate (liste, spacing) {
let result = ''
if (liste.length > 1) {
result = '\\begin{enumerate}\n'
if (spacing > 1) {
result += `\\begin{spacing}{${spacing}}\n`
}
for (const i in liste) {
result += '\t\\item ' + liste[i] + '\n'
}
if (spacing > 1) {
result += '\\end{spacing}\n'
}
result += '\\end{enumerate}\n'
} else {
if (spacing > 1) {
result += `\\begin{spacing}{${spacing}}\n`
}
result += liste[0] + '\n'
if (spacing > 1) {
result += '\\end{spacing}\n'
}
}
return result.replace(/(<br *\/?>[\n\t ]*)+<br *\/?>/mig, '\n\n\\medskip\n').replace(/<br>/g, '\\\\\n').replace(/€/g, '\\euro{}')
}
/**
* * Retourne un environnement LaTeX enumerate à partir d'une liste sans afficher les numéros.
* * `<br>` est remplacé par un saut de paragraphe
* * `<br><br>` est remplacé par un saut de paragraphe et un medskip
* * L'espacement est généré avec spacing
* @author Rémi Angot
*/
export function texEnumerateSansNumero (liste, spacing) {
// return texEnumerate(liste,spacing).replace('\\begin{enumerate}[label={}]','\\begin{enumerate}[label={}]')
return texEnumerate(liste, spacing).replace('\\begin{enumerate}', '\\begin{enumerate}[label={}]')
}
/**
* * Concatène les éléments d'une liste avec un saut de ligne entre chaque élément
* * `<br>` est remplacé par un saut de paragraphe
* * `<br><br>` est remplacé par un saut de paragraphe et un medskip
* @author Rémi Angot
*/
export function texParagraphe (liste, spacing = false, retourCharriot) {
let result = ''
if (spacing > 1) {
result = `\\begin{spacing}{${spacing}}\n`
}
for (const i in liste) {
if (retourCharriot) {
result += `\t${liste[i]}\\\\\n`
} else {
result += `\t${liste[i]}\n`
}
}
if (spacing > 1) {
result += '\\end{spacing}'
}
// les <br> peuvent être 2 ou plus et peuvent être séparés par des sauts de ligne ou des espaces
return result.replace(/(<br *\/?>[\n\t ]*)+<br *\/?>/mig, '\n\n\\medskip\n').replace(/<br>/g, '\\\\\n').replace(/€/g, '\\euro{}')
}
/**
* * Recopie le texte.
* * `<br>` est remplacé par un saut de paragraphe
* * `<br><br>` est remplacé par un saut de paragraphe et un medskip
* @author Rémi Angot
*/
export function texIntroduction (texte) {
return texte.replace(/(<br *\/?>[\n\t ]*)+<br *\/?>/mig, '\n\n\\medskip\n').replace(/<br>/g, '\\\\\n')
}
/**
* Renvoie une liste HTML à partir d'une liste
*
* @param liste une liste de questions
* @param spacing interligne (line-height en css)
* @author Rémi Angot
*/
export function htmlEnumerate (liste, spacing, classe = 'question', id = '', tailleDiaporama = 1, classeOl) {
let result = ''
// Pour diapCorr, on numérote les questions même si un exercice n'en comporte qu'une
if (liste.length > 1 || context.vue === 'diapCorr') {
(spacing > 1) ? result = `<ol style="line-height: ${spacing};" ${classeOl ? `class = ${classeOl}` : ''}>` : result = `<ol ${classeOl ? `class = ${classeOl}` : ''}>`
for (const i in liste) {
result += `<li class="${classe}" ${id ? 'id="' + id + i + '"' : ''} ${dataTaille(tailleDiaporama)}>` + liste[i].replace(/\\dotfill/g, '..............................').replace(/\\not=/g, '≠').replace(/\\ldots/g, '....') + '</li>' // .replace(/~/g,' ') pour enlever les ~ mais je voulais les garder dans les formules LaTeX donc abandonné
}
result += '</ol>'
} else if (liste.length === 1) {
// Pour garder la même hiérarchie avec une ou plusieurs questions
// On met ce div inutile comme ça le grand-père de la question est toujours l'exercice
// Utile pour la vue can
(spacing > 1) ? result = `<div><div class="${classe}" ${id ? 'id="' + id + '0"' : ''} style="line-height: ${spacing}; margin-bottom: 20px" ${dataTaille(tailleDiaporama)}>` : result = `<div><div class="${classe}" ${id ? 'id="' + id + '0"' : ''}>`
result += liste[0].replace(/\\dotfill/g, '..............................').replace(/\\not=/g, '≠').replace(/\\ldots/g, '....') // .replace(/~/g,' ') pour enlever les ~ mais je voulais les garder dans les formules LaTeX donc abandonné
result += '</div></div>'
}
return result
}
/**
* Renvoie une liste HTML ou LaTeX suivant le contexte
*
* @param liste une liste de questions
* @param spacing interligne (line-height en css)
* @author Rémi Angot
*/
export function enumerate (liste, spacing) {
if (context.isHtml) {
return htmlEnumerate(liste, spacing)
} else {
return texEnumerate(liste, spacing)
}
}
/**
* Renvoie une liste sans puce ni numéro HTML ou LaTeX suivant le contexte
*
* @param liste une liste de questions
* @param spacing interligne (line-height en css)
* @author Sébastien Lozano
*/
export function enumerateSansPuceSansNumero (liste, spacing) {
if (context.isHtml) {
// return htmlEnumerate(liste,spacing)
// for (let i=0; i<liste.length;i++) {
// liste[i]='> '+liste[i];
// }
return htmlLigne(liste, spacing)
} else {
// return texEnumerate(liste,spacing)
return texEnumerate(liste, spacing).replace('\\begin{enumerate}', '\\begin{enumerate}[label={}]')
}
}
/**
* Renvoie un paragraphe HTML à partir d'un string
*
* @param string
* @author Rémi Angot
*/
export function htmlParagraphe (texte, retourCharriot) {
if (texte.length > 1) {
if (retourCharriot) {
return `\n<p>${texte}</p>\n\n`
} else {
return `\n${texte}\n\n`
}
} else {
return ''
}
}
/**
* Renvoie un div HTML à partir d'une liste découpée par des sauts de ligne
*
* @param liste une liste de questions
* @param spacing interligne (line-height en css)
* @author Rémi Angot
*/
export function htmlLigne (liste, spacing, classe = 'question') {
let result = '<div>'
const spacingTxt = (spacing > 1) ? `style="line-height: ${spacing};"` : ''
// Pour garder la même hiérarchie avec listeDeQuestionsToContenu
// On met ce div inutile comme ça le grand-père de la question est toujours l'exercice
// Utile pour la vue can
for (const i in liste) {
result += '\t' + `<div ${spacingTxt} class="${classe}">` + liste[i].replace(/\\dotfill/g, '...') + '</div>' // .replace(/~/g,' ') pour enlever les ~ mais je voulais les garder dans les formules LaTeX donc abandonné
// .replace(/\\\\/g,'<br>') abandonné pour supporter les array
}
result += '</div></div>\n'
return result
}
/**
* Renvoie un environnent LaTeX multicolonnes
* @author Rémi Angot
*/
export function texMulticols (texte, nbCols = 2) {
let result
if (nbCols > 1) {
result = '\\begin{multicols}{' + nbCols + '}\n' +
texte + '\n\\end{multicols}'
} else {
result = texte
}
return result
}
/**
* Renvoie la consigne en titre 4
* @author Rémi Angot
*/
export function htmlConsigne (consigne) {
if (consigne) return '<h4>' + consigne + '</h4>\n\n'
else return ''
}
/**
* Renvoie \exo{consigne}
* @author Rémi Angot
*/
export function texConsigne (consigne) {
return '\\exo{' + consigne.replace(/<br>/g, '\\\\') + '}\n\n'
}
/**
* @author Frédéric Piou
* @param {number} nb
* @returns retourne un nombre au format français sans espace après la virgule
*/
export function num (nb) {
return Intl.NumberFormat('fr-FR', { maximumFractionDigits: 20 }).format(nb).toString().replace(/\s+/g, '\\thickspace ').replace(',', '{,}')
}
/**
* @author Frédéric Piou
* @param {number} nb
* @returns retourne un nombre au format français
*/
export function numberFormat (nb) {
return Intl.NumberFormat('fr-FR', { maximumFractionDigits: 20 }).format(nb).toString().replace(/\s+/g, '\\thickspace ')
}
/**
* La chaîne de caractères en sortie doit être interprétée par KateX et doit donc être placée entre des $ $
* Renvoie "Trop de chiffres" s'il y a plus de 15 chiffres significatifs (et donc un risque d'erreur d'approximation)
* S'utilise indifféremment avec des nombres (nb) au format natif (entier, flottant) ou au format Decimal (nécessite la librairie decimal.js)
* Avec comme avantage immédiat pour le format Decimal : precision est illimité.
* Sinon, renvoie un nombre dans le format français (avec une virgule et des espaces pour séparer les classes dans la partie entière et la partie décimale)
* @author Guillaume Valmont
* @param {number} nb nombre à afficher
* @param {number} precision nombre de décimales demandé
* @param {boolean} force true pour forcer à precision chiffres (ajout de zéros éventuels). false par défaut pour supprimer les zéros non significatifs.
* @returns string avec le nombre dans le format français à mettre entre des $ $
*/
export function texNombre (nb, precision = 8, force = false) {
const result = afficherNombre(nb, precision, 'texNombre', force)
return result.replace(',', '{,}').replace(/\s+/g, '\\,')
}
/**
* Renvoie un nombre dans le format français (séparateur de classes) pour la partie entière comme pour la partie décimale
* @author Rémi Angot
*/
export function texNombre2 (nb) {
let nombre = math.format(nb, { notation: 'auto', lowerExp: -12, upperExp: 12, precision: 12 }).replace('.', ',')
const rangVirgule = nombre.indexOf(',')
let partieEntiere = ''
if (rangVirgule !== -1) {
partieEntiere = nombre.substring(0, rangVirgule)
} else {
partieEntiere = nombre
}
let partieDecimale = ''
if (rangVirgule !== -1) {
partieDecimale = nombre.substring(rangVirgule + 1)
}
for (let i = partieEntiere.length - 3; i > 0; i -= 3) {
partieEntiere = partieEntiere.substring(0, i) + '\\,' + partieEntiere.substring(i)
}
for (let i = 3; i < partieDecimale.length; i += 5) {
partieDecimale = partieDecimale.substring(0, i) + '\\,' + partieDecimale.substring(i)
i += 12
}
if (partieDecimale === '') {
nombre = partieEntiere
} else {
nombre = partieEntiere + '{,}' + partieDecimale
}
return nombre
}
export function texNombrec2 (expr, precision = 12) {
return texNombre(expr, precision)
}
export function nombrec2 (nb) {
return math.evaluate(nb)
}
/**
* Renvoie un nombre dans le format français (séparateur de classes) pour la partie entière comme pour la partie décimale
* Avec espace géré par nbsp en HTML pour pouvoir l'inclure dans une phrase formatée en français et pas seulement un calcul.
* Modif EE pour la gestion de l'espace dans un texte non mathématique
* @author Eric Elter d'après la fonction de Rémi Angot
* Rajout Octobre 2021 pour 6C14
*/
export function texNombre3 (nb) {
let nombre = math.format(nb, { notation: 'auto', lowerExp: -12, upperExp: 12, precision: 12 }).replace('.', ',')
const rangVirgule = nombre.indexOf(',')
let partieEntiere = ''
if (rangVirgule !== -1) {
partieEntiere = nombre.substring(0, rangVirgule)
} else {
partieEntiere = nombre
}
let partieDecimale = ''
if (rangVirgule !== -1) {
partieDecimale = nombre.substring(rangVirgule + 1)
}
for (let i = partieEntiere.length - 3; i > 0; i -= 3) {
partieEntiere = partieEntiere.substring(0, i) + sp() + partieEntiere.substring(i)
}
for (let i = 3; i <= partieDecimale.length; i += 3) {
partieDecimale = partieDecimale.substring(0, i) + sp() + partieDecimale.substring(i)
i += 12
}
if (partieDecimale === '') {
nombre = partieEntiere
} else {
nombre = partieEntiere + ',' + partieDecimale
}
return nombre
}
/**
* Renvoie un espace insécable pour le mode texte suivant la sortie html ou Latex.
* @author Jean-Claude Lhote
*/
export function sp (nb = 1) {
let s = ''
for (let i = 0; i < nb; i++) {
if (context.isHtml) s += ' '
else s += '\\,'
}
return s
}
/**
* Renvoie un nombre dans le format français (séparateur de classes)
* Fonctionne sans le mode maths contrairement à texNombre()
* insereEspaceDansNombre fonctionne peut-être mieux
* @author Rémi Angot
*/
export function nombreAvecEspace (nb) {
if (isNaN(nb)) {
window.notify('nombreAvecEspace : argument NaN ou undefined', { nb })
return 'NaN'
}
// Ecrit \nombre{nb} pour tous les nombres supérieurs à 1 000 (pour la gestion des espaces)
if (context.isHtml) {
return Intl.NumberFormat('fr-FR', { maximumFractionDigits: 20 }).format(nb).toString().replace(/\s+/g, ' ')
} else {
let result
if (nb > 999 || nombreDeChiffresDansLaPartieDecimale(nb) > 3) {
result = '\\numprint{' + nb.toString().replace('.', ',') + '}'
} else {
result = Number(nb).toString().replace('.', '{,}')
}
return result
}
}
/**
*
* @param {number} mantisse
* @param {integer} exp
* @returns {string} Écriture décimale avec espaces
*/
/* export const scientifiqueToDecimal = (mantisse, exp) => {
mantisse = mantisse.toString()
let indiceVirguleDepart = mantisse.indexOf('.')
if (indiceVirguleDepart < 0) {
indiceVirguleDepart = mantisse.length
}
const indiceVirguleArrivee = indiceVirguleDepart + exp
let mantisseSansVirgule = mantisse.replace('.', '')
const indiceMax = mantisseSansVirgule.length - 1
// indiceMax est l'indice du chiffre des unités
if (indiceVirguleArrivee > indiceMax) {
// On ajoute des 0 à droite
for (let i = indiceMax + 1; i < indiceVirguleArrivee; i++) {
mantisseSansVirgule += '0'
}
} else if (indiceVirguleArrivee > 0 && indiceVirguleArrivee <= indiceMax) {
// On insère la virgule
mantisseSansVirgule = mantisseSansVirgule.substring(0, indiceVirguleArrivee) + ',' + mantisseSansVirgule.substring(indiceVirguleArrivee, mantisseSansVirgule.length)
} else {
// On ajoute des 0 à gauche
let partiGauche = '0,'
for (let i = 0; i < Math.abs(indiceVirguleArrivee); i++) {
partiGauche += '0'
}
mantisseSansVirgule = partiGauche + mantisseSansVirgule
}
return insereEspaceDansNombre(mantisseSansVirgule)
}
*/
export const scientifiqueToDecimal = (mantisse, exp) => {
if (exp < -6) Decimal.toExpNeg = exp - 1
else if (exp > 20) Decimal.toExpPos = exp + 1
return texNombre(new Decimal(mantisse).mul(Decimal.pow(10, exp)), 10)
}
/**
*
* @param {string |number} nb
* @returns {string}
*/
export const insereEspaceDansNombre = nb => {
if (!Number.isNaN(nb)) {
nb = nb.toString().replace('.', ',')
} else {
window.notify('insereEspaceDansNombre : l\'argument n\'est pas un nombre', nb)
return nb
}
let indiceVirgule = nb.indexOf(',')
const indiceMax = nb.length - 1
const tableauIndicesEspaces = []
if (indiceVirgule < 0) {
// S'il n'y a pas de virgule c'est qu'elle est après le dernier chiffre
indiceVirgule = nb.length
}
for (let i = 0; i < indiceMax; i++) {
if ((i - indiceVirgule) % 3 === 0 && (i - indiceVirgule) !== 0) {
if (i < indiceVirgule) {
tableauIndicesEspaces.push(i - 1) // Partie entière espace à gauche
} else {
tableauIndicesEspaces.push(i) // Partie décimale espace à droite
}
}
}
for (let i = tableauIndicesEspaces.length - 1; i >= 0; i--) {
const indice = tableauIndicesEspaces[i] + 1
if (indice !== 0)nb = insertCharInString(nb, indice, ' \\thickspace ')
}
return nb
}
export const insertCharInString = (string, index, char) => string.substring(0, index) + char + string.substring(index, string.length)
/**
* Destinée à être utilisée hors des $ $
* Signale une erreur en console s'il y a plus de 15 chiffres significatifs (et donc qu'il y a un risque d'erreur d'approximation)
* Sinon, renvoie le nombre à afficher dans le format français (avec virgule et des espaces pour séparer les classes dans la partie entière et la partie décimale)
* @author Jean-Claude Lhote
* @author Guillaume Valmont
* @param {number} nb nombre à afficher
* @param {number} precision nombre de décimales demandé
* @param {boolean} force true pour forcer à precision chiffres (ajout de zéros éventuels). false par défaut pour supprimer les zéros non significatifs.
* @returns string avec le nombre dans le format français à placer hors des $ $
*/
export function stringNombre (nb, precision = 8, force = false) {
return afficherNombre(nb, precision, 'stringNombre', force)
}
/**
* Fonction auxiliaire aux fonctions stringNombre et texNombre
* Vérifie le nombre de chiffres significatifs en fonction du nombre de chiffres de la partie entière de nb et du nombre de décimales demandées par le paramètre precision
* S'il y a plus de 15 chiffres significatifs, envoie un message à bugsnag et renvoie un nombre avec 15 chiffres significatifs
* Sinon, renvoie un nombre avec le nombre de décimales demandé
* @author Guillaume Valmont
* @param {number} nb nombre qu'on veut afficher
* @param {number} precision nombre de décimales demandé
* @param {string} fonction nom de la fonction qui appelle afficherNombre (texNombre ou stringNombre) -> sert pour le message envoyé à bugsnag
*/
function afficherNombre (nb, precision, fonction, force = false) {
/**
* Fonction auxiliaire de stringNombre pour une meilleure lisibilité
* Elle renvoie un nombre dans le format français (avec virgule et des espaces pour séparer les classes dans la partie entière et la partie décimale)
* @author Rémi Angot
* @author Guillaume Valmont
* @param {number} nb nombre à afficher
* @param {number} precision nombre de décimales demandé
* @returns string avec le nombre dans le format français
*/
function insereEspacesNombre (nb, nbChiffresPartieEntiere, precision, fonction) {
let signe
let nombre
const maximumSignificantDigits = nbChiffresPartieEntiere + precision
if (nb instanceof Decimal) {
signe = nb.isNeg()
if (nb.abs().gte(1)) {
if (force) {
nombre = nb.toFixed(precision).replace('.', ',')
} else {
nombre = nb.toDP(precision).toString().replace('.', ',')
}
} else {
if (force) {
nombre = nb.toFixed(precision).replace('.', ',')
} else {
nombre = nb.toDP(precision).toString().replace('.', ',')
}
}
} else {
signe = nb < 0
// let nombre = math.format(nb, { notation: 'fixed', lowerExp: -precision, upperExp: precision, precision: precision }).replace('.', ',')
if (Math.abs(nb) < 1) {
if (force) {
nombre = Intl.NumberFormat('fr-FR', { maximumFractionDigits: precision, minimumFractionDigits: precision }).format(nb)
} else {
nombre = Intl.NumberFormat('fr-FR', { maximumFractionDigits: precision }).format(nb)
}
} else {
if (force) {
nombre = Intl.NumberFormat('fr-FR', { maximumSignificantDigits, minimumSignificantDigits: maximumSignificantDigits }).format(nb)
} else {
nombre = Intl.NumberFormat('fr-FR', { maximumSignificantDigits }).format(nb)
}
}
}
const rangVirgule = nombre.indexOf(',')
let partieEntiere = ''
if (rangVirgule !== -1) {
partieEntiere = nombre.substring(0, rangVirgule)
} else {
partieEntiere = nombre
}
let partieDecimale = ''
if (rangVirgule !== -1) {
partieDecimale = nombre.substring(rangVirgule + 1)
}
// La partie entière est déjà formatée par le Intl.NumberFormat('fr-FR', { maximumSignificantDigits }).format(nb)
// Dans le cas d'un Number, mais pas d'un Decimal
if (nb instanceof Decimal) {
if (signe) partieEntiere = partieEntiere.substring(1)
for (let i = partieEntiere.length - 3; i > 0; i -= 3) {
partieEntiere = partieEntiere.substring(0, i) + ' ' + partieEntiere.substring(i)
}
if (signe) partieEntiere = '-' + partieEntiere
}
for (let i = 3; i < partieDecimale.length; i += (fonction === 'texNombre' ? 5 : 4)) { // des paquets de 3 nombres + 1 espace
partieDecimale = partieDecimale.substring(0, i) + (fonction === 'texNombre' ? '\\,' : ' ') + partieDecimale.substring(i)
}
if (partieDecimale === '') {
nombre = partieEntiere
} else {
nombre = partieEntiere + ',' + partieDecimale
}
return nombre
} // fin insereEspacesNombre()
// si nb n'est pas un nombre, on le retourne tel quel, on ne fait rien.
if (isNaN(nb) && !(nb instanceof Decimal)) {
window.notify("AfficherNombre : Le nombre n'en est pas un", { nb, precision, fonction })
return ''
}
if (nb instanceof Decimal) {
if (nb.isZero()) return '0'
} else if (Number(nb) === 0) return '0'
let nbChiffresPartieEntiere
if (nb instanceof Decimal) {
if (nb.abs().lt(1)) {
nbChiffresPartieEntiere = 0
} else {
nbChiffresPartieEntiere = nb.abs().toFixed(0).length
}
if (nb.isInteger()) precision = 0
else {
if (typeof precision !== 'number') { // Si precision n'est pas un nombre, on le remplace par la valeur max acceptable
precision = 15 - nbChiffresPartieEntiere
} else if (precision < 0) {
precision = 0
}
}
} else {
if (Math.abs(nb) < 1) {
nbChiffresPartieEntiere = 0
} else {
// attention 9.7 donner 10 avec Math.abs(9.7).toFixed(0)
nbChiffresPartieEntiere = Math.floor(Math.abs(nb)).toFixed(0).length
}
if (Number.isInteger(nb) && !force) {
precision = 0
} else {
if (typeof precision !== 'number') { // Si precision n'est pas un nombre, on le remplace par la valeur max acceptable
precision = 15 - nbChiffresPartieEntiere
} else if (precision < 0) {
precision = 0
}
}
}
const maximumSignificantDigits = nbChiffresPartieEntiere + precision
if ((maximumSignificantDigits > 15) && (!(nb instanceof Decimal))) { // au delà de 15 chiffres significatifs, on risque des erreurs d'arrondi
window.notify(fonction + ` : ${tropDeChiffres}`, { nb, precision })
return insereEspacesNombre(nb, nbChiffresPartieEntiere, precision, fonction)
} else {
return insereEspacesNombre(nb, nbChiffresPartieEntiere, precision, fonction)
}
}
/**
* Centre un texte
*
* @author Rémi Angot
*/
export function texteCentre (texte) {
if (context.isHtml) {
return `<p style="text-align: center">${texte}</p>`
} else {
return `\\begin{center}
${texte}
\\end{center}`
}
}
/**
* Met en couleur et en gras
*
* Met en couleur et gras un texte. JCL dit : "S'utilise entre $ car utilise des commandes qui fonctionnent en math inline"
* @param {string} texte à mettre en couleur
* @param {string} couleur en anglais ou code couleur hexadécimal par défaut c'est le orange de CoopMaths
* @author Rémi Angot
*/
export function miseEnEvidence (texte, couleur = '#f15929') {
if (context.isHtml) {
return `{\\color{${couleur}}\\boldsymbol{${texte}}}`
} else {
if (couleur[0] === '#') {
return `{\\color[HTML]{${couleur.replace('#', '')}}\\boldsymbol{${texte}}}`
} else {
return `{\\color{${couleur.replace('#', '')}}\\boldsymbol{${texte}}}`
}
}
}
/**
* Met en couleur
* Met en couleur un texte. JCL dit : "S'utilise entre $ car utilise des commandes qui fonctionnent en math inline"
* @param {string} texte à mettre en couleur
* @param {string} couleur en anglais ou code couleur hexadécimal par défaut c'est le orange de CoopMaths
* @author Guillaume Valmont d'après MiseEnEvidence() de Rémi Angot
*/
export function miseEnCouleur (texte, couleur = '#f15929') {
if (context.isHtml) {
return `{\\color{${couleur}} ${texte}}`
} else {
if (couleur[0] === '#') {
return `{\\color[HTML]{${couleur.replace('#', '')}} ${texte}}`
} else {
return `{\\color{${couleur.replace('#', '')}} ${texte}}`
}
}
}
/**
* Met en couleur un texte
* @param {string} texte à mettre en couleur
* @param {string} couleur en anglais ou code couleur hexadécimal par défaut c'est le orange de CoopMaths
* @author Rémi Angot
*/
export function texteEnCouleur (texte, couleur = '#f15929') {
if (context.isHtml) {
return `<span style="color:${couleur};">${texte}</span>`
} else {
if (couleur[0] === '#') {
return `{\\color[HTML]{${couleur.replace('#', '')}}${texte}}`
} else {
return `{\\color{${couleur.replace('#', '')}}${texte}}`
}
}
}
/**
* Met en couleur et gras un texte. JCL dit : "Ne fonctionne qu'en dehors de $....$". Utiliser miseEnEvidence si $....$.
* @param {string} texte à mettre en couleur
* @param {string} couleur en anglais ou code couleur hexadécimal par défaut c'est le orange de CoopMaths
* @author Rémi Angot
*/
export function texteEnCouleurEtGras (texte, couleur = '#f15929') {
if (context.isHtml) {
return `<span style="color:${couleur};font-weight: bold;">${texte}</span>`
} else {
if (couleur[0] === '#') {
return `{\\bfseries \\color[HTML]{${couleur.replace('#', '')}}${texte}}`
} else {
return `{\\bfseries \\color{${couleur.replace('#', '')}}${texte}}`
}
}
}
/**
* couleurAleatoire() renvoie le code d'une couleur au hasard
*
* @author Rémi Angot
*/
export function couleurAleatoire () {
return choice(['white', 'black', 'red', 'green', 'blue', 'cyan', 'magenta', 'yellow'])
}
/**
* couleurTab() renvoie :
* soit le code d'une couleur au hasard, ainsi que sa traduction française au masculin et au féminin,
* soit le code d'une couleur imposée, ainsi que sa traduction française au masculin et au féminin.
* @example couleurTab() peut renvoyer ['black','noir','noire'].
* @example couleurTab(0) renverra de façon certaine ['black','noir','noire'].
* @author Eric Elter
*/
export function couleurTab (choixCouleur = 999) {
const panelCouleurs = [
['black', 'noir', 'noire'],
['red', 'rouge', 'rouge'],
['green', 'vert', 'verte'],
['blue', 'bleu', 'bleue'],
['HotPink', 'rose', 'rose'],
['Sienna', 'marron', 'marron'],
['darkgray', 'gris', 'grise'],
['DarkOrange', 'orange', 'orange']
]
return (choixCouleur === 999 || choixCouleur >= panelCouleurs.length || !isInteger(choixCouleur)) ? choice(panelCouleurs) : panelCouleurs[choixCouleur]
}
export function arcenciel (i, fondblanc = true) {
let couleurs
if (fondblanc) couleurs = ['violet', 'purple', 'blue', 'green', 'lime', '#f15929', 'red']
else couleurs = ['violet', 'indigo', 'blue', 'green', 'yellow', '#f15929', 'red']
return couleurs[i % 7]
}
export function texcolors (i, fondblanc = true) {
const couleurs = ['black', 'blue', 'GreenYellow', 'brown', 'LightSlateBlue', 'cyan', 'darkgray', 'HotPink', 'LightSteelBlue', 'Chocolate', 'gray', 'green', 'lightgray', 'lime', 'magenta', 'olive', 'DarkOrange', 'pink', 'purple', 'red', 'teal', 'violet', 'white', 'yellow']
if (fondblanc && i % couleurs.length >= couleurs.length - 2) i += 2
return couleurs[i % couleurs.length]
}
/**
* Met gras un texte
* @param {string} texte à mettre en gras
* @author Rémi Angot
*/
export function texteGras (texte) {
if (context.isHtml) {
return `<b>${texte}</b>`
} else {
return `\\textbf{${texte}}`
}
}
/**
* Affiche un lien vers une URL
* @param {string} texte à afficher
* @param {string} URL
* @author Rémi Angot
*/
export function href (texte, lien) {
if (context.isHtml) {
return `<a target="_blank" href=${lien}> ${texte} </a>`
} else {
return `\\href{${lien}}{${texte}}`
}
}
/**
* Pour bien afficher les centimes avec 2 chiffres après la virgule
* @author Rémi Angot
*/
export function texPrix (nb) {
// Remplace le . par la ,
if (nb instanceof Decimal) {
if (nb.isInteger()) return texNombre(nb, 0)
else return texNombre(nb, 2, true)
}
const nombre = Number(nb)
let result
if (nombre.toString() === nombre.toFixed(0)) {
result = nombre
} else {
result = nombre.toFixed(2).toString().replace('.', '{,}') // Ne gère pas l'espace des milliers
}
return result
}
/**
* Pour afficher les masses avec 3 chiffres après la virgule
* @author Mireille Gain
*/
export function texMasse (nb) {
// Remplace le . par la ,
const nombre = Number(nb)
let result
if (nombre.toString() === nombre.toFixed(0)) {
result = nombre
} else {
result = nombre.toFixed(3).toString().replace('.', ',') // Ne gère pas l'espace des milliers
}
return result
}
/**
* Convertit en majuscule la première lettre
* @author Rémi Angot
*/
export function premiereLettreEnMajuscule (text) { return (text + '').charAt(0).toUpperCase() + text.substr(1) }
/**
* Renvoie le nombre de chiffres de la partie décimale
* @param nb : nombre décimal
* @param except : chiffre à ne pas compter (0 par exemple) [Ajout EE]
* @author Rémi Angot
*/
export function nombreDeChiffresDansLaPartieDecimale (nb, except = 'aucune') {
let sauf = 0
if (String(nb).indexOf('.') > 0) {
if (!isNaN(except)) sauf = (String(nb).split('.')[1].split(String(except)).length - 1)
return String(nb).split('.')[1].length - sauf
} else {
return 0
}
}
/**
* Renvoie le nombre de chiffres dans la partie entière
* @author ?
*/
export function nombreDeChiffresDansLaPartieEntiere (nb, except = 'aucune') {
let nombre; let sauf = 0
if (nb < 0) {
nombre = -nb
} else {
nombre = nb
}
if (String(nombre).indexOf('.') > 0) {
if (!isNaN(except)) sauf = (String(nombre).split('.')[0].split(String(except)).length - 1)
return String(nombre).split('.')[0].length - sauf
} else {
if (!isNaN(except)) sauf = (String(nombre).split(String(except)).length - 1)
return String(nombre).length
}
}
/**
* Renvoie le nombre de chiffres d'un nombre décimal
* @param nb : nombre décimal
* @param except : chiffre à ne pas compter (0 par exemple) [Ajout EE]
* @author Jean-Claude Lhote
*/
export function nombreDeChiffresDe (nb, except) {
return nombreDeChiffresDansLaPartieDecimale(nb, except) + nombreDeChiffresDansLaPartieEntiere(nb, except)
}
/**
* Retourne la string LaTeX de la fraction
* @param num
* @param den
* @return {string}
* @author Jean-Claude Lhote
*/
export function texFractionSigne (num, den) {
if (den === 1) return String(num)
if (num * den > 0) {
return `\\dfrac{${texNombre(Math.abs(num))}}{${texNombre(Math.abs(den))}}`
}
if (num * den < 0) {
return `-\\dfrac{${texNombre(Math.abs(num))}}{${texNombre(Math.abs(den))}}`
}
return '0'
}
/**
* Met de grandes parenthèses autour de la fraction a/b si besoin pour inclure une fraction dans une expresion en fonction du signe
* @author Jean-Claude Lhote
*/
export function texFractionParentheses (a, b) {
if (a * b > 0) { return texFractionSigne(a, b) } else { return '\\left(' + texFractionSigne(a, b) + '\\right)' }
}
/**
* Retourne une liste de fractions irréductibles
* @author Jean-Claude Lhote
*/
export function obtenirListeFractionsIrreductibles () { // sous forme de tableaux [numérateur,dénominateur]
return [[1, 2], [1, 3], [2, 3], [1, 4], [3, 4], [1, 5], [2, 5], [3, 5], [4, 5],
[1, 6], [5, 6], [1, 7], [2, 7], [3, 7], [4, 7], [5, 7], [6, 7], [1, 8], [3, 8], [5, 8], [7, 8],
[1, 9], [2, 9], [4, 9], [5, 9], [7, 9], [8, 9], [1, 10], [3, 10], [7, 10], [9, 10]]
}
/**
* Retourne une liste de fractions irréductibles de dénominateur égal à 2 3 5 7
* @author Mireille Gain
*/
export function obtenirListeFractionsIrreductiblesFaciles () { // sous forme de tableaux [numérateur,dénominateur]
return [[1, 2], [1, 3], [2, 3], [1, 5], [2, 5], [3, 5], [4, 5],
[1, 7], [2, 7], [3, 7], [4, 7], [5, 7], [6, 7]]
}
/**
* Retourne la liste des nombres premiers inférieurs à 300
* @author Rémi Angot
*/
export function obtenirListeNombresPremiers (n = 300) {
const prems = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293]
for (let i = 307; i <= n; i++) {
if (isPrime(i)) prems.push(i)
}
return prems
}
/**
* Retourne le code LaTeX de la décomposition en produit de facteurs premiers d'un nombre
* @author Rémi Angot
*/
export function decompositionFacteursPremiers (n) {
let decomposition = ''
const liste = obtenirListeFacteursPremiers(n)
for (const i in liste) {
decomposition += liste[i] + '\\times'
}
decomposition = decomposition.substr(0, decomposition.length - 6)
return decomposition
}
/**
* Renvoie la décomposition en produit de facteurs premiers d'un nombre avec les facteursABarrer barrés
* @author Guillaume Valmont
* @param {number} nombre
* @param {number[]} facteursABarrer
* @returns texte en LateX
*/
export function decompositionFacteursPremiersBarres (nombreADecomposer, facteursABarrer) {
const decomposition = decompositionFacteursPremiersArray(nombreADecomposer)
const facteursBarres = []
let str = ''
for (const nombre of decomposition) {
let unNombreAEteBarre = false
for (let i = 0; i < facteursABarrer.length; i++) {
const facteurABarrer = facteursABarrer[i]
if (nombre === facteurABarrer && !facteursBarres.includes(i) && !unNombreAEteBarre) {
str += ` \\cancel{${facteurABarrer}} \\times `
facteursBarres.push(i)
unNombreAEteBarre = true
}
}
if (!unNombreAEteBarre) {
str += nombre + ' \\times '
}
}
return str.slice(0, -8)
}
/**
* Retourne la liste des diviseurs d'un entier
* @author Rémi Angot
*/
export function listeDesDiviseurs (n) {
let k = 2
const liste = [1]
while (k <= n) {
if (n % k === 0) {
liste.push(k)
}
k++
}
return liste
}
/**
* Retourne le code LaTeX d'une fraction a/b
* @author Rémi Angot
*/
export function texFraction (a, b) {
if (b !== 1) {
return `\\dfrac{${typeof a === 'number' ? texNombre(a) : a}}{${typeof b === 'number' ? texNombre(b) : b}}`
} else {
return a
}
}
/**
* Retourne le code LateX correspondant à un symbole
* @param {string} symbole
* @returns {string} string
* @author Guillaume Valmont
* @example texSymbole('≤') retourne '\\leqslant'
*/
export function texSymbole (symbole) {
switch (symbole) {
case '<':
return '<'
case '>':
return '>'
case '≤':
return '\\leqslant'
case '≥':
return '\\geqslant'
case '\\':
return '\\smallsetminus'
default:
return 'symbole non connu par texSymbole()'
}
}
/**
* Utilise printlatex et quote de Algebrite
* @author Rémi Angot
*/
export function printlatex (e) {
if (e === '0x') {
return '0'
} else {
return Algebrite.run(`printlatex(quote(${e}))`)
}
}
/**
* Écrit du texte en mode mathématiques
* @author Rémi Angot
*/
export function texTexte (texte) {
return '~\\text{' + texte + '}'
}
/**
* Retourne un environnement LaTeX itemize à partir d'une liste
* @author Rémi Angot
*/
export function itemize (tableauDeTexte) {
let texte = ''
if (context.isHtml) {
texte = '<div>'
for (let i = 0; i < tableauDeTexte.length; i++) {
texte += '<div> − ' + tableauDeTexte[i] + '</div>'
}
texte += '</div>'
} else {
texte = '\t\\begin{itemize}\n'
for (let i = 0; i < tableauDeTexte.length; i++) {
texte += '\t\t\\item ' + tableauDeTexte[i] + '\n'
}
texte += '\t\\end{itemize}'
}
return texte
}
/**
* Utilise pgfplots pour tracer la courbe représentative de f dans le repère avec -10 < x < 10 et -8 < y < 8
*
* @param string expression de fonction
* @author Rémi Angot
*/
export function texGraphique (f, xmin = -5, xmax = 5, ymin = -5, ymax = 5) {
return `
\\pgfplotsset{width=10cm,
compat=1.9,
every axis/.append style={
axis x line=middle, % put the x axis in the middle
axis y line=middle, % put the y axis in the middle
xlabel={$x$}, % default put x on x-axis
ylabel={$y$}, % default put y on y-axis
label style={font=\\tiny},
tick label style={font=\\tiny},
xlabel style={above right},
ylabel style={above right},
grid = major,
xtick distance=1,
ytick distance=1,
}}
\\begin{tikzpicture}
\\begin{axis}[
xmin = ${xmin}, xmax = ${xmax}, ymin = ${ymin}, ymax = ${ymax},
]
\\addplot [
ultra thick,
blue,
samples=100,
domain=${xmin}:${xmax},
]{${f}};
\\end{axis}
\\end{tikzpicture}`
}
/**
* Classe MatriceCarree
* Générateur de Matrice :
* Si l'argument est un nombre, alors on s'en sert pour définir la taille de la matrice carrée qu'on rempli de zéros.
* Sinon, c'est le tableau qui sert à remplir la Matrice
* @author Jean-Claude Lhote
*/
export class MatriceCarree {
constructor (table) {
let ligne
this.table = []
if (typeof (table) === 'number') {
this.dim = table // si c'est un nombre qui est passé en argument, c'est la taille, et on rempli la table de 0
for (let i = 0; i < this.dim; i++) {
ligne = []
for (let j = 0; j < this.dim; j++) { ligne.push(0) }
this.table.push(ligne)
}
} else { // si l'argument est une table, on la copie dans this.table et sa longueur donne la dimension de la matrice
this.dim = table.length
this.table = table.slice()
}
/**
* Méthode : Calcule le déterminant de la matrice carrée
* @author Jean-Claude Lhote
*/
this.determinant = function () {
const n = this.dim // taille de la matrice = nxn
let determinant = 0; let M
for (let i = 0; i < n; i++) { // on travaille sur la ligne du haut de la matrice :ligne 0 i est la colonne de 0 à n-1
// if (n==1) determinant=this.table[0][0]
if (n === 2) { determinant = this.table[0][0] * this.table[1][1] - this.table[1][0] * this.table[0][1] } else {
M = this.matriceReduite(0, i)
determinant += ((-1) ** i) * this.table[0][i] * M.determinant()
}
}
return determinant
}
/**
* Méthode : m=M.matriceReduite(l,c) retourne une nouvelle matrice obtenue à partir de la matrice M (carrée) en enlevant la ligne l et la colonne c
* (Utilisée dans le calcul du déterminant d'une matrice carrée.)
* @author Jean-Claude Lhote
*/
this.matriceReduite = function (l, c) {
const resultat = []; let ligne
for (let i = 0; i < this.table.length; i++) {
if (i !== l) {
ligne = []
for (let j = 0; j < this.table.length; j++) {
if (j !== c) ligne.push(this.table[i][j])
}
if (ligne.length > 0) resultat.push(ligne)
}
}
return matriceCarree(resultat)
}
/**
* Méthode : m=M.cofacteurs() retourne la matrice des cofacteurs de M utilisée dans l'inversion de M.
*/
this.cofacteurs = function () { // renvoie la matrice des cofacteurs.
const n = this.dim; let resultat = []; let ligne; let M
if (n > 2) {
for (let i = 0; i < n; i++) {
ligne = []
for (let j = 0; j < n; j++) {
M = this.matriceReduite(i, j)
ligne.push((-1) ** (i + j) * M.determinant())
}
resultat.push(ligne)
}
} else if (n === 2) {
resultat = [[this.table[1][1], -this.table[1][0]], [-this.table[0][1], this.table[0][0]]]
} else return false
return matriceCarree(resultat)
}
/**
* Méthode : m=M.transposee() retourne la matrice transposée de M utilisée pour l'inversion de M
*/
this.transposee = function () { // retourne la matrice transposée
const n = this.dim; const resultat = []; let ligne
for (let i = 0; i < n; i++) {
ligne = []
for (let j = 0; j < n; j++) {
ligne.push(this.table[j][i])
}
resultat.push(ligne)
}
return matriceCarree(resultat)
}
/**
* m=M.multiplieParReel(k) Multiplie tous les éléments de la matrice par k. Utilisée pour l'inversion de M
* @param {*} k
*/
this.multiplieParReel = function (k) { // retourne k * la matrice
const n = this.dim; const resultat = []; let ligne
for (let i = 0; i < n; i++) {
ligne = []
for (let j = 0; j < n; j++) {
ligne.push(k * this.table[i][j])
}
resultat.push(ligne)
}
return matriceCarree(resultat)
}
/**
* Méthode : Calcule le produit d'une matrice nxn par un vecteur 1xn (matrice colonne): retourne un vecteur 1xn.
*
*/
this.multiplieVecteur = function (V) { // Vecteur est un simple array pour l'instant
const n = this.dim; const resultat = []; let somme
if (n === V.length) {
for (let i = 0; i < n; i++) {
somme = 0
for (let j = 0; j < n; j++) {
somme += this.table[i][j] * V[j]
}
resultat.push(somme)
}
return resultat
} else return false
}
/**
* Méthode : m=M.inverse() Retourne la matrice inverse de M. Utilisation : résolution de systèmes linéaires
*/
this.inverse = function () { // retourne la matrice inverse (si elle existe)
const d = this.determinant()
if (!egal(d, 0)) {
return this.cofacteurs().transposee().multiplieParReel(1 / d)
} else return false
}
/**
* Méthode : m=M.multiplieMatriceCarree(P) : retourne m = M.P
*
*/
this.multiplieMatriceCarree = function (M) {
const n = this.dim; const resultat = []; let ligne; let somme
for (let i = 0; i < n; i++) {
ligne = []
for (let j = 0; j < n; j++) {
somme = 0
for (let k = 0; k < n; k++) somme += this.table[i][k] * M.table[k][j]
ligne.push(somme)
}
resultat.push(ligne)
}
return matriceCarree(resultat)
}
this.toTex = function () {
let matrice = this.table
matrice = matrix(matrice)
matrice = matrice.toString()
matrice = parse(matrice).toTex().replaceAll('bmatrix', 'pmatrix')
return matrice
}
}
}
/**
* Crée une nouvelle instance de la classe MatriceCarree à partir d'un tableau.
*
*/
export function matriceCarree (table) {
return new MatriceCarree(table)
}
// Fin de la classe MAtriceCarree
/**
* Fonction qui retourne les coefficients a et b de f(x)=ax²+bx+c à partir des données de x1,x2,f(x1),f(x2) et c.
*
* @author Jean-Claude Lhote
*/
export function resolutionSystemeLineaire2x2 (x1, x2, fx1, fx2, c) {
const matrice = matriceCarree([[x1 ** 2, x1], [x2 ** 2, x2]])
const determinant = matrice.determinant()
const [a, b] = matrice.cofacteurs().transposee().multiplieVecteur([fx1 - c, fx2 - c])
if (Number.isInteger(a) && Number.isInteger(b) && Number.isInteger(determinant)) {
const fa = fraction(a, determinant)
const fb = fraction(b, determinant)
return [[fa.numIrred, fa.denIrred], [fb.numIrred, fb.denIrred]]
}
return [[a / determinant, 1], [b / determinant, 1]]
}
/**
* Fonction qui retourne les coefficients a, b et c de f(x)=ax^3 + bx² + cx + d à partir des données de x1,x2,x3,f(x1),f(x2),f(x3) et d (entiers !)
* sous forme de fraction irréductible. Si pas de solution (déterminant nul) alors retourne [[0,0],[0,0],[0,0]]
* @author Jean-Claude Lhote
*/
export function resolutionSystemeLineaire3x3 (x1, x2, x3, fx1, fx2, fx3, d) {
const matrice = matriceCarree([[x1 ** 3, x1 ** 2, x1], [x2 ** 3, x2 ** 2, x2], [x3 ** 3, x3 ** 2, x3]])
const y1 = fx1 - d; const y2 = fx2 - d; const y3 = fx3 - d
const determinant = matrice.determinant()
if (determinant === 0) {
return [[0, 0], [0, 0], [0, 0]]
}
const [a, b, c] = matrice.cofacteurs().transposee().multiplieVecteur([y1, y2, y3])
if (Number.isInteger(a) && Number.isInteger(b) && Number.isInteger(c) && Number.isInteger(determinant)) { // ici on retourne un tableau de couples [num,den] entiers !
const fa = fraction(a, determinant)
const fb = fraction(b, determinant)
const fc = fraction(c, determinant)
return [
[fa.numIrred, fa.denIrred],
[fb.numIrred, fb.denIrred],
[fc.numIrred, fc.denIrred]
]
// pour l'instant on ne manipule que des entiers, mais on peut imaginer que ce ne soit pas le cas... dans ce cas, la forme est numérateur = nombre & dénominateur=1
}
return [
[a / determinant, 1],
[b / determinant, 1],
[b / determinant, 1]
]
}
/**
* Fonction qui cherche une fonction polynomiale de degré 3 dont les coefficients a, b et c de f(x)=ax^3 + bx² + cx + d
* sont des fractions dont le dénominateur est inférieur à 10 et pour laquelle l'image de 3 entiers compris entre -10 et 10
* sont des entiers compris eux aussi entre -10 et 10
* @author Jean-Claude Lhote
*/
export function criblePolynomeEntier () {
let trouve = false
let coefs = [[]]
for (let i = 0, x1, x2, x3, fx1, fx2, fx3, d; ; i++) {
x1 = randint(-10, 10)
x2 = randint(-10, 10, [x1])
x3 = randint(-10, 10, [x1, x2])
fx1 = randint(-10, 10)
fx2 = randint(-10, 10)
fx3 = randint(-10, 10)
d = randint(0, 10)
coefs = resolutionSystemeLineaire3x3(x1, x2, x3, fx1, fx2, fx3, d)
if (coefs[0][1] !== 0 && coefs[0][1] < 10 && coefs[1][1] < 10 && coefs[2][1] < 10) trouve = true
if (trouve) {
coefs.push([x1, fx1])
coefs.push([x2, fx2])
coefs.push([x3, fx3])
coefs.push(d)
break
}
}
if (trouve) return coefs
}
/**
* Fonction qui cherche les minimas et maximas d'une fonction polynomiale f(x)=ax^3 + bx² + cx + d
* retourne [] si il n'y en a pas, sinon retourne [[x1,f(x1)],[x2,f(x2)] ne précise pas si il s'agit d'un minima ou d'un maxima.
* @author Jean-Claude Lhote
*/
export function chercheMinMaxFonction ([a, b, c, d]) {
const delta = 4 * b * b - 12 * a * c
if (delta <= 0) return [[0, 10 ** 99], [0, 10 ** 99]]
const x1 = (-2 * b - Math.sqrt(delta)) / (6 * a)
const x2 = (-2 * b + Math.sqrt(delta)) / (6 * a)
return [[x1, a * x1 ** 3 + b * x1 ** 2 + c * x1 + d], [x2, a * x2 ** 3 + b * x2 ** 2 + c * x2 + d]]
}
/**
* retourne les coefficients d'un polynome de degré 3 dont la dérivée s'annule en x1 et x2 et tel que f(x1)=y1 et f(x2)=y2.
* @author Jean-Claude Lhote
*/
export function cherchePolynomeDegre3aExtremaFixes (x1, x2, y1, y2) {
const M = matriceCarree([[x1 ** 3, x1 ** 2, x1, 1], [x2 ** 3, x2 ** 2, x2, 1], [3 * x1 ** 2, 2 * x1, 1, 0], [3 * x2 ** 2, 2 * x2, 1, 0]])
const R = [y1, y2, 0, 0]
if (!egal(M.determinant(), 0)) return M.inverse().multiplieVecteur(R)
else return false
}
/**
* Fonction pour simplifier l'ecriture lorsque l'exposant vaut 0 ou 1
* retourne 1, la base ou rien
* @param b base
* @param e exposant
* @author Sébastien Lozano
*/
export function simpExp (b, e) {
switch (e) {
case 1:
return ` ${b}`
case 0:
return ' 1'
default:
return ' '
}
}
/**
* Fonction pour écrire des notations scientifique de la forme a * b ^ n
* @param a {number} mantisse
* @param b {number} base
* @param n {number} exposant
* @author Erwan Duplessy
*/
export function puissance (b, n) {
switch (b) {
case 0:
return '0'
case 1:
return '1'
case -1:
if (b % 2 === 0) {
return '1'
} else {
return '-1'
}
default:
if (b < 0) {
return `(${b})^{${n}}`
} else {
return `${b}^{${n}}`
}
}
}
export function ecriturePuissance (a, b, n) {
switch (a) {
case 0:
return '$0$'
case 1:
return `$${puissance(b, n)}$`
default:
return `$${String(round(a, 3)).replace('.', '{,}')} \\times ${puissance(b, n)}$`.replace('.', '{,}')
}
}
/**
* Fonction pour simplifier les notations puissance dans certains cas
* si la base vaut 1 ou -1 quelque soit l'exposant, retourne 1 ou -1,
* si la base est négative on teste la parité de l'exposant pour alléger la notation sans le signe
* si l'exposant vaut 0 ou 1 retourne 1, la base ou rien
* @param b base
* @param e exposant
* @author Sébastien Lozano
*/
export function simpNotPuissance (b, e) {
// on switch sur la base
switch (b) {
case -1: // si la base vaut -1 on teste la parité de l'exposant
if (e % 2 === 0) {
return ' 1'
// break;
} else {
return ' -1'
// break;
}
case 1: // si la base vaut 1 on renvoit toujours 1
return ' 1'
default: // sinon on switch sur l'exposant
switch (e) {
case 0: // si l'exposant vaut 0 on ranvoit toujours 1
return '1'
case 1: // si l'exposant vaut 1 on renvoit toujours la base
return ` ${b}`
default: // sinon on teste le signe de la base et la parité de l'exposant
if (b < 0 && e % 2 === 0) { // si la base est négative et que l'exposant est pair, le signe est inutile
return ` ${b * -1}^{${e}}`
// break;
} else {
return ` ${b}^{${e}}`
// return ` `;
// break;
}
}
}
}
/**
* Fonction pour écrire en couleur la forme éclatée d'une puissance
* @param b base
* @param e exposant
* @param couleur
* @author Sébastien Lozano
*/
export function eclatePuissance (b, e, couleur) {
let str
switch (e) {
case 0:
return `\\mathbf{\\color{${couleur}}{1}}`
case 1:
return `\\mathbf{\\color{${couleur}}{${b}}}`
default:
str = `\\mathbf{\\color{${couleur}}{${b}}} `
for (let i = 1; i < e; i++) {
str = str + `\\times \\mathbf{\\color{${couleur}}{${b}}}`
}
return str
}
}
/**
* Fonction pour écrire la forme éclatée d'une puissance
* @param b {number} base
* @param e {integer} exposant
* @author Rémi Angot
* @return string
*/
export function puissanceEnProduit (b, e) {
let str
if (e === 0) {
return '1'
} else if (e === 1) {
return `${b}`
} else if (e > 1) {
str = `${ecritureParentheseSiNegatif(b)}`
for (let i = 1; i < e; i++) {
str = str + `\\times ${ecritureParentheseSiNegatif(b)}`
}
return str
} else if (e < 0) {
return `\\dfrac{1}{${puissanceEnProduit(b, -e)}}`
}
}
/**
* Fonction qui renvoie un tableau contenant la mantisse et l'exposant de l'écriture scientique d'un nombre donné en paramètres sous sa forme décimale.
* @param nbDecimal
*
* @example
* // Renvoie [4.1276,1]
* range(decimalToScientifique,[41.276])
* // Renvoie [3.48,-2]
* range(decimalToScientifique,[0.0348])
* // Renvoie [-2.315,3]
* range(decimalToScientifique,[-2315])
*
* @author Eric Elter
*/
export function decimalToScientifique (nbDecimal) {
let exposant = 0
let mantisseNb = new Decimal(nbDecimal)
if (mantisseNb.abs().gte(10)) {
while (exposant < 50 && mantisseNb.abs().gt(10)) {
mantisseNb = mantisseNb.div(10)
exposant++
}
return [mantisseNb.toNumber(), exposant]
} else if (mantisseNb.abs().lt(1)) {
while (exposant < 50 && mantisseNb.abs().lt(1)) {
mantisseNb = mantisseNb.mul(10)
exposant++
}
return [mantisseNb.toNumber(), -1 * exposant]
} else return [nbDecimal, 0]
}
/**
* Fonction pour écrire avec deux couleurs la forme éclatée d'un produit de puissances de même exposant
* @param b1 base1
* @param b2 base2
* @param e exposant
* @param couleur1
* @param couleur2
* @author Sébastien Lozano
*/
export function reorganiseProduitPuissance (b1, b2, e, couleur1, couleur2) {
let str
switch (e) {
case 0:
return '1'
case 1:
return `\\mathbf{\\color{${couleur1}}{${b1}}} \\times \\mathbf{\\color{${couleur2}}{${b2}}}`
default:
str = `\\mathbf{(\\color{${couleur1}}{${b1}}} \\times \\mathbf{\\color{${couleur2}}{${b2}}}) `
for (let i = 1; i < e; i++) {
str = str + `\\times (\\mathbf{\\color{${couleur1}}{${b1}}} \\times \\mathbf{\\color{${couleur2}}{${b2}}})`
}
return str
}
}
/**
*
* x le nombre dont on cherche l'ordre de grandeur
* type = 0 pour la puissance de 10 inférieure, 1 pour la puissance de 10 supérieur et 2 pour la plus proche
*/
export function ordreDeGrandeur (x, type) {
let signe
if (x < 0) signe = -1
else signe = 1
x = Math.abs(x)
const P = 10 ** Math.floor(Math.log10(x))
if (type === 0) return P * signe
else if (type === 1) return P * 10 * signe
else if (x - P < 10 * P - x) return P * signe
else return P * 10 * signe
}
/**
* Fonction créant le bouton d'aide utilisée par les différentes fonctions modal_ type de contenu
* @param numeroExercice
* @param contenu code HTML
* @param icone
* @author Rémi Angot
*/
export function creerModal (numeroExercice, contenu, labelBouton, icone) {
if (context.isHtml) {
const HTML = `<button class="ui right floated mini compact button" onclick="$('#modal${numeroExercice}').modal('show');"><i class="large ${icone} icon"></i>${labelBouton}</button>
<div class="ui modal" id="modal${numeroExercice}">
${contenu}
</div>`
return HTML
} else {
return ''
}
}
/**
* Fonction créant le bouton d'aide utilisée par les différentes fonctions modal_ type de contenu
* @param numeroExercice
* @param contenu code HTML
* @param icone
* @author Rémi Angot
*/
export function creerBoutonMathalea2d (numeroExercice, fonction, labelBouton = 'Aide', icone = 'info circle') {
if (context.versionMathalea === 3) {
return `<button class="inline-block px-6 py-2.5 mr-10 my-5 ml-6 bg-coopmaths text-white font-medium text-xs leading-tight uppercase rounded shadow-md transform hover:scale-110 hover:bg-coopmaths-dark hover:shadow-lg focus:bg-coopmaths-dark focus:shadow-lg focus:outline-none focus:ring-0 active:bg-coopmaths-dark active:shadow-lg transition duration-150 ease-in-out" id = "btnMathALEA2d_${numeroExercice}" onclick="${fonction}"><i class="large ${icone} icon"></i>${labelBouton}</button>`
} else {
return `<button class="ui toggle left floated mini compact button" id = "btnMathALEA2d_${numeroExercice}" onclick="${fonction}"><i class="large ${icone} icon"></i>${labelBouton}</button>`
}
}
/**
* Créé un bouton pour une aide modale avec un texte court
* @param numeroExercice
* @param texte Texte court qui sera affiché comme un titre
* @param labelBouton Titre du bouton (par défaut Aide)
* @param icone Nom de l'icone (par défaut c'est info circle icon), liste complète sur https://semantic-ui.com/elements/icon.html
* @author Rémi Angot
*/
export function modalTexteCourt (numeroExercice, texte, labelBouton = 'Aide', icone = 'info circle') {
const contenu = `<div class="header">${texte}</div>`
return creerModal(numeroExercice, contenu, labelBouton, icone)
}
/**
* Créé un bouton pour une aide modale avec un texte et une vidéo YouTube
* @param numeroExercice
* @param idYoutube
* @param titre Texte court qui sera affiché comme un titre
* @param labelBouton Titre du bouton (par défaut Aide)
* @param icone Nom de l'icone (par défaut c'est youtube icon), liste complète sur https://semantic-ui.com/elements/icon.html
* @author Rémi Angot
*/
export function modalYoutube (numeroExercice, idYoutube, titre, labelBouton = 'Aide - Vidéo', icone = 'youtube') {
let contenu
if (idYoutube.substr(0, 4) === 'http') {
if (idYoutube.slice(-4) === '.pdf') {
contenu = `<div class="header">${titre}</div><div class="content"><p align="center"><object type="application/pdf" data="${idYoutube}" width="560" height="315"> </object></p></div>`
}
if (idYoutube.substr(0, 17) === 'https://youtu.be/') {
contenu = `<div class="header">${titre}</div><div class="content"><p align="center"><iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/${idYoutube.substring(17)}" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></p></div>`
} else {
contenu = `<div class="header">${titre}</div><div class="content"><p align="center"><iframe width="560" height="315" sandbox="allow-same-origin allow-scripts allow-popups" src="${idYoutube}" frameborder="0" allowfullscreen></iframe></p></div>`
}
} else if (idYoutube.substr(0, 4) === '<ifr') {
contenu = `<div class="header">${titre}</div><div class="content"><p align="center">${idYoutube}</p></div>`
} else {
contenu = `<div class="header">${titre}</div><div class="content"><p align="center"><iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/${idYoutube}?rel=0&showinfo=0" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></p></div>`
}
return creerModal(numeroExercice, contenu, labelBouton, icone)
}
/**
* Créé un bouton pour une aide modale avec un titre et un texte
* @param numeroExercice
* @param titre
* @param texte
* @param labelBouton Titre du bouton (par défaut Aide)
* @param icone Nom de l'icone (par défaut c'est info circle icon), liste complète sur https://semantic-ui.com/elements/icon.html
* @author Rémi Angot
*/
export function modalTexteLong (numeroExercice, titre, texte, labelBouton = 'Aide', icone = 'info circle') {
let contenu = `<div class="header">${titre}</div>`
contenu += `<div class="content">${texte}</div>`
return creerModal(numeroExercice, contenu, labelBouton, icone)
}
/**
* Créé un bouton pour une aide modale avec un titre et un texte
* @param numeroExercice
* @param url
* @param labelBouton Titre du bouton (par défaut Aide)
* @param icone Nom de l'icone (par défaut c'est info circle icon), liste complète sur https://semantic-ui.com/elements/icon.html
* @author Rémi Angot
*/
export function modalUrl (numeroExercice, url, labelBouton = 'Aide', icone = 'info circle') {
const contenu = `<iframe width="100%" height="600" src="${url}" frameborder="0" ></iframe>`
return creerModal(numeroExercice, contenu, labelBouton, icone)
}
/**
* Créé un bouton pour une aide modale avec un texte et une vidéo YouTube
* @param numeroExercice
* @param urlPdf
* @param titre Texte court qui sera affiché comme un titre
* @param labelBouton Titre du bouton (par défaut Aide)
* @param icone Nom de l'icone (par défaut c'est file pdf icon), liste complète sur https://semantic-ui.com/elements/icon.html
* @author Rémi Angot
*/
export function modalPdf (numeroExercice, urlPdf, titre = 'Aide', labelBouton = 'Aide - PDF', icone = 'file pdf') {
const contenu = `<div class="header">${titre}</div><div class="content"><p align="center"><embed src=${urlPdf} width=90% height=500 type='application/pdf'/></p></div>`
return creerModal(numeroExercice, contenu, labelBouton, icone)
}
/**
* Créé un bouton pour une aide modale avec une vidéo
* @param numeroExercice désigne l'id du modal qui doit être unique
* @param urlVideo
* @param titre Texte court qui sera affiché comme un titre
* @param labelBouton Titre du bouton (par défaut Vidéo)
* @param icone Nom de l'icone (par défaut c'est file video outline icon), liste complète sur https://semantic-ui.com/elements/icon.html
* @author Sébastien Lozano
*/
export function modalVideo (numeroExercice, urlVideo, titre, labelBouton = 'Vidéo', icone = 'file video outline') {
// let contenu = `<div class="header">${titre}</div><div class="content"><p align="center"><iframe width="560" height="315" src="${urlVideo}" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></p></div>`
const contenu = `
<div class="header">${titre}</div>
<div class="content">
<div class="embed-responsive embed-responsive-16by9" align="center">
<video width="560" height="315" controls preload="none" style="max-width: 100%">
<source src="` + urlVideo + `">
Votre navigateur ne gère pas l'élément <code>video</code>.
</video>
</div>
</div>`
return creerModal(numeroExercice, contenu, labelBouton, icone)
}
/**
*
* @param {number} numeroExercice
* @param {string} urlImage
* @param {string} titre = ce qui est écrit en titre de l'image
* @param {string} labelBouton = ce qui est écrit sur le bouton à côté de l'icône d'image.
* @param {string} icone
*/
export function modalImage (numeroExercice, urlImage, titre, labelBouton = 'Illustration', icone = 'image') {
const contenu = `<div class="header">${titre}</div><div class="image content"><img class="ui centered medium image" src="${urlImage}"></div>`
return creerModal(numeroExercice, contenu, labelBouton, icone)
}
/**
* Renvoie un tableau contenant les diviseurs d'un nombre entier, rangés dans l'ordre croissant
* @param {integer} n
* @author Sébastien Lozano
*/
export function listeDiviseurs (n) {
'use strict'
let i = 2
const diviseurs = [1]
while (i <= n) {
if (n % i === 0) {
diviseurs.push(i)
}
i++
}
return diviseurs
}
//= ================================================
// fonctions de 3F1-act
//= ================================================
/**
* Crée une machine mathématique Tikz pour la version LaTeX
* @param {string} nom nom de la machine en mode maths!
* @param {string} etape1 chaine en mode maths attention aux espaces et accents
* @param {string} etape2 chaine en mode maths attention aux espaces et accents
* @param {string} etape3 chaine en mode maths attention aux espaces et accents
* @param {string} xLigne1 chaine en mode maths attention aux espaces et accents
* @param {string} xLigne2 chaine en mode maths attention aux espaces et accents
* @param {string} yLigne1 chaine en mode maths attention aux espaces et accents
* @param {string} yLigne2 chaine en mode maths attention aux espaces et accents
* @author Sébastien Lozano
*/
export function tikzMachineMaths (nom, etape1, etape2, etape3, xLigne1, xLigne2, yLigne1, yLigne2) {
// tous les textes sont en mode maths !!!
'use strict'
return `
\\definecolor{frvzsz}{rgb}{0.9450980392156862,0.34901960784313724,0.1607843137254902}
\\begin{tikzpicture}[line cap=round,line join=round,>=triangle 45,x=1cm,y=1cm]
\\draw [line width=3pt,color=frvzsz] (-4,4)-- (2,4);
\\draw [line width=3pt,color=frvzsz] (2,4)-- (2,0);
\\draw [line width=3pt,color=frvzsz] (2,0)-- (-4,0);
\\draw [line width=3pt,color=frvzsz] (-4,0)-- (-4,4);
\\draw [line width=3pt,color=frvzsz] (-4,2)-- (-5,2);
\\draw [line width=3pt,color=frvzsz] (-5,2.4)-- (-5,1.6);
\\draw [->,line width=3pt,color=frvzsz] (2,2) -- (3,2);
\\node[text width=3cm,text centered, scale=1.8] at(-1,3.5){$\\mathbf{machine\\,${nom}}$};
\\node[text width=3cm,text centered, scale=1.5] at(-1,2.8){$\\mathbf{${etape1}}$};
\\node[text width=3cm,text centered, scale=1.5] at(-1,2.3){$${etape2}$};
\\node[text width=3cm,text centered, scale=1.5] at(-1,1.6){$${etape3}$};
\\node[text width=3cm,text centered, scale=1.5] at(-8,2.5) {$\\mathbf{${xLigne1}}$};
\\node[text width=3cm,text centered, scale=1.5] at(-8,1.5) {$\\mathbf{${xLigne2}}$};
\\fill [line width=3pt,color=frvzsz] (-6,2) -- (-6.5,1) -- (-5.5,2) -- (-6.5,3) -- cycle;
%\\fill [line width=3pt,color=frvzsz] (1,2) -- (0.5,1) -- (1.5,2) -- (0.5,3) -- cycle;
\\node[text width=3cm,text centered, scale=1.5] at(5.5,2.5) {$\\mathbf{${yLigne1}}$};
\\node[text width=3cm,text centered, scale=1.5] at(5.5,1.5) {$\\mathbf{${yLigne2}}$};
\\fill [line width=3pt,color=frvzsz] (3.5,2) -- (3,1) -- (4,2) -- (3,3) -- cycle;
\\end{tikzpicture}
`
}
/**
* Crée un diagramme tikz pour une machine maths
* @param {string} nom nom de la fonction
* @param {string} xAnt nom du nombre de départ
* @param {array} etapesExpressions tableau contenant les etapes et le expressions algébriques
* attention mode maths pour les chaines
* @author Sébastien Lozano
*/
export function tikzMachineDiag (nom, xAnt, etapesExpressions) {
'use strict'
const xInit = -10
let saut = 0
const pas = 1
let sortie = ''
sortie += `
\\definecolor{frvzsz}{rgb}{0.9450980392156862,0.34901960784313724,0.1607843137254902}
\\begin{tikzpicture}[line cap=round,line join=round,>=triangle 45,x=1cm,y=1cm]
\\draw [line width=3pt,color=frvzsz] (` + xInit + ',0.5) -- (' + (xInit + pas) + ',0.5) -- (' + (xInit + pas) + ',-0.5) -- (' + xInit + `,-0.5) -- cycle;
\\node[text width=3cm,text centered, scale=1] at(` + (xInit + 0.5) + `,0){$${xAnt}$};
`
saut = saut + pas
for (let i = 0; i < etapesExpressions.length; i++) {
// si la longueur du tableau des etapes vaut i+1 c'est que c'est la derniere
// on affiche donc chaque fois avec le nom de la fonction
if (etapesExpressions.length === i + 1) {
// si il y a une operation et une expression algébrique
if (typeof etapesExpressions[i][0] !== 'undefined' && typeof etapesExpressions[i][1] !== 'undefined') {
const wEtape = `${nom}(x)=${etapesExpressions[i][1]}}`.length
sortie += `
\\draw [line width=3pt,color=frvzsz] (` + (xInit + saut) + ',0) -- (' + (xInit + saut + pas / 2) + `,0);
\\draw [line width=3pt,color=frvzsz] (` + (xInit + saut + pas) + `,0) circle(0.5);
\\node [text width=3cm,text centered, scale=1] at(` + (xInit + saut + pas) + `,0){$${etapesExpressions[i][0]}$};
\\draw [->,line width=3pt,color=frvzsz] (` + (xInit + saut + 3 * pas / 2) + ',0) -- (' + (xInit + saut + 5 * pas / 2) + `,0);
\\draw [line width=3pt,color=frvzsz] (` + (xInit + saut + 5 * pas / 2) + ',0.5) -- (' + (xInit + saut + wEtape / 4 + 6 * pas / 2) + ',0.5) -- (' + (xInit + saut + wEtape / 4 + 6 * pas / 2) + ',-0.5) -- (' + (xInit + saut + 5 * pas / 2) + `,-0.5) -- cycle;
\\node [text width=3cm,text centered, scale=1] at(` + (xInit + saut + wEtape / 8 + 5.5 * pas / 2) + `,0){$${nom}(` + xAnt + `)=${etapesExpressions[i][1]}$};
`
}
// si il y a une operation et pas d'expression algébrique
if (typeof etapesExpressions[i][0] !== 'undefined' && typeof etapesExpressions[i][1] === 'undefined') {
const wEtape = `${nom}(x)=\\ldots`.length
sortie += `
\\draw [line width=3pt,color=frvzsz] (` + (xInit + saut) + ',0) -- (' + (xInit + saut + pas / 2) + `,0);
\\draw [line width=3pt,color=frvzsz] (` + (xInit + saut + pas) + ',0) circle(' + (pas / 2) + `);
\\node [text width=3cm,text centered, scale=1] at(` + (xInit + saut + pas) + `,0){$${etapesExpressions[i][0]}$};
\\draw [->,line width=3pt,color=frvzsz] (` + (xInit + saut + 3 * pas / 2) + ',0) -- (' + (xInit + saut + 5 * pas / 2) + `,0);
\\draw [line width=3pt,color=frvzsz] (` + (xInit + saut + 5 * pas / 2) + ',' + (pas / 2) + ') -- (' + (xInit + saut + wEtape / 4 + 6 * pas / 2) + ',' + (pas / 2) + ') -- (' + (xInit + saut + wEtape / 4 + 6 * pas / 2) + ',-' + (pas / 2) + ') -- (' + (xInit + saut + 5 * pas / 2) + ',-' + (pas / 2) + `) -- cycle;
\\node [text width=3cm,text centered, scale=1] at(` + (xInit + saut + wEtape / 8 + 5.5 * pas / 2) + `,0){$${nom}(` + xAnt + `)=\\ldots$};
`
}
// si il n'y a pas d'operation mais une expression algébrique
if (typeof etapesExpressions[i][0] === 'undefined' && typeof etapesExpressions[i][1] !== 'undefined') {
const wEtape = `${nom}(x)=${etapesExpressions[i][1]}`.length
sortie += `
\\draw [line width=3pt,color=frvzsz] (` + (xInit + saut) + ',0) -- (' + (xInit + saut + pas / 2) + `,0);
\\draw [line width=3pt,color=frvzsz] (` + (xInit + saut + pas) + ',0) circle(' + (pas / 2) + `);
\\node [text width=3cm,text centered, scale=1] at(` + (xInit + saut + pas) + `,0){$\\ldots$};
\\draw [->,line width=3pt,color=frvzsz] (` + (xInit + saut + 3 * pas / 2) + ',0) -- (' + (xInit + saut + 5 * pas / 2) + `,0);
\\draw [line width=3pt,color=frvzsz] (` + (xInit + saut + 5 * pas / 2) + ',' + (pas / 2) + ') -- (' + (xInit + saut + wEtape / 4 + 6 * pas / 2) + ',' + (pas / 2) + ') -- (' + (xInit + saut + wEtape / 4 + 6 * pas / 2) + ',-' + (pas / 2) + ') -- (' + (xInit + saut + 5 * pas / 2) + ',-' + (pas / 2) + `) -- cycle;
\\node [text width=3cm,text centered, scale=1] at(` + (xInit + saut + wEtape / 8 + 5.5 * pas / 2) + `,0){$${nom}(` + xAnt + `)=${etapesExpressions[i][1]}$};
`
}
// si il n'y ni une operation et ni expression algébrique
if (typeof etapesExpressions[i][0] === 'undefined' && typeof etapesExpressions[i][1] === 'undefined') {
const wEtape = `${nom}(x)=\\ldots`.length
sortie += `
\\draw [line width=3pt,color=frvzsz] (` + (xInit + saut) + ',0) -- (' + (xInit + saut + pas / 2) + `,0);
\\draw [line width=3pt,color=frvzsz] (` + (xInit + saut + pas) + ',0) circle(' + (pas / 2) + `);
\\node [text width=3cm,text centered, scale=1] at(` + (xInit + saut + pas) + `,0){$\\ldots$};
\\draw [->,line width=3pt,color=frvzsz] (` + (xInit + saut + 3 * pas / 2) + ',0) -- (' + (xInit + saut + 5 * pas / 2) + `,0);
\\draw [line width=3pt,color=frvzsz] (` + (xInit + saut + 5 * pas / 2) + ',' + (pas / 2) + ') -- (' + (xInit + saut + wEtape / 4 + 6 * pas / 2) + ',' + (pas / 2) + ') -- (' + (xInit + saut + wEtape / 4 + 6 * pas / 2) + ',-' + (pas / 2) + ') -- (' + (xInit + saut + 5 * pas / 2) + ',-' + (pas / 2) + `) -- cycle;
\\node [text width=3cm,text centered, scale=1] at(` + (xInit + saut + wEtape / 8 + 5.5 * pas / 2) + `,0){$${nom}(` + xAnt + `)=\\ldots$};
`
}
} else { // sinon c'est une étape intermédiaire
// si il y a une operation et une expression algébrique
if (typeof etapesExpressions[i][0] !== 'undefined' && typeof etapesExpressions[i][1] !== 'undefined') {
const wEtape = `${etapesExpressions[i][1]}`.length
sortie += `
\\draw [line width=3pt,color=frvzsz] (` + (xInit + saut) + ',0) -- (' + (xInit + saut + pas / 2) + `,0);
\\draw [line width=3pt,color=frvzsz] (` + (xInit + saut + pas) + ',0) circle(' + (pas / 2) + `);
\\node [text width=3cm,text centered, scale=1] at(` + (xInit + saut + pas) + `,0){$${etapesExpressions[i][0]}$};
\\draw [->,line width=3pt,color=frvzsz] (` + (xInit + saut + 3 * pas / 2) + ',0) -- (' + (xInit + saut + 5 * pas / 2) + `,0);
\\draw [line width=3pt,color=frvzsz] (` + (xInit + saut + 5 * pas / 2) + ',' + (pas / 2) + ') -- (' + (xInit + saut + wEtape / 4 + 6 * pas / 2) + ',' + (pas / 2) + ') -- (' + (xInit + saut + wEtape / 4 + 6 * pas / 2) + ',-' + (pas / 2) + ') -- (' + (xInit + saut + 5 * pas / 2) + ',-' + (pas / 2) + `) -- cycle;
\\node [text width=3cm,text centered, scale=1] at(` + (xInit + saut + wEtape / 8 + 5.5 * pas / 2) + `,0){$${etapesExpressions[i][1]}$};
`
saut = saut + 3 * pas + wEtape / 4
}
// si il y a une operation et pas d'expression algébrique
if (typeof etapesExpressions[i][0] !== 'undefined' && typeof etapesExpressions[i][1] === 'undefined') {
const wEtape = '\\ldots'.length
sortie += `
\\draw [line width=3pt,color=frvzsz] (` + (xInit + saut) + ',0) -- (' + (xInit + saut + pas / 2) + `,0);
\\draw [line width=3pt,color=frvzsz] (` + (xInit + saut + pas) + ',0) circle(' + (pas / 2) + `);
\\node [text width=3cm,text centered, scale=1] at(` + (xInit + saut + pas) + `,0){$${etapesExpressions[i][0]}$};
\\draw [->,line width=3pt,color=frvzsz] (` + (xInit + saut + 3 * pas / 2) + ',0) -- (' + (xInit + saut + 5 * pas / 2) + `,0);
\\draw [line width=3pt,color=frvzsz] (` + (xInit + saut + 5 * pas / 2) + ',' + (pas / 2) + ') -- (' + (xInit + saut + wEtape / 4 + 6 * pas / 2) + ',' + (pas / 2) + ') -- (' + (xInit + saut + wEtape / 4 + 6 * pas / 2) + ',-' + (pas / 2) + ') -- (' + (xInit + saut + 5 * pas / 2) + ',-' + (pas / 2) + `) -- cycle;
\\node [text width=3cm,text centered, scale=1] at(` + (xInit + saut + wEtape / 8 + 5.5 * pas / 2) + `,0){$\\ldots$};
`
saut = saut + 3 * pas + wEtape / 4
}
// si il n'y a pas d'operation mais une expression algébrique
if (typeof etapesExpressions[i][0] === 'undefined' && typeof etapesExpressions[i][1] !== 'undefined') {
const wEtape = `${etapesExpressions[i][1]}`.length
sortie += `
\\draw [line width=3pt,color=frvzsz] (` + (xInit + saut) + ',0) -- (' + (xInit + saut + pas / 2) + `,0);
\\draw [line width=3pt,color=frvzsz] (` + (xInit + saut + pas) + ',0) circle(' + (pas / 2) + `);
\\node [text width=3cm,text centered, scale=1] at(` + (xInit + saut + pas) + `,0){$\\ldots$};
\\draw [->,line width=3pt,color=frvzsz] (` + (xInit + saut + 3 * pas / 2) + ',0) -- (' + (xInit + saut + 5 * pas / 2) + `,0);
\\draw [line width=3pt,color=frvzsz] (` + (xInit + saut + 5 * pas / 2) + ',' + (pas / 2) + ') -- (' + (xInit + saut + wEtape / 4 + 6 * pas / 2) + ',' + (pas / 2) + ') -- (' + (xInit + saut + wEtape / 4 + 6 * pas / 2) + ',-' + (pas / 2) + ') -- (' + (xInit + saut + 5 * pas / 2) + ',-' + (pas / 2) + `) -- cycle;
\\node [text width=3cm,text centered, scale=1] at(` + (xInit + saut + wEtape / 8 + 5.5 * pas / 2) + `,0){$${etapesExpressions[i][1]}$};
`
saut = saut + 3 * pas + wEtape / 4
}
// si il n'y ni une operation et ni expression algébrique
if (typeof etapesExpressions[i][0] === 'undefined' && typeof etapesExpressions[i][1] === 'undefined') {
const wEtape = '\\ldots'.length
sortie += `
\\draw [line width=3pt,color=frvzsz] (` + (xInit + saut) + ',0) -- (' + (xInit + saut + pas / 2) + `,0);
\\draw [line width=3pt,color=frvzsz] (` + (xInit + saut + pas) + ',0) circle(' + (pas / 2) + `);
\\node [text width=3cm,text centered, scale=1] at(` + (xInit + saut + pas) + `,0){$\\ldots$};
\\draw [->,line width=3pt,color=frvzsz] (` + (xInit + saut + 3 * pas / 2) + ',0) -- (' + (xInit + saut + 5 * pas / 2) + `,0);
\\draw [line width=3pt,color=frvzsz] (` + (xInit + saut + 5 * pas / 2) + ',' + (pas / 2) + ') -- (' + (xInit + saut + wEtape / 4 + 6 * pas / 2) + ',' + (pas / 2) + ') -- (' + (xInit + saut + wEtape / 4 + 6 * pas / 2) + ',-' + (pas / 2) + ') -- (' + (xInit + saut + 5 * pas / 2) + ',-' + (pas / 2) + `) -- cycle;
\\node [text width=3cm,text centered, scale=1] at(` + (xInit + saut + wEtape / 8 + 5.5 * pas / 2) + `,0){$\\ldots$};
`
saut = saut + 3 * pas + wEtape / 4
}
}
}
sortie += `
\\end{tikzpicture}
`
return sortie
}
/**
* Crée un popup html avec un icon info, éventuellement avec du contenu LaTeX
* @param {string} texte
* @param {string} titrePopup
* @param {string} textePopup
* @author Sébastien Lozano
*/
export function katexPopup (texte, titrePopup, textePopup) {
'use strict'
let contenu = ''
if (context.isHtml) {
contenu = '<div class="mini ui right labeled icon button katexPopup"><i class="info circle icon"></i> ' + texte + '</div>'
contenu += '<div class="ui special popup" >'
if (titrePopup !== '') {
contenu += '<div class="header">' + titrePopup + '</div>'
}
contenu += '<div>' + textePopup + '</div>'
contenu += '</div>'
return contenu
} else {
return `\\textbf{${texte}} \\footnote{\\textbf{${titrePopup}} ${textePopup}}`
}
}
export function katexPopupTest (texte, titrePopup, textePopup) {
'use strict'
let contenu = ''
if (context.isHtml) {
contenu = '<div class="ui right label katexPopup">' + texte + '</div>'
contenu += '<div class="ui special popup" >'
if (titrePopup !== '') {
contenu += '<div class="header">' + titrePopup + '</div>'
}
contenu += '<div>' + textePopup + '</div>'
contenu += '</div>'
return contenu
} else {
return `\\textbf{${texte}} \\footnote{\\textbf{${titrePopup}} ${textePopup}}`
}
}
/**
* Ecrit un string sans accents
* @param {string} str
* @author Sébastien Lozano
* @source --> http://www.finalclap.com/faq/257-javascript-supprimer-remplacer-accent
*/
/* export function sansAccent(str) {
var accent = [
/[\300-\306]/g, /[\340-\346]/g,
/[\310-\313]/g, /[\350-\353]/g,
/[\314-\317]/g, /[\354-\357]/g,
/[\322-\330]/g, /[\362-\370]/g,
/[\331-\334]/g, /[\371-\374]/g,
/[\321]/g, /[\361]/g,
/[\307]/g, /[\347]/g,
];
var noaccent = ['A', 'a', 'E', 'e', 'I', 'i', 'O', 'o', 'U', 'u', 'N', 'n', 'C', 'c'];
//var str = this;
for (var i = 0; i < accent.length; i++) {
str = str.replace(accent[i], noaccent[i]);
}
return str;
}
*/
/**
* Crée un popup html avec une icône info ou un bouton modal suivant le type donné :0=Latex inline compatible, 1=bouton modal texte long, 2=bouton modal image.
* ATTENTION la variable texte doit exactement correspondre au nom de l'image sans l'extension et etre au format png
* @param {number} numero
* @param {number} type
* @param {string} titrePopup = Le titre du texte dévoilé par le bouton
* @param {string} texte = Ce qu'il y a sur le bouton qui doit exactement etre le nom de l'image sans l'extension
* @param {string} textePopup = Le texte dévoilé par le bouton ou l'url de l'image.
* @author Jean-claude Lhote & Rémi Angot & Sebastien Lozano
**/
export function katexPopup2 (numero, type, texte, titrePopup, textePopup) {
'use strict'
switch (type) {
case 0:
return katexPopupTest(texte, titrePopup, textePopup)
case 1:
if (context.isHtml) {
return `${texte}` + modalTexteLong(numero, `${titrePopup}`, `${textePopup}`, `${texte}`, 'info circle')
} else {
return `\\textbf{${texte}} \\footnote{\\textbf{${titrePopup}} ${textePopup}}`
}
case 2:
if (context.isHtml) {
return `${texte}` + modalImage(numero, textePopup, `${titrePopup}`, `${texte}`)
} else {
return `\\href{https://coopmaths.fr/images/${texte}.png}{\\textcolor{blue}{\\underline{${texte}}} } \\footnote{\\textbf{${texte}} ${textePopup}}`
}
}
}
/**
* Crée une liste de questions alphabétique
* @param {number} k valeur numérique
* @author Sébastien Lozano (Rajout par EE, l'opportunité d'enlever l'espace final qui est par défaut)
*/
export function numAlpha (k, nospace = false) {
if (context.isHtml) return '<span style="color:#f15929; font-weight:bold">' + String.fromCharCode(97 + k) + ')' + (nospace ? '' : ' ') + '</span>'
else return '\\textbf {' + String.fromCharCode(97 + k) + '.}' + (nospace ? '' : ' ')
}
/**
* crée un cadre orange autour d'un paragraphe
* utilisé notamment dans 3F12 pour entourer les programmes de calcul
* @param {string} texte paragraphe entouré par le cadre orange rectangulaire
* @author Sébastien Lozano
*/
export function texCadreParOrange (texte) {
'use strict'
// \\definecolor{orangeCoop}{rgb}{0.9450980392156862,0.34901960784313724,0.1607843137254902}
const sortie = `
\\setlength{\\fboxrule}{1.5mm}
\\par\\vspace{0.25cm}
\\noindent\\fcolorbox{nombres}{white}{\\parbox{\\linewidth-2\\fboxrule-2\\fboxsep}{` + texte + `}}
\\par\\vspace{0.25cm}
`
return sortie
}
/**
* affiche une video centrée dans une div
* ATTENTION BUG SVG DONC LES ANIMATIONS SONT FILMEES A PARTIR DE CELLES GENEREES PAR LA FONCTION SVG_machine_maths() SOUS FIREFOX
* DE FACON A AVOIR UN RENDU UNIFORME QUEL QUE SOIT LE NAVIGATEUR ON REND LES ANIMATIONS PAR DES VIDEOS
* ON LAISSE LA PIROUETTE DE DETECTION DU USERAGENT EN COMMENTAIRE EN ATTENDANT DE TROUVER UNE SOLUTION DE RENDU LATEX DANS SVG UNIVERSELLE
* @param {string} urlVideo
* @author Sébastien Lozano
*/
export function machineMathsVideo (urlVideo) {
'use strict'
const video = `
<div style="text-align:center">
<video width="560" height="100%" controls loop autoplay muted style="max-width: 100%">
<source src="` + urlVideo + `">
Votre navigateur ne gère pas l'élément <code>video</code>.
</video>
</div>`
return video
}
/**
* détecte si le navigateur et safari ou chrome et renvoie un booléen
* @author Sébastien Lozano
*/
export function detectSafariChromeBrowser () {
'use strict'
let isChrome = navigator.userAgent.indexOf('Chrome') > -1
// var is_explorer = navigator.userAgent.indexOf('MSIE') > -1;
// var is_firefox = navigator.userAgent.indexOf('Firefox') > -1;
let isSafari = navigator.userAgent.indexOf('Safari') > -1
const isOpera = navigator.userAgent.toLowerCase().indexOf('op') > -1
if ((isChrome) && (isSafari)) { isSafari = false }
if ((isChrome) && (isOpera)) { isChrome = false }
return (isChrome || isSafari)
}
/**
* Retourne la liste des nombres premiers inférieurs à N N<300 N exclu
* @param {integer} k On cherchera un multiple de k
* @param {integer} n Ce multiple sera supérieur ou égal à n
* @author Rémi Angot
*/
export function premierMultipleSuperieur (k, n) {
let result = n
let reste
if (Number.isInteger(k) && Number.isInteger(n)) {
while (result % k !== 0) {
result += 1
}
return result
} else {
if (egal(Math.floor((n / k), n / k))) return n
else {
reste = n / k - Math.floor(n / k)
return n - reste * k + k
}
}
}
export function premierMultipleInferieur (k, n) {
const result = premierMultipleSuperieur(k, n)
if (result !== n) return result - k
else return n
}
/**
* Retourne la liste des nombres premiers inférieurs à N N<300 N exclu
* @param {number} borneSup
* @author Sébastien Lozano
*/
export function listeNombresPremiersStrictJusqua (borneSup) {
'use strict'
// tableau contenant les 300 premiers nombres premiers
const liste300 = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293]
const liste = []
let i = 0
while (liste300[i] < borneSup) {
liste.push(liste300[i])
i++
}
return liste
}
/**
* Liste les nombres premiers jusque n avec la méthode du crible d'Eratosthene optimisée
* @param {number} n
* @author Sébastien Lozano
*/
export function cribleEratostheneN (n) {
'use strict'
const tabEntiers = [] // pour tous les entiers de 2 à n
const testMax = Math.sqrt(n + 1) // inutile de tester au dela de racine de n
const liste = [] // tableau de la liste des premiers jusqu'à n
// On rempli un tableau avec des booléeens de 2 à n
for (let i = 0; i < n + 1; i++) {
tabEntiers.push(true)
}
// On supprime les multiples des nombres premiers à partir de 2, 3, 5,...
for (let i = 2; i <= testMax; i++) {
if (tabEntiers[i]) {
for (let j = i * i; j < n + 1; j += i) {
tabEntiers[j] = false
}
}
}
// On récupère tous les indices du tableau des entiers dont le booléen est à true qui sont donc premiers
for (let i = 2; i < n + 1; i++) {
if (tabEntiers[i]) {
liste.push(i)
}
}
return liste
}
/**
* Liste les premiers compris entre min et max au sens large,
* min est inclu
* max est inclu.
* @param {number} min
* @param {number} max
* @author Sébastien Lozano
*/
export function premiersEntreBornes (min, max) {
'use strict'
// on crée les premiers jusque min
const premiersASupprimer = cribleEratostheneN(min - 1)
// on crée les premiers jusque max
const premiersJusqueMax = cribleEratostheneN(max)
// on supprime le début de la liste jusque min
premiersJusqueMax.splice(0, premiersASupprimer.length)
// on renvoie le tableau restant
return premiersJusqueMax
}
/**
* tire à pile ou face pour écrire ou non un texte
* @param {string} texte
* @author Sébastien Lozano
*/
export function texteOuPas (texte) {
'use strict'
const bool = randint(0, 1)
if (bool === 0) {
return '\\ldots'
} else {
return texte
}
}
/**
* Crée un tableau avec un nombre de lignes et de colonnes déterminées
* par la longueur des tableaux des entetes passés en paramètre
* Les contenus sont en mode maths par défaut, il faut donc penser à remplir les tableaux
* en utilisant éventuellement la commande \\text{}
*
* @example
* tableauColonneLigne(['coin','A','B'],['1','2'],['A1','B1','A2','B2']) affiche le tableau ci-dessous
* ------------------
* | coin | A | B |
* ------------------
* | 1 | A1 | B1 |
* ------------------
* | 2 | A2 | B2 |
* ------------------
*
* @example
* tableauColonneLigne(['coin','A','B','C'],['1','2'],['A1','B1','C1','A2','B2','C2']) affiche le tableau ci-dessous
* -----------------------
* | coin | A | B | C |
* -----------------------
* | 1 | A1 | B1 | C1 |
* -----------------------
* | 2 | A2 | B2 | C2 |
* -----------------------
*
* @example
* tableauColonneLigne(['coin','A','B'],['1','2','3'],['A1','B1','A2','B2','A3','B3']) affiche le tableau ci-dessous
* ------------------
* | coin | A | B |
* ------------------
* | 1 | A1 | B1 |
* ------------------
* | 2 | A2 | B2 |
* ------------------
* | 3 | A3 | B3 |
* ------------------
*
* @example
* tableauColonneLigne(['coin','A','B','C'],['1','2','3'],['A1','B1','C1','A2','B2','C2','A3','B3','C3']) affiche le tableau ci-dessous
* -----------------------
* | coin | A | B | C |
* -----------------------
* | 1 | A1 | B1 | C1 |
* -----------------------
* | 2 | A2 | B2 | C2 |
* -----------------------
* | 3 | A3 | B3 | C3 |
* -----------------------
*
* @param {array} tabEntetesColonnes contient les entetes des colonnes
* @param {array} tabEntetesLignes contient les entetes des lignes
* @param {array} tabLignes contient les elements de chaque ligne
* @author Sébastien Lozano
*
*/
export function tableauColonneLigne (tabEntetesColonnes, tabEntetesLignes, tabLignes, arraystretch, math = true) {
// on définit le nombre de colonnes
const C = tabEntetesColonnes.length
// on définit le nombre de lignes
const L = tabEntetesLignes.length
// On construit le string pour obtenir le tableau pour compatibilité HTML et LaTeX
let tableauCL = ''
if (!arraystretch) {
if (context.isHtml) {
arraystretch = 2.5
} else {
arraystretch = 1
}
}
if (context.isHtml) {
tableauCL += `$\\def\\arraystretch{${arraystretch}}\\begin{array}{|`
} else {
tableauCL += `$\\renewcommand{\\arraystretch}{${arraystretch}}\n`
tableauCL += '\\begin{array}{|'
}
// on construit la 1ere ligne avec toutes les colonnes
for (let k = 0; k < C; k++) {
tableauCL += 'c|'
}
tableauCL += '}\n'
tableauCL += '\\hline\n'
if (typeof tabEntetesColonnes[0] === 'number') {
tableauCL += math ? texNombre(tabEntetesColonnes[0]) + '' : `\\text{${stringNombre(tabEntetesColonnes[0])}} `
} else {
tableauCL += math ? tabEntetesColonnes[0] : `\\text{${tabEntetesColonnes[0]}}`
}
for (let k = 1; k < C; k++) {
if (typeof tabEntetesColonnes[k] === 'number') {
tableauCL += ` & ${math ? texNombre(tabEntetesColonnes[k]) : '\\text{' + stringNombre(tabEntetesColonnes[k]) + '}'}`
} else {
tableauCL += ` & ${math ? tabEntetesColonnes[k] : '\\text{' + tabEntetesColonnes[k] + '}'}`
}
}
tableauCL += '\\\\\n'
tableauCL += '\\hline\n'
// on construit toutes les lignes
for (let k = 0; k < L; k++) {
if (typeof tabEntetesLignes[k] === 'number') {
tableauCL += math ? texNombre(tabEntetesLignes[k]) : `\\text{${stringNombre(tabEntetesLignes[k]) + ''}}`
} else {
tableauCL += math ? tabEntetesLignes[k] : `\\text{${tabEntetesLignes[k] + ''}}`
}
for (let m = 1; m < C; m++) {
if (typeof tabLignes[(C - 1) * k + m - 1] === 'number') {
tableauCL += ` & ${math ? texNombre(tabLignes[(C - 1) * k + m - 1]) : '\\text{' + stringNombre(tabLignes[(C - 1) * k + m - 1]) + '}'}`
} else {
tableauCL += ` & ${math ? tabLignes[(C - 1) * k + m - 1] : '\\text{' + tabLignes[(C - 1) * k + m - 1] + '}'}`
}
}
tableauCL += '\\\\\n'
tableauCL += '\\hline\n'
}
tableauCL += '\\end{array}\n'
if (context.isHtml) {
tableauCL += '$'
} else {
tableauCL += '\\renewcommand{\\arraystretch}{1}$\n'
}
return tableauCL
}
/**
* Renvoie un encart sur fond d'alert semantic ui en HTML ou dans un cadre bclogo en LaTeX avec le texte
* @param {string} texte
* @param {string} couleur
* @param {string} titre
* @author Sébastien Lozano
*/
export function warnMessage (texte, couleur, titre) {
'use strict'
if (typeof (titre) === 'undefined') {
titre = ''
}
if (context.isHtml) {
return `
<br>
<div class="ui compact warning message">
<h4><i class="lightbulb outline icon"></i>${titre}</h4>
<p>` + texte + `
</p>
</div>
`
} else {
// return texCadreParOrange(texte);
return `
\\begin{bclogo}[couleurBarre=` + couleur + ',couleurBord=' + couleur + ',epBord=2,couleur=gray!10,logo=\\bclampe,arrondi=0.1]{\\bf ' + titre + `}
` + texte + `
\\end{bclogo}
`
}
}
/**
* @returns un encart sur fond d'alert semantic ui en HTML ou dans un cadre bclogo en LaTeX avec le texte + icone info
* @param {object}
* @author Sébastien Lozano
*/
export function infoMessage ({ titre, texte, couleur }) {
// 'use strict';
if (context.isHtml) {
return `
<div class="ui compact icon message">
<i class="info circle icon"></i>
<div class="content">
<div class="header">
` + titre + `
</div>
<p>` + texte + `</p>
</div>
</div>
`
} else {
return `
\\begin{bclogo}[couleurBarre=` + couleur + ',couleurBord=' + couleur + ',epBord=2,couleur=gray!10,logo=\\bcinfo,arrondi=0.1]{\\bf ' + titre + `}
` + texte + `
\\end{bclogo}
`
}
}
/**
* @returns un encart sur fond d'alert semantic ui en HTML ou dans un cadre bclogo en LaTeX avec le texte + icone lampe
* @param {object}
* @author Sébastien Lozano
*/
export function lampeMessage ({ titre, texte, couleur }) {
if (context.isHtml) {
if (context.versionMathalea === 3) {
return `
<div class='bg-gray-100 border-solid border-2 border-black rounded p-2'>
<h1 class='font-bold'>${titre}</h1>
<p>${texte}</p>
</div>
`
} else {
return `
<div class="ui compact icon message" style="width: auto">
<i class="lightbulb outline icon"></i>
<div class="content">
<div class="header">
` + titre + `
</div>
<p>` + texte + `</p>
</div>
</div>
`
}
} else if (context.isAmc) {
return `
{\\bf ${titre}} : ${texte}
`
} else {
return `
\\begin{bclogo}[couleurBarre=` + couleur + ',couleurBord=' + couleur + ',epBord=2,couleur=gray!10,logo=\\bclampe,arrondi=0.1]{\\bf ' + titre + `}
` + texte + `
\\end{bclogo}
`
}
}
/**
* renvoie un tableau avec la decomposition en facteurs premiers sous forme développée
* @param {number} n
* @author Sébastien Lozano
*/
export function decompositionFacteursPremiersArray (n) {
const decomposition = []
const liste = obtenirListeFacteursPremiers(n)
for (const i in liste) {
decomposition.push(liste[i])
}
return decomposition
}
/**
* @class
* @classdesc Classe Triangles - Méthodes utiles pour les triangles *
* * @param {number} l1 une des longueurs du triangle
* * @param {number} l2 une des longueurs du triangle
* * @param {number} l3 une des longueurs du triangle
* * @param {number} a1 un des angles du triangle
* * @param {number} a2 un des angles du triangle
* * @param {number} a3 un des angles du triangle
* @author Sébastien Lozano
*/
export function Triangles (l1, l2, l3, a1, a2, a3) {
'use strict'
const self = this
/**
* @constant {array} nomsPossibles liste de noms possibles pour un triangle
*/
const nomsPossibles = ['AGE', 'AIL', 'AIR', 'ALU', 'AME', 'AMI', 'ANE', 'ARC', 'BAC', 'BAL', 'BAR', 'BEC', 'BEL', 'BIO', 'BIP', 'BIS', 'BLE', 'BOA', 'BOF', 'BOG', 'BOL', 'BUT', 'BYE', 'COQ', 'CRI', 'CRU', 'DUC', 'DUO', 'DUR', 'EAU', 'ECU', 'EGO', 'EPI', 'FER', 'FIL', 'FUN', 'GPS', 'ICE', 'JET', 'KIF', 'KIR', 'MAC', 'NEM', 'PAS', 'PIC', 'PIF', 'PIN', 'POT', 'RAI', 'RAP', 'RAT', 'RIF', 'SEL', 'TAF', 'TIC', 'TAC', 'TOC', 'TOP', 'UNI', 'WOK', 'YAK', 'YEN', 'ZEN', 'ZIG', 'ZAG']
/**
* @property {string} nom nom du triangle, tiré au hasard dans un tableau
*/
this.nom = choice(nomsPossibles)
/**
* @return {string} Renvoie le nom du triangle tiré au hasard
* * les strings sont EN MODE MATHS le premier caractère du string est un $
* @example si triangle est une instance de la classe Triangle() triangle.getNom() renvoie le string '$AMI$' si AMI est le nom tiré au hasard
*/
function getNom () {
return '$' + self.nom + '$'
}
/**
* @return {array} Renvoie un tableau contenant le nom des côtés, segments, du triangle tiré au hasard
* * les strings sont EN MODE MATHS le premier caractère du string est un $
* @example si triangle est une instance de la classe Triangle() triangle.getCotes() renvoie le tableau de strings ['$[AM]$','$[MI]$','$[IA]$'] dans cet ordre si AMI est le nom tiré au hasard
*/
function getCotes () {
const cotes = []
const triangle = self.nom
const sommets = triangle.split('')
cotes[0] = '$[' + sommets[0] + '' + sommets[1] + ']$'
cotes[1] = '$[' + sommets[1] + '' + sommets[2] + ']$'
cotes[2] = '$[' + sommets[2] + '' + sommets[0] + ']$'
return cotes
}
/**
* @return {array} Renvoie un tableau contenant le nom des longueurs des côtés du triangle tiré au hasard
* * les strings sont EN MODE MATHS le premier caractère du string est un $
* @example si triangle est une instance de la classe Triangle() triangle.getCotes() renvoie le tableau de strings ['$AM$','$MI$','$IA$'] dans cet ordre si AMI est le nom tiré au hasard
*/
function getLongueurs () {
const longueurs = []
const triangle = self.nom
const sommets = triangle.split('')
longueurs[0] = '$' + sommets[0] + '' + sommets[1] + '$'
longueurs[1] = '$' + sommets[1] + '' + sommets[2] + '$'
longueurs[2] = '$' + sommets[2] + '' + sommets[0] + '$'
return longueurs
}
/**
* @return {array} Renvoie un tableau avec les valeurs des longueurs des côtés du triangle passées en paramètre à l'instance de la classe
*/
function getLongueursValeurs () {
if ((typeof self.l1 === 'undefined') || (typeof self.l2 === 'undefined') || (typeof self.l3 === 'undefined')) {
// return false;
return ['L\'une des longueurs de l\'objet triangle n\'est pas définie']
}
const longueurs = []
longueurs[0] = self.l1
longueurs[1] = self.l2
longueurs[2] = self.l3
return longueurs
}
/**
* @return {array} Renvoie un tableau de strings avec les noms des angles du triangle.
* * les strings sont EN MODE MATHS le premier caractère du string est un $
*/
function getAngles () {
const angles = []
const triangle = self.nom
const sommets = triangle.split('')
angles[0] = `$\\;\\widehat{${sommets[0] + sommets[1] + sommets[2]}}$`
angles[1] = `$\\;\\widehat{${sommets[1] + sommets[2] + sommets[0]}}$`
angles[2] = `$\\;\\widehat{${sommets[2] + sommets[0] + sommets[1]}}$`
return angles
}
/**
* @return {array} Renvoie un tableau avec les valeurs des angles du triangle passées en paramètre à l'instance de la classe
*/
function getAnglesValeurs () {
if ((typeof self.a1 === 'undefined') || (typeof self.a2 === 'undefined') || (typeof self.a3 === 'undefined')) {
// return false;
return ['L\'un des angles de l\'objet triangle n\'est pas définie']
}
const angles = []
angles[0] = self.a1
angles[1] = self.a2
angles[2] = self.a3
return angles
}
/**
* @return {array} Renvoie un tableau de strings avec les noms des sommets du triangle.
* * les strings sont EN MODE MATHS le premier caractère du string est un $
*/
function getSommets (math = true) {
const triangle = self.nom
const sommets = triangle.split('')
if (math === true) {
sommets[0] = '$' + sommets[0] + '$'
sommets[1] = '$' + sommets[1] + '$'
sommets[2] = '$' + sommets[2] + '$'
}
return sommets
}
/**
* @return {array} Renvoie le périmètre de l'instance de la classe Triangle() avec les valeurs des longueurs des côtés du triangle passées en paramètre à l'instance
* @example let triangle = new Triangle();
* * triangle.l1 = 2;
* * triangle.l2 = 3;
* * triangle.l3 = 4
* * triangle.getPerimetre() renvoie 9
*/
function getPerimetre () {
if ((typeof self.l1 === 'undefined') || (typeof self.l2 === 'undefined') || (typeof self.l3 === 'undefined')) {
// return false;
return 'L\'une des longueurs de l\'objet triangle n\'est pas définie'
} else {
return self.l1 + self.l2 + self.l3
}
}
/**
* @return {array} Renvoie un booleen selon que les trois longueurs passées à l'instance de la classe forment un vrai triangle ou non
* @example let triangle = new Triangle();
* * triangle.l1 = 2;
* * triangle.l2 = 3;
* * triangle.l3 = 7
* * triangle.isTrueTriangleLongueurs() renvoie false
* @example let triangle = new Triangle();
* * triangle.l1 = 2;
* * triangle.l2 = 3;
* * triangle.l3 = 4
* * triangle.isTrueTriangleLongueurs() renvoie true
*/
function isTrueTriangleLongueurs () {
if ((typeof self.l1 === 'undefined') || (typeof self.l2 === 'undefined') || (typeof self.l3 === 'undefined')) {
return false
// return 'L\'une des longueurs de l\'objet triangle n\'est pas définie';
}
const longueurs = [self.l1, self.l2, self.l3]
longueurs.sort(function (a, b) {
return a - b
})
if (longueurs[2] < longueurs[0] + longueurs[1]) {
return true
} else {
return false
}
}
/**
* @return {array} Renvoie un booleen selon que les trois longueurs passées à l'instance de la classe forment un triangle plat ou non
* @example let triangle = new Triangle();
* * triangle.l1 = 2;
* * triangle.l2 = 3;
* * triangle.l3 = 5
* * triangle.isTrueTriangleLongueurs() renvoie true
* @example let triangle = new Triangle();
* * triangle.l1 = 2;
* * triangle.l2 = 3;
* * triangle.l3 = 4
* * triangle.isTrueTriangleLongueurs() renvoie false
*/
function isPlatTriangleLongueurs () {
if ((typeof self.l1 === 'undefined') || (typeof self.l2 === 'undefined') || (typeof self.l3 === 'undefined')) {
// return 'L\'une des longueurs de l\'objet triangle n\'est pas définie';
return false
}
const longueurs = [self.l1, self.l2, self.l3]
longueurs.sort(function (a, b) {
return a - b
})
if (egal(longueurs[2], longueurs[0] + longueurs[1])) {
return true
} else {
return false
}
}
/**
* @return {array} Renvoie un booleen selon que les trois angles passés à l'instance de la classe forment un vrai triangle ou non
* @example let triangle = new Triangle();
* * triangle.a1 = 100;
* * triangle.a2 = 40;
* * triangle.a3 = 50
* * triangle.isTrueTriangleAngles() renvoie false
* @example let triangle = new Triangle();
* * triangle.a1 = 80;
* * triangle.a2 = 40;
* * triangle.a3 = 60
* * triangle.isTrueTriangleAngles() renvoie true
*/
function isTrueTriangleAngles () {
// si l'un des angles n'est pas defini ça ne va pas
if ((typeof self.a1 === 'undefined') || (typeof self.a2 === 'undefined') || (typeof self.a3 === 'undefined')) {
return false
// return 'L\'une des longueurs de l\'objet triangle n\'est pas définie';
}
// si l'un des angles est négatif ça ne va pas
if ((self.a1 < 0) || (self.a2 < 0) || (self.a3 < 0)) {
return false
// return 'L\'une des longueurs de l\'objet triangle n\'est pas définie';
}
if ((self.a1 + self.a2 + self.a3) === 180) {
if ((self.a1 === 0 && self.a2 === 0) || (self.a2 === 0 && self.a3 === 0) || (self.a3 === 0 && self.a1 === 0)) {
return false
} else {
return true
}
} else {
return false
}
}
// renvoie un booleen selon que les trois angles forment un triangle plat ou non
/**
* @return {array} Renvoie un booleen selon que les trois angles passés à l'instance de la classe forment un triangle plat ou non
* @example let triangle = new Triangle();
* * triangle.a1 = 0;
* * triangle.a2 = 0;
* * triangle.a3 = 180
* * triangle.isTrueTriangleAngles() renvoie true
* @example let triangle = new Triangle();
* * triangle.a1 = 80;
* * triangle.a2 = 40;
* * triangle.a3 = 60
* * triangle.isTrueTriangleAngles() renvoie false
*/
function isPlatTriangleAngles () {
if ((typeof self.a1 === 'undefined') || (typeof self.a2 === 'undefined') || (typeof self.a3 === 'undefined')) {
return false
// return 'L\'une des longueurs de l\'objet triangle n\'est pas définie';
}
if ((self.a1 + self.a2 + self.a3) === 180) {
if ((self.a1 === 0 && self.a2 === 0) || (self.a2 === 0 && self.a3 === 0) || (self.a3 === 0 && self.a1 === 0)) {
return true
} else {
return false
}
} else {
return false
}
}
this.l1 = l1
this.l2 = l2
this.l3 = l3
this.a1 = a1
this.a2 = a2
this.a3 = a3
// this.nom = nom;
this.getNom = getNom
this.getCotes = getCotes
this.getLongueurs = getLongueurs
this.getLongueursValeurs = getLongueursValeurs
this.getAngles = getAngles
this.getAnglesValeurs = getAnglesValeurs
this.getSommets = getSommets
this.getPerimetre = getPerimetre
this.isTrueTriangleLongueurs = isTrueTriangleLongueurs
this.isPlatTriangleLongueurs = isPlatTriangleLongueurs
this.isTrueTriangleAngles = isTrueTriangleAngles
this.isPlatTriangleAngles = isPlatTriangleAngles
// this.isQuelconque = isQuelconque;
}
/**
* @class
* @classdesc Classe Relatif - Méthodes utiles sur les relatifs
* @param {...any} relatifs est un paramètre du reste
* @author Sébastien Lozano
*/
export function Relatif (...relatifs) {
// 'use strict'; pas de use strict avec un paramètre du reste
this.relatifs = relatifs
/**
* * Récupère le signe de chaque relatif déclaré dans le paramètre du reste relatifs,
* * Si 0 fait partie des relatifs on renvoie une erreur
* @return {array} Renvoie un tableau de -1 ou 1
* @example getSigneNumber(-1,-2,8,-9,4) renvoie [-1,-1,1,-1,1]
*/
function getSigneNumber () {
const signes = []
try {
// port du string interdit !
relatifs.forEach(function (element) {
if (typeof element === 'string') {
throw new TypeError(`${element} est un string !`)
}
if (element === 0) {
throw new RangeError(`${element} a été exclu des valeurs possibles.`)
}
})
// Quoi faire sans nombres ?
if (relatifs.length === 0) {
throw new Error('C\'est mieux avec quelques nombres !')
}
relatifs.forEach(function (element) {
if (element < 0) {
signes.push(-1)
}
if (element > 0) {
signes.push(1)
}
})
} catch (err) {
console.log(err.message)
console.log(err.stack)
}
return signes
}
/**
* * Récupère le signe de chaque relatif déclaré dans le paramètre du reste relatifs
* @return {array} Renvoie un tableau de strings valant 'négatif' ou 'positif'
* @example getSigneNumber(-1,-2,8,-9,4) renvoie le tableau de strings [négatif,négatif,positif,négatif,positif]
*/
function getSigneString () {
const signesString = []
const signes = getSigneNumber()
signes.forEach(function (element) {
if (element === -1) {
signesString.push('négatif')
}
if (element === 1) {
signesString.push('positif')
}
})
return signesString
}
/**
*
* @param {...any} n une liste de deux ou plus de nombres relatifs
* @return {number} Renvoie le signe du produit des nombres de cette liste. 1 ou -1
* @example getSigneProduitNumber(1,-4,-7) renvoie 1
*/
function getSigneProduitNumber (...n) {
let produit = 1
try {
// port du string interdit !
n.forEach(function (element) {
if (typeof element === 'string') {
throw new TypeError(`${element} est un string !`)
}
if (element === 0) {
throw new RangeError(`${element} a été exclu des valeurs possibles.`)
}
})
// Quoi faire sans nombres ?
if (n.length === 0) {
throw new Error('C\'est mieux avec quelques nombres !')
}
n.forEach(function (element) {
produit = produit * element
})
if (produit < 0) {
return -1
}
if (produit > 0) {
return 1
}
} catch (err) {
console.log(err.message)
console.log(err.stack)
}
}
/**
*
* @param {...any} n une liste de deux ou plus de nombres relatifs
* @return {string} Renvoie un string désignant le signe du produit des nombres de cette liste. postif1 ou négatif
* @example getSigneProduitNumber(1,-4,-7) renvoie le string positif
*/
function getSigneProduitString (...n) {
const produit = getSigneProduitNumber(...n)
if (produit === -1) {
return 'négatif'
}
if (produit === 1) {
return 'positif'
}
}
/**
*
* @param {...any} n une liste de deux ou plus de nombres relatifs
* @return {string} Renvoie le nombre d'éléments négatifs des nombres de cette liste.
* * la liste d'entiers doit être passé dans un tableau
* @example getCardNegatifs([1,-4,-7]) renvoie 2
* @example getCardNegatifs([4,-5,7,7,-8,-9]) renvoie 3
*/
function getCardNegatifs ([...n]) {
let card = 0
try {
// port du string interdit !
n.forEach(function (element) {
if (typeof element === 'string') {
throw new TypeError(`${element} est un string !`)
}
if (element === 0) {
throw new RangeError(`${element} a été exclu des valeurs possibles.`)
}
})
// Quoi faire sans nombres ?
if (n.length === 0) {
throw new Error('C\'est mieux avec quelques nombres !')
}
n.forEach(function (element) {
if (element < 0) {
card = card + 1
}
})
return card
} catch (err) {
console.log(err.message)
}
}
/**
* Fonction locale
* @param {integer} n un entier désignant le cardinal de facteurs négatifs dans un produit
* @return un string au singulier ou au pluriel
* @example orth_facteurs_negatifs(0) ou orth_facteurs_negatifs(1) renvoie 'facteur negatif'
* @example orth_facteurs_negatifs(7) renvoie 'facteurs negatifs'
*/
function orthographeFacteursNegatifs (n) {
if (n >= 2) {
return 'facteurs négatifs'
} else {
return 'facteur négatif'
}
}
/**
* @param {...any} n une liste de deux ou plus de nombres relatifs qui constituent les facteurs du produit
* @return {string} Renvoie la règle qui permet de justifier le signe d'un produit de relatifs adaptée à la liste passée en paramètre.
* @example setRegleProduitFacteurs([1,-2,-8,5]) renvoie le string 'Il y a 2 facteurs négatifs, le nombre de facteurs négatifs est pair donc le produit est positif.'
*/
function setRegleSigneProduit (...n) {
try {
// port du string interdit !
n.forEach(function (element) {
if (typeof element === 'string') {
throw new TypeError(`${element} est un string !`)
}
})
// Quoi faire sans nombres ?
if (n.length === 0) {
throw new Error('C\'est mieux avec quelques nombres !')
}
if (n.length === 2) {
if (getCardNegatifs(n) % 2 === 0) {
return 'Les deux facteurs ont le même signe donc le produit est positif.'
} else {
return 'Les deux facteurs ont un signe différent donc le produit est négatif.'
}
} else if (n.length > 2) {
if (getCardNegatifs(n) % 2 === 0) {
if (getCardNegatifs(n) === 0) {
return 'Tous les facteurs sont positifs donc le produit est positif.'
} else {
return `Il y a ${getCardNegatifs(n)} ${orthographeFacteursNegatifs(getCardNegatifs(n))}, le nombre de facteurs négatifs est pair donc le produit est positif.`
}
} else {
return `Il y a ${getCardNegatifs(n)} ${orthographeFacteursNegatifs(getCardNegatifs(n))}, le nombre de facteurs négatifs est impair donc le produit est négatif.`
}
}
} catch (err) {
console.log(err.message)
}
}
/**
*
* @param {...any} num une liste de deux ou plus de nombres relatifs qui constituent les facteurs du numérateur
* @param {...any} den une liste de deux ou plus de nombres relatifs qui constituent les facteurs du dénominateur
* @return {string} Renvoie la règle qui permet de justifier le signe d'un produit de relatifs adaptée à la liste passée en paramètre.
* @example setRegleProduitQuotient([1,-2],[-8,5]) renvoie le string 'La somme des facteurs négatifs du numérateur et des facteurs négatifs du dénominateur vaut 2, ce nombre est pair donc le quotient est positif.'
*/
function setRegleSigneQuotient (...n) {
try {
// port du string interdit !
n.forEach(function (element) {
if (typeof element === 'string') {
throw new TypeError(`${element} est un string !`)
}
})
// Quoi faire sans nombres ?
if (n.length === 0) {
throw new Error('C\'est mieux avec quelques nombres !')
}
if (n.length === 2) {
if (getCardNegatifs(n) % 2 === 0) {
return 'Le numérateur et le dénominateur ont le même signe donc le quotient est positif.'
} else {
return 'Les numérateur et le dénominateur ont un signe différent donc le quotient est négatif.'
}
} else if (n.length > 2) {
if (getCardNegatifs(n) % 2 === 0) {
if (getCardNegatifs(n) === 0) {
return 'Tous les facteurs du numérateur et tous les facteurs du dénominateur sont positifs donc le quotient est positif.'
} else {
// return `La somme du nombre de facteurs négatifs du numérateur et du nombre de facteurs négatifs du dénominateur vaut ${getCardNegatifs(n)}, ce nombre est pair donc le quotient est positif.`;
return `Quand on compte les facteurs négatifs du numérateur et du dénominateur, on trouve ${getCardNegatifs(n)}, ce nombre est pair donc le quotient est positif.`
}
} else {
// return `La somme du nombre de facteurs négatifs du numérateur et du nombre de facteurs négatifs du dénominateur vaut ${getCardNegatifs(n)}, ce nombre est impair donc le quotient est négatif.`;
return `Quand on compte les facteurs négatifs du numérateur et du dénominateur, on trouve ${getCardNegatifs(n)}, ce nombre est impair donc le quotient est négatif.`
}
}
} catch (err) {
console.log(err.message)
}
}
this.getSigneNumber = getSigneNumber
this.getSigneString = getSigneString
this.getSigneProduitNumber = getSigneProduitNumber
this.getSigneProduitString = getSigneProduitString
this.getCardNegatifs = getCardNegatifs
this.setRegleSigneProduit = setRegleSigneProduit
this.setRegleSigneQuotient = setRegleSigneQuotient
}
export function nombreEnLettres (nb, type = 1) {
let partieEntiere, partieDecimale, nbstring, nbDec, decstring
if (estentier(nb)) return partieEntiereEnLettres(nb)
else {
partieEntiere = Math.floor(nb)
partieDecimale = new Decimal(nb).sub(partieEntiere).toDP(3)
nbDec = partieDecimale.toString().replace(/\d*\./, '').length
partieDecimale = partieDecimale.mul(10 ** nbDec).toNumber()
switch (nbDec) {
case 1:
if (partieDecimale > 1) decstring = ' dixièmes'
else decstring = ' dixième'
break
case 2:
if (partieDecimale > 1) decstring = ' centièmes'
else decstring = ' centième'
break
case 3:
if (partieDecimale > 1) decstring = ' millièmes'
else decstring = ' millième'
break
}
if (type === 1) {
nbstring = partieEntiereEnLettres(partieEntiere) + ' unités et ' + partieEntiereEnLettres(partieDecimale) + decstring
} else if (nbDec === nombreDeChiffresDansLaPartieEntiere(partieDecimale)) {
nbstring = partieEntiereEnLettres(partieEntiere) + ' virgule ' + partieEntiereEnLettres(partieDecimale)
} else {
nbstring = partieEntiereEnLettres(partieEntiere) + ' virgule '
for (let n = 0; n < nbDec - nombreDeChiffresDansLaPartieEntiere(partieDecimale); n++) {
nbstring += 'zéro-'
}
nbstring += partieEntiereEnLettres(partieDecimale)
}
}
return nbstring
}
/**
*
*
* @param {int} nb
*
*/
export function partieEntiereEnLettres (nb) {
const dictionnaire = {
0: 'zéro',
'000': '',
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',
20: 'vingt',
21: 'vingt et un',
22: 'vingt-deux',
23: 'vingt-trois',
24: 'vingt-quatre',
25: 'vingt-cinq',
26: 'vingt-six',
27: 'vingt-sept',
28: 'vingt-huit',
29: 'vingt-neuf',
30: 'trente',
31: 'trente et un',
32: 'trente-deux',
33: 'trente-trois',
34: 'trente-quatre',
35: 'trente-cinq',
36: 'trente-six',
37: 'trente-sept',
38: 'trente-huit',
39: 'trente-neuf',
40: 'quarante',
41: 'quarante et un',
42: 'quarante-deux',
43: 'quarante-trois',
44: 'quarante-quatre',
45: 'quarante-cinq',
46: 'quarante-six',
47: 'quarante-sept',
48: 'quarante-huit',
49: 'quarante-neuf',
50: 'cinquante',
51: 'cinquante et un',
52: 'cinquante-deux',
53: 'cinquante-trois',
54: 'cinquante-quatre',
55: 'cinquante-cinq',
56: 'cinquante-six',
57: 'cinquante-sept',
58: 'cinquante-huit',
59: 'cinquante-neuf',
60: 'soixante',
61: 'soixante et un',
62: 'soixante-deux',
63: 'soixante-trois',
64: 'soixante-quatre',
65: 'soixante-cinq',
66: 'soixante-six',
67: 'soixante-sept',
68: 'soixante-huit',
69: 'soixante-neuf',
70: 'soixante-dix',
71: 'soixante et onze',
72: 'soixante-douze',
73: 'soixante-treize',
74: 'soixante-quatorze',
75: 'soixante-quinze',
76: 'soixante-seize',
77: 'soixante-dix-sept',
78: 'soixante-dix-huit',
79: 'soixante-dix-neuf',
80: 'quatre-vingts',
81: 'quatre-vingt-un',
82: 'quatre-vingt-deux',
83: 'quatre-vingt-trois',
84: 'quatre-vingt-quatre',
85: 'quatre-vingt-cinq',
86: 'quatre-vingt-six',
87: 'quatre-vingt-sept',
88: 'quatre-vingt-huit',
89: 'quatre-vingt-neuf',
90: 'quatre-vingt-dix',
91: 'quatre-vingt-onze',
92: 'quatre-vingt-douze',
93: 'quatre-vingt-treize',
94: 'quatre-vingt-quatorze',
95: 'quatre-vingt-quinze',
96: 'quatre-vingt-seize',
97: 'quatre-vingt-dix-sept',
98: 'quatre-vingt-dix-huit',
99: 'quatre-vingt-dix-neuf',
100: 'cent',
101: 'cent un',
102: 'cent deux',
103: 'cent trois',
104: 'cent quatre',
105: 'cent cinq',
106: 'cent six',
107: 'cent sept',
108: 'cent huit',
109: 'cent neuf',
110: 'cent dix',
111: 'cent onze',
112: 'cent douze',
113: 'cent treize',
114: 'cent quatorze',
115: 'cent quinze',
116: 'cent seize',
117: 'cent dix-sept',
118: 'cent dix-huit',
119: 'cent dix-neuf',
120: 'cent vingt',
121: 'cent vingt et un',
122: 'cent vingt-deux',
123: 'cent vingt-trois',
124: 'cent vingt-quatre',
125: 'cent vingt-cinq',
126: 'cent vingt-six',
127: 'cent vingt-sept',
128: 'cent vingt-huit',
129: 'cent vingt-neuf',
130: 'cent trente',
131: 'cent trente et un',
132: 'cent trente-deux',
133: 'cent trente-trois',
134: 'cent trente-quatre',
135: 'cent trente-cinq',
136: 'cent trente-six',
137: 'cent trente-sept',
138: 'cent trente-huit',
139: 'cent trente-neuf',
140: 'cent quarante',
141: 'cent quarante et un',
142: 'cent quarante-deux',
143: 'cent quarante-trois',
144: 'cent quarante-quatre',
145: 'cent quarante-cinq',
146: 'cent quarante-six',
147: 'cent quarante-sept',
148: 'cent quarante-huit',
149: 'cent quarante-neuf',
150: 'cent cinquante',
151: 'cent cinquante et un',
152: 'cent cinquante-deux',
153: 'cent cinquante-trois',
154: 'cent cinquante-quatre',
155: 'cent cinquante-cinq',
156: 'cent cinquante-six',
157: 'cent cinquante-sept',
158: 'cent cinquante-huit',
159: 'cent cinquante-neuf',
160: 'cent soixante',
161: 'cent soixante et un',
162: 'cent soixante-deux',
163: 'cent soixante-trois',
164: 'cent soixante-quatre',
165: 'cent soixante-cinq',
166: 'cent soixante-six',
167: 'cent soixante-sept',
168: 'cent soixante-huit',
169: 'cent soixante-neuf',
170: 'cent soixante-dix',
171: 'cent soixante et onze',
172: 'cent soixante-douze',
173: 'cent soixante-treize',
174: 'cent soixante-quatorze',
175: 'cent soixante-quinze',
176: 'cent soixante-seize',
177: 'cent soixante-dix-sept',
178: 'cent soixante-dix-huit',
179: 'cent soixante-dix-neuf',
180: 'cent quatre-vingts',
181: 'cent quatre-vingt-un',
182: 'cent quatre-vingt-deux',
183: 'cent quatre-vingt-trois',
184: 'cent quatre-vingt-quatre',
185: 'cent quatre-vingt-cinq',
186: 'cent quatre-vingt-six',
187: 'cent quatre-vingt-sept',
188: 'cent quatre-vingt-huit',
189: 'cent quatre-vingt-neuf',
190: 'cent quatre-vingt-dix',
191: 'cent quatre-vingt-onze',
192: 'cent quatre-vingt-douze',
193: 'cent quatre-vingt-treize',
194: 'cent quatre-vingt-quatorze',
195: 'cent quatre-vingt-quinze',
196: 'cent quatre-vingt-seize',
197: 'cent quatre-vingt-dix-sept',
198: 'cent quatre-vingt-dix-huit',
199: 'cent quatre-vingt-dix-neuf',
200: 'deux cents',
201: 'deux cent un',
202: 'deux cent deux',
203: 'deux cent trois',
204: 'deux cent quatre',
205: 'deux cent cinq',
206: 'deux cent six',
207: 'deux cent sept',
208: 'deux cent huit',
209: 'deux cent neuf',
210: 'deux cent dix',
211: 'deux cent onze',
212: 'deux cent douze',
213: 'deux cent treize',
214: 'deux cent quatorze',
215: 'deux cent quinze',
216: 'deux cent seize',
217: 'deux cent dix-sept',
218: 'deux cent dix-huit',
219: 'deux cent dix-neuf',
220: 'deux cent vingt',
221: 'deux cent vingt et un',
222: 'deux cent vingt-deux',
223: 'deux cent vingt-trois',
224: 'deux cent vingt-quatre',
225: 'deux cent vingt-cinq',
226: 'deux cent vingt-six',
227: 'deux cent vingt-sept',
228: 'deux cent vingt-huit',
229: 'deux cent vingt-neuf',
230: 'deux cent trente',
231: 'deux cent trente et un',
232: 'deux cent trente-deux',
233: 'deux cent trente-trois',
234: 'deux cent trente-quatre',
235: 'deux cent trente-cinq',
236: 'deux cent trente-six',
237: 'deux cent trente-sept',
238: 'deux cent trente-huit',
239: 'deux cent trente-neuf',
240: 'deux cent quarante',
241: 'deux cent quarante et un',
242: 'deux cent quarante-deux',
243: 'deux cent quarante-trois',
244: 'deux cent quarante-quatre',
245: 'deux cent quarante-cinq',
246: 'deux cent quarante-six',
247: 'deux cent quarante-sept',
248: 'deux cent quarante-huit',
249: 'deux cent quarante-neuf',
250: 'deux cent cinquante',
251: 'deux cent cinquante et un',
252: 'deux cent cinquante-deux',
253: 'deux cent cinquante-trois',
254: 'deux cent cinquante-quatre',
255: 'deux cent cinquante-cinq',
256: 'deux cent cinquante-six',
257: 'deux cent cinquante-sept',
258: 'deux cent cinquante-huit',
259: 'deux cent cinquante-neuf',
260: 'deux cent soixante',
261: 'deux cent soixante et un',
262: 'deux cent soixante-deux',
263: 'deux cent soixante-trois',
264: 'deux cent soixante-quatre',
265: 'deux cent soixante-cinq',
266: 'deux cent soixante-six',
267: 'deux cent soixante-sept',
268: 'deux cent soixante-huit',
269: 'deux cent soixante-neuf',
270: 'deux cent soixante-dix',
271: 'deux cent soixante et onze',
272: 'deux cent soixante-douze',
273: 'deux cent soixante-treize',
274: 'deux cent soixante-quatorze',
275: 'deux cent soixante-quinze',
276: 'deux cent soixante-seize',
277: 'deux cent soixante-dix-sept',
278: 'deux cent soixante-dix-huit',
279: 'deux cent soixante-dix-neuf',
280: 'deux cent quatre-vingts',
281: 'deux cent quatre-vingt-un',
282: 'deux cent quatre-vingt-deux',
283: 'deux cent quatre-vingt-trois',
284: 'deux cent quatre-vingt-quatre',
285: 'deux cent quatre-vingt-cinq',
286: 'deux cent quatre-vingt-six',
287: 'deux cent quatre-vingt-sept',
288: 'deux cent quatre-vingt-huit',
289: 'deux cent quatre-vingt-neuf',
290: 'deux cent quatre-vingt-dix',
291: 'deux cent quatre-vingt-onze',
292: 'deux cent quatre-vingt-douze',
293: 'deux cent quatre-vingt-treize',
294: 'deux cent quatre-vingt-quatorze',
295: 'deux cent quatre-vingt-quinze',
296: 'deux cent quatre-vingt-seize',
297: 'deux cent quatre-vingt-dix-sept',
298: 'deux cent quatre-vingt-dix-huit',
299: 'deux cent quatre-vingt-dix-neuf',
300: 'trois cents',
301: 'trois cent un',
302: 'trois cent deux',
303: 'trois cent trois',
304: 'trois cent quatre',
305: 'trois cent cinq',
306: 'trois cent six',
307: 'trois cent sept',
308: 'trois cent huit',
309: 'trois cent neuf',
310: 'trois cent dix',
311: 'trois cent onze',
312: 'trois cent douze',
313: 'trois cent treize',
314: 'trois cent quatorze',
315: 'trois cent quinze',
316: 'trois cent seize',
317: 'trois cent dix-sept',
318: 'trois cent dix-huit',
319: 'trois cent dix-neuf',
320: 'trois cent vingt',
321: 'trois cent vingt et un',
322: 'trois cent vingt-deux',
323: 'trois cent vingt-trois',
324: 'trois cent vingt-quatre',
325: 'trois cent vingt-cinq',
326: 'trois cent vingt-six',
327: 'trois cent vingt-sept',
328: 'trois cent vingt-huit',
329: 'trois cent vingt-neuf',
330: 'trois cent trente',
331: 'trois cent trente et un',
332: 'trois cent trente-deux',
333: 'trois cent trente-trois',
334: 'trois cent trente-quatre',
335: 'trois cent trente-cinq',
336: 'trois cent trente-six',
337: 'trois cent trente-sept',
338: 'trois cent trente-huit',
339: 'trois cent trente-neuf',
340: 'trois cent quarante',
341: 'trois cent quarante et un',
342: 'trois cent quarante-deux',
343: 'trois cent quarante-trois',
344: 'trois cent quarante-quatre',
345: 'trois cent quarante-cinq',
346: 'trois cent quarante-six',
347: 'trois cent quarante-sept',
348: 'trois cent quarante-huit',
349: 'trois cent quarante-neuf',
350: 'trois cent cinquante',
351: 'trois cent cinquante et un',
352: 'trois cent cinquante-deux',
353: 'trois cent cinquante-trois',
354: 'trois cent cinquante-quatre',
355: 'trois cent cinquante-cinq',
356: 'trois cent cinquante-six',
357: 'trois cent cinquante-sept',
358: 'trois cent cinquante-huit',
359: 'trois cent cinquante-neuf',
360: 'trois cent soixante',
361: 'trois cent soixante et un',
362: 'trois cent soixante-deux',
363: 'trois cent soixante-trois',
364: 'trois cent soixante-quatre',
365: 'trois cent soixante-cinq',
366: 'trois cent soixante-six',
367: 'trois cent soixante-sept',
368: 'trois cent soixante-huit',
369: 'trois cent soixante-neuf',
370: 'trois cent soixante-dix',
371: 'trois cent soixante et onze',
372: 'trois cent soixante-douze',
373: 'trois cent soixante-treize',
374: 'trois cent soixante-quatorze',
375: 'trois cent soixante-quinze',
376: 'trois cent soixante-seize',
377: 'trois cent soixante-dix-sept',
378: 'trois cent soixante-dix-huit',
379: 'trois cent soixante-dix-neuf',
380: 'trois cent quatre-vingts',
381: 'trois cent quatre-vingt-un',
382: 'trois cent quatre-vingt-deux',
383: 'trois cent quatre-vingt-trois',
384: 'trois cent quatre-vingt-quatre',
385: 'trois cent quatre-vingt-cinq',
386: 'trois cent quatre-vingt-six',
387: 'trois cent quatre-vingt-sept',
388: 'trois cent quatre-vingt-huit',
389: 'trois cent quatre-vingt-neuf',
390: 'trois cent quatre-vingt-dix',
391: 'trois cent quatre-vingt-onze',
392: 'trois cent quatre-vingt-douze',
393: 'trois cent quatre-vingt-treize',
394: 'trois cent quatre-vingt-quatorze',
395: 'trois cent quatre-vingt-quinze',
396: 'trois cent quatre-vingt-seize',
397: 'trois cent quatre-vingt-dix-sept',
398: 'trois cent quatre-vingt-dix-huit',
399: 'trois cent quatre-vingt-dix-neuf',
400: 'quatre cents',
401: 'quatre cent un',
402: 'quatre cent deux',
403: 'quatre cent trois',
404: 'quatre cent quatre',
405: 'quatre cent cinq',
406: 'quatre cent six',
407: 'quatre cent sept',
408: 'quatre cent huit',
409: 'quatre cent neuf',
410: 'quatre cent dix',
411: 'quatre cent onze',
412: 'quatre cent douze',
413: 'quatre cent treize',
414: 'quatre cent quatorze',
415: 'quatre cent quinze',
416: 'quatre cent seize',
417: 'quatre cent dix-sept',
418: 'quatre cent dix-huit',
419: 'quatre cent dix-neuf',
420: 'quatre cent vingt',
421: 'quatre cent vingt et un',
422: 'quatre cent vingt-deux',
423: 'quatre cent vingt-trois',
424: 'quatre cent vingt-quatre',
425: 'quatre cent vingt-cinq',
426: 'quatre cent vingt-six',
427: 'quatre cent vingt-sept',
428: 'quatre cent vingt-huit',
429: 'quatre cent vingt-neuf',
430: 'quatre cent trente',
431: 'quatre cent trente et un',
432: 'quatre cent trente-deux',
433: 'quatre cent trente-trois',
434: 'quatre cent trente-quatre',
435: 'quatre cent trente-cinq',
436: 'quatre cent trente-six',
437: 'quatre cent trente-sept',
438: 'quatre cent trente-huit',
439: 'quatre cent trente-neuf',
440: 'quatre cent quarante',
441: 'quatre cent quarante et un',
442: 'quatre cent quarante-deux',
443: 'quatre cent quarante-trois',
444: 'quatre cent quarante-quatre',
445: 'quatre cent quarante-cinq',
446: 'quatre cent quarante-six',
447: 'quatre cent quarante-sept',
448: 'quatre cent quarante-huit',
449: 'quatre cent quarante-neuf',
450: 'quatre cent cinquante',
451: 'quatre cent cinquante et un',
452: 'quatre cent cinquante-deux',
453: 'quatre cent cinquante-trois',
454: 'quatre cent cinquante-quatre',
455: 'quatre cent cinquante-cinq',
456: 'quatre cent cinquante-six',
457: 'quatre cent cinquante-sept',
458: 'quatre cent cinquante-huit',
459: 'quatre cent cinquante-neuf',
460: 'quatre cent soixante',
461: 'quatre cent soixante et un',
462: 'quatre cent soixante-deux',
463: 'quatre cent soixante-trois',
464: 'quatre cent soixante-quatre',
465: 'quatre cent soixante-cinq',
466: 'quatre cent soixante-six',
467: 'quatre cent soixante-sept',
468: 'quatre cent soixante-huit',
469: 'quatre cent soixante-neuf',
470: 'quatre cent soixante-dix',
471: 'quatre cent soixante et onze',
472: 'quatre cent soixante-douze',
473: 'quatre cent soixante-treize',
474: 'quatre cent soixante-quatorze',
475: 'quatre cent soixante-quinze',
476: 'quatre cent soixante-seize',
477: 'quatre cent soixante-dix-sept',
478: 'quatre cent soixante-dix-huit',
479: 'quatre cent soixante-dix-neuf',
480: 'quatre cent quatre-vingts',
481: 'quatre cent quatre-vingt-un',
482: 'quatre cent quatre-vingt-deux',
483: 'quatre cent quatre-vingt-trois',
484: 'quatre cent quatre-vingt-quatre',
485: 'quatre cent quatre-vingt-cinq',
486: 'quatre cent quatre-vingt-six',
487: 'quatre cent quatre-vingt-sept',
488: 'quatre cent quatre-vingt-huit',
489: 'quatre cent quatre-vingt-neuf',
490: 'quatre cent quatre-vingt-dix',
491: 'quatre cent quatre-vingt-onze',
492: 'quatre cent quatre-vingt-douze',
493: 'quatre cent quatre-vingt-treize',
494: 'quatre cent quatre-vingt-quatorze',
495: 'quatre cent quatre-vingt-quinze',
496: 'quatre cent quatre-vingt-seize',
497: 'quatre cent quatre-vingt-dix-sept',
498: 'quatre cent quatre-vingt-dix-huit',
499: 'quatre cent quatre-vingt-dix-neuf',
500: 'cinq cents',
501: 'cinq cent un',
502: 'cinq cent deux',
503: 'cinq cent trois',
504: 'cinq cent quatre',
505: 'cinq cent cinq',
506: 'cinq cent six',
507: 'cinq cent sept',
508: 'cinq cent huit',
509: 'cinq cent neuf',
510: 'cinq cent dix',
511: 'cinq cent onze',
512: 'cinq cent douze',
513: 'cinq cent treize',
514: 'cinq cent quatorze',
515: 'cinq cent quinze',
516: 'cinq cent seize',
517: 'cinq cent dix-sept',
518: 'cinq cent dix-huit',
519: 'cinq cent dix-neuf',
520: 'cinq cent vingt',
521: 'cinq cent vingt et un',
522: 'cinq cent vingt-deux',
523: 'cinq cent vingt-trois',
524: 'cinq cent vingt-quatre',
525: 'cinq cent vingt-cinq',
526: 'cinq cent vingt-six',
527: 'cinq cent vingt-sept',
528: 'cinq cent vingt-huit',
529: 'cinq cent vingt-neuf',
530: 'cinq cent trente',
531: 'cinq cent trente et un',
532: 'cinq cent trente-deux',
533: 'cinq cent trente-trois',
534: 'cinq cent trente-quatre',
535: 'cinq cent trente-cinq',
536: 'cinq cent trente-six',
537: 'cinq cent trente-sept',
538: 'cinq cent trente-huit',
539: 'cinq cent trente-neuf',
540: 'cinq cent quarante',
541: 'cinq cent quarante et un',
542: 'cinq cent quarante-deux',
543: 'cinq cent quarante-trois',
544: 'cinq cent quarante-quatre',
545: 'cinq cent quarante-cinq',
546: 'cinq cent quarante-six',
547: 'cinq cent quarante-sept',
548: 'cinq cent quarante-huit',
549: 'cinq cent quarante-neuf',
550: 'cinq cent cinquante',
551: 'cinq cent cinquante et un',
552: 'cinq cent cinquante-deux',
553: 'cinq cent cinquante-trois',
554: 'cinq cent cinquante-quatre',
555: 'cinq cent cinquante-cinq',
556: 'cinq cent cinquante-six',
557: 'cinq cent cinquante-sept',
558: 'cinq cent cinquante-huit',
559: 'cinq cent cinquante-neuf',
560: 'cinq cent soixante',
561: 'cinq cent soixante et un',
562: 'cinq cent soixante-deux',
563: 'cinq cent soixante-trois',
564: 'cinq cent soixante-quatre',
565: 'cinq cent soixante-cinq',
566: 'cinq cent soixante-six',
567: 'cinq cent soixante-sept',
568: 'cinq cent soixante-huit',
569: 'cinq cent soixante-neuf',
570: 'cinq cent soixante-dix',
571: 'cinq cent soixante et onze',
572: 'cinq cent soixante-douze',
573: 'cinq cent soixante-treize',
574: 'cinq cent soixante-quatorze',
575: 'cinq cent soixante-quinze',
576: 'cinq cent soixante-seize',
577: 'cinq cent soixante-dix-sept',
578: 'cinq cent soixante-dix-huit',
579: 'cinq cent soixante-dix-neuf',
580: 'cinq cent quatre-vingts',
581: 'cinq cent quatre-vingt-un',
582: 'cinq cent quatre-vingt-deux',
583: 'cinq cent quatre-vingt-trois',
584: 'cinq cent quatre-vingt-quatre',
585: 'cinq cent quatre-vingt-cinq',
586: 'cinq cent quatre-vingt-six',
587: 'cinq cent quatre-vingt-sept',
588: 'cinq cent quatre-vingt-huit',
589: 'cinq cent quatre-vingt-neuf',
590: 'cinq cent quatre-vingt-dix',
591: 'cinq cent quatre-vingt-onze',
592: 'cinq cent quatre-vingt-douze',
593: 'cinq cent quatre-vingt-treize',
594: 'cinq cent quatre-vingt-quatorze',
595: 'cinq cent quatre-vingt-quinze',
596: 'cinq cent quatre-vingt-seize',
597: 'cinq cent quatre-vingt-dix-sept',
598: 'cinq cent quatre-vingt-dix-huit',
599: 'cinq cent quatre-vingt-dix-neuf',
600: 'six cents',
601: 'six cent un',
602: 'six cent deux',
603: 'six cent trois',
604: 'six cent quatre',
605: 'six cent cinq',
606: 'six cent six',
607: 'six cent sept',
608: 'six cent huit',
609: 'six cent neuf',
610: 'six cent dix',
611: 'six cent onze',
612: 'six cent douze',
613: 'six cent treize',
614: 'six cent quatorze',
615: 'six cent quinze',
616: 'six cent seize',
617: 'six cent dix-sept',
618: 'six cent dix-huit',
619: 'six cent dix-neuf',
620: 'six cent vingt',
621: 'six cent vingt et un',
622: 'six cent vingt-deux',
623: 'six cent vingt-trois',
624: 'six cent vingt-quatre',
625: 'six cent vingt-cinq',
626: 'six cent vingt-six',
627: 'six cent vingt-sept',
628: 'six cent vingt-huit',
629: 'six cent vingt-neuf',
630: 'six cent trente',
631: 'six cent trente et un',
632: 'six cent trente-deux',
633: 'six cent trente-trois',
634: 'six cent trente-quatre',
635: 'six cent trente-cinq',
636: 'six cent trente-six',
637: 'six cent trente-sept',
638: 'six cent trente-huit',
639: 'six cent trente-neuf',
640: 'six cent quarante',
641: 'six cent quarante et un',
642: 'six cent quarante-deux',
643: 'six cent quarante-trois',
644: 'six cent quarante-quatre',
645: 'six cent quarante-cinq',
646: 'six cent quarante-six',
647: 'six cent quarante-sept',
648: 'six cent quarante-huit',
649: 'six cent quarante-neuf',
650: 'six cent cinquante',
651: 'six cent cinquante et un',
652: 'six cent cinquante-deux',
653: 'six cent cinquante-trois',
654: 'six cent cinquante-quatre',
655: 'six cent cinquante-cinq',
656: 'six cent cinquante-six',
657: 'six cent cinquante-sept',
658: 'six cent cinquante-huit',
659: 'six cent cinquante-neuf',
660: 'six cent soixante',
661: 'six cent soixante et un',
662: 'six cent soixante-deux',
663: 'six cent soixante-trois',
664: 'six cent soixante-quatre',
665: 'six cent soixante-cinq',
666: 'six cent soixante-six',
667: 'six cent soixante-sept',
668: 'six cent soixante-huit',
669: 'six cent soixante-neuf',
670: 'six cent soixante-dix',
671: 'six cent soixante et onze',
672: 'six cent soixante-douze',
673: 'six cent soixante-treize',
674: 'six cent soixante-quatorze',
675: 'six cent soixante-quinze',
676: 'six cent soixante-seize',
677: 'six cent soixante-dix-sept',
678: 'six cent soixante-dix-huit',
679: 'six cent soixante-dix-neuf',
680: 'six cent quatre-vingts',
681: 'six cent quatre-vingt-un',
682: 'six cent quatre-vingt-deux',
683: 'six cent quatre-vingt-trois',
684: 'six cent quatre-vingt-quatre',
685: 'six cent quatre-vingt-cinq',
686: 'six cent quatre-vingt-six',
687: 'six cent quatre-vingt-sept',
688: 'six cent quatre-vingt-huit',
689: 'six cent quatre-vingt-neuf',
690: 'six cent quatre-vingt-dix',
691: 'six cent quatre-vingt-onze',
692: 'six cent quatre-vingt-douze',
693: 'six cent quatre-vingt-treize',
694: 'six cent quatre-vingt-quatorze',
695: 'six cent quatre-vingt-quinze',
696: 'six cent quatre-vingt-seize',
697: 'six cent quatre-vingt-dix-sept',
698: 'six cent quatre-vingt-dix-huit',
699: 'six cent quatre-vingt-dix-neuf',
700: 'sept cents',
701: 'sept cent un',
702: 'sept cent deux',
703: 'sept cent trois',
704: 'sept cent quatre',
705: 'sept cent cinq',
706: 'sept cent six',
707: 'sept cent sept',
708: 'sept cent huit',
709: 'sept cent neuf',
710: 'sept cent dix',
711: 'sept cent onze',
712: 'sept cent douze',
713: 'sept cent treize',
714: 'sept cent quatorze',
715: 'sept cent quinze',
716: 'sept cent seize',
717: 'sept cent dix-sept',
718: 'sept cent dix-huit',
719: 'sept cent dix-neuf',
720: 'sept cent vingt',
721: 'sept cent vingt et un',
722: 'sept cent vingt-deux',
723: 'sept cent vingt-trois',
724: 'sept cent vingt-quatre',
725: 'sept cent vingt-cinq',
726: 'sept cent vingt-six',
727: 'sept cent vingt-sept',
728: 'sept cent vingt-huit',
729: 'sept cent vingt-neuf',
730: 'sept cent trente',
731: 'sept cent trente et un',
732: 'sept cent trente-deux',
733: 'sept cent trente-trois',
734: 'sept cent trente-quatre',
735: 'sept cent trente-cinq',
736: 'sept cent trente-six',
737: 'sept cent trente-sept',
738: 'sept cent trente-huit',
739: 'sept cent trente-neuf',
740: 'sept cent quarante',
741: 'sept cent quarante et un',
742: 'sept cent quarante-deux',
743: 'sept cent quarante-trois',
744: 'sept cent quarante-quatre',
745: 'sept cent quarante-cinq',
746: 'sept cent quarante-six',
747: 'sept cent quarante-sept',
748: 'sept cent quarante-huit',
749: 'sept cent quarante-neuf',
750: 'sept cent cinquante',
751: 'sept cent cinquante et un',
752: 'sept cent cinquante-deux',
753: 'sept cent cinquante-trois',
754: 'sept cent cinquante-quatre',
755: 'sept cent cinquante-cinq',
756: 'sept cent cinquante-six',
757: 'sept cent cinquante-sept',
758: 'sept cent cinquante-huit',
759: 'sept cent cinquante-neuf',
760: 'sept cent soixante',
761: 'sept cent soixante et un',
762: 'sept cent soixante-deux',
763: 'sept cent soixante-trois',
764: 'sept cent soixante-quatre',
765: 'sept cent soixante-cinq',
766: 'sept cent soixante-six',
767: 'sept cent soixante-sept',
768: 'sept cent soixante-huit',
769: 'sept cent soixante-neuf',
770: 'sept cent soixante-dix',
771: 'sept cent soixante et onze',
772: 'sept cent soixante-douze',
773: 'sept cent soixante-treize',
774: 'sept cent soixante-quatorze',
775: 'sept cent soixante-quinze',
776: 'sept cent soixante-seize',
777: 'sept cent soixante-dix-sept',
778: 'sept cent soixante-dix-huit',
779: 'sept cent soixante-dix-neuf',
780: 'sept cent quatre-vingts',
781: 'sept cent quatre-vingt-un',
782: 'sept cent quatre-vingt-deux',
783: 'sept cent quatre-vingt-trois',
784: 'sept cent quatre-vingt-quatre',
785: 'sept cent quatre-vingt-cinq',
786: 'sept cent quatre-vingt-six',
787: 'sept cent quatre-vingt-sept',
788: 'sept cent quatre-vingt-huit',
789: 'sept cent quatre-vingt-neuf',
790: 'sept cent quatre-vingt-dix',
791: 'sept cent quatre-vingt-onze',
792: 'sept cent quatre-vingt-douze',
793: 'sept cent quatre-vingt-treize',
794: 'sept cent quatre-vingt-quatorze',
795: 'sept cent quatre-vingt-quinze',
796: 'sept cent quatre-vingt-seize',
797: 'sept cent quatre-vingt-dix-sept',
798: 'sept cent quatre-vingt-dix-huit',
799: 'sept cent quatre-vingt-dix-neuf',
800: 'huit cents',
801: 'huit cent un',
802: 'huit cent deux',
803: 'huit cent trois',
804: 'huit cent quatre',
805: 'huit cent cinq',
806: 'huit cent six',
807: 'huit cent sept',
808: 'huit cent huit',
809: 'huit cent neuf',
810: 'huit cent dix',
811: 'huit cent onze',
812: 'huit cent douze',
813: 'huit cent treize',
814: 'huit cent quatorze',
815: 'huit cent quinze',
816: 'huit cent seize',
817: 'huit cent dix-sept',
818: 'huit cent dix-huit',
819: 'huit cent dix-neuf',
820: 'huit cent vingt',
821: 'huit cent vingt et un',
822: 'huit cent vingt-deux',
823: 'huit cent vingt-trois',
824: 'huit cent vingt-quatre',
825: 'huit cent vingt-cinq',
826: 'huit cent vingt-six',
827: 'huit cent vingt-sept',
828: 'huit cent vingt-huit',
829: 'huit cent vingt-neuf',
830: 'huit cent trente',
831: 'huit cent trente et un',
832: 'huit cent trente-deux',
833: 'huit cent trente-trois',
834: 'huit cent trente-quatre',
835: 'huit cent trente-cinq',
836: 'huit cent trente-six',
837: 'huit cent trente-sept',
838: 'huit cent trente-huit',
839: 'huit cent trente-neuf',
840: 'huit cent quarante',
841: 'huit cent quarante et un',
842: 'huit cent quarante-deux',
843: 'huit cent quarante-trois',
844: 'huit cent quarante-quatre',
845: 'huit cent quarante-cinq',
846: 'huit cent quarante-six',
847: 'huit cent quarante-sept',
848: 'huit cent quarante-huit',
849: 'huit cent quarante-neuf',
850: 'huit cent cinquante',
851: 'huit cent cinquante et un',
852: 'huit cent cinquante-deux',
853: 'huit cent cinquante-trois',
854: 'huit cent cinquante-quatre',
855: 'huit cent cinquante-cinq',
856: 'huit cent cinquante-six',
857: 'huit cent cinquante-sept',
858: 'huit cent cinquante-huit',
859: 'huit cent cinquante-neuf',
860: 'huit cent soixante',
861: 'huit cent soixante et un',
862: 'huit cent soixante-deux',
863: 'huit cent soixante-trois',
864: 'huit cent soixante-quatre',
865: 'huit cent soixante-cinq',
866: 'huit cent soixante-six',
867: 'huit cent soixante-sept',
868: 'huit cent soixante-huit',
869: 'huit cent soixante-neuf',
870: 'huit cent soixante-dix',
871: 'huit cent soixante et onze',
872: 'huit cent soixante-douze',
873: 'huit cent soixante-treize',
874: 'huit cent soixante-quatorze',
875: 'huit cent soixante-quinze',
876: 'huit cent soixante-seize',
877: 'huit cent soixante-dix-sept',
878: 'huit cent soixante-dix-huit',
879: 'huit cent soixante-dix-neuf',
880: 'huit cent quatre-vingts',
881: 'huit cent quatre-vingt-un',
882: 'huit cent quatre-vingt-deux',
883: 'huit cent quatre-vingt-trois',
884: 'huit cent quatre-vingt-quatre',
885: 'huit cent quatre-vingt-cinq',
886: 'huit cent quatre-vingt-six',
887: 'huit cent quatre-vingt-sept',
888: 'huit cent quatre-vingt-huit',
889: 'huit cent quatre-vingt-neuf',
890: 'huit cent quatre-vingt-dix',
891: 'huit cent quatre-vingt-onze',
892: 'huit cent quatre-vingt-douze',
893: 'huit cent quatre-vingt-treize',
894: 'huit cent quatre-vingt-quatorze',
895: 'huit cent quatre-vingt-quinze',
896: 'huit cent quatre-vingt-seize',
897: 'huit cent quatre-vingt-dix-sept',
898: 'huit cent quatre-vingt-dix-huit',
899: 'huit cent quatre-vingt-dix-neuf',
900: 'neuf cents',
901: 'neuf cent un',
902: 'neuf cent deux',
903: 'neuf cent trois',
904: 'neuf cent quatre',
905: 'neuf cent cinq',
906: 'neuf cent six',
907: 'neuf cent sept',
908: 'neuf cent huit',
909: 'neuf cent neuf',
910: 'neuf cent dix',
911: 'neuf cent onze',
912: 'neuf cent douze',
913: 'neuf cent treize',
914: 'neuf cent quatorze',
915: 'neuf cent quinze',
916: 'neuf cent seize',
917: 'neuf cent dix-sept',
918: 'neuf cent dix-huit',
919: 'neuf cent dix-neuf',
920: 'neuf cent vingt',
921: 'neuf cent vingt et un',
922: 'neuf cent vingt-deux',
923: 'neuf cent vingt-trois',
924: 'neuf cent vingt-quatre',
925: 'neuf cent vingt-cinq',
926: 'neuf cent vingt-six',
927: 'neuf cent vingt-sept',
928: 'neuf cent vingt-huit',
929: 'neuf cent vingt-neuf',
930: 'neuf cent trente',
931: 'neuf cent trente et un',
932: 'neuf cent trente-deux',
933: 'neuf cent trente-trois',
934: 'neuf cent trente-quatre',
935: 'neuf cent trente-cinq',
936: 'neuf cent trente-six',
937: 'neuf cent trente-sept',
938: 'neuf cent trente-huit',
939: 'neuf cent trente-neuf',
940: 'neuf cent quarante',
941: 'neuf cent quarante et un',
942: 'neuf cent quarante-deux',
943: 'neuf cent quarante-trois',
944: 'neuf cent quarante-quatre',
945: 'neuf cent quarante-cinq',
946: 'neuf cent quarante-six',
947: 'neuf cent quarante-sept',
948: 'neuf cent quarante-huit',
949: 'neuf cent quarante-neuf',
950: 'neuf cent cinquante',
951: 'neuf cent cinquante et un',
952: 'neuf cent cinquante-deux',
953: 'neuf cent cinquante-trois',
954: 'neuf cent cinquante-quatre',
955: 'neuf cent cinquante-cinq',
956: 'neuf cent cinquante-six',
957: 'neuf cent cinquante-sept',
958: 'neuf cent cinquante-huit',
959: 'neuf cent cinquante-neuf',
960: 'neuf cent soixante',
961: 'neuf cent soixante et un',
962: 'neuf cent soixante-deux',
963: 'neuf cent soixante-trois',
964: 'neuf cent soixante-quatre',
965: 'neuf cent soixante-cinq',
966: 'neuf cent soixante-six',
967: 'neuf cent soixante-sept',
968: 'neuf cent soixante-huit',
969: 'neuf cent soixante-neuf',
970: 'neuf cent soixante-dix',
971: 'neuf cent soixante et onze',
972: 'neuf cent soixante-douze',
973: 'neuf cent soixante-treize',
974: 'neuf cent soixante-quatorze',
975: 'neuf cent soixante-quinze',
976: 'neuf cent soixante-seize',
977: 'neuf cent soixante-dix-sept',
978: 'neuf cent soixante-dix-huit',
979: 'neuf cent soixante-dix-neuf',
980: 'neuf cent quatre-vingts',
981: 'neuf cent quatre-vingt-un',
982: 'neuf cent quatre-vingt-deux',
983: 'neuf cent quatre-vingt-trois',
984: 'neuf cent quatre-vingt-quatre',
985: 'neuf cent quatre-vingt-cinq',
986: 'neuf cent quatre-vingt-six',
987: 'neuf cent quatre-vingt-sept',
988: 'neuf cent quatre-vingt-huit',
989: 'neuf cent quatre-vingt-neuf',
990: 'neuf cent quatre-vingt-dix',
991: 'neuf cent quatre-vingt-onze',
992: 'neuf cent quatre-vingt-douze',
993: 'neuf cent quatre-vingt-treize',
994: 'neuf cent quatre-vingt-quatorze',
995: 'neuf cent quatre-vingt-quinze',
996: 'neuf cent quatre-vingt-seize',
997: 'neuf cent quatre-vingt-dix-sept',
998: 'neuf cent quatre-vingt-dix-huit',
999: 'neuf cent quatre-vingt-dix-neuf'
}
const nbString = nb.toString()
let classeDesMilliards = ''
if (nbString.substring(nbString.length - 12, nbString.length - 9).length > 0) {
classeDesMilliards = dictionnaire[nbString.substring(nbString.length - 12, nbString.length - 9).replace(/^0{1,2}/, '')].replaceAll(' ', '-')
}
let classeDesMillions = ''
if (nbString.substring(nbString.length - 9, nbString.length - 6).length > 0) {
classeDesMillions = dictionnaire[nbString.substring(nbString.length - 9, nbString.length - 6).replace(/^0{1,2}/, '')].replaceAll(' ', '-')
}
let classeDesMilliers = ''
if (nbString.substring(nbString.length - 6, nbString.length - 3) === '080' || nbString.substring(nbString.length - 6, nbString.length - 3) === '80') {
classeDesMilliers = 'quatre-vingt'
} else if (nbString.substring(nbString.length - 5, nbString.length - 3) === '00' && nbString.substring(nbString.length - 6, nbString.length - 5) !== '1') {
classeDesMilliers = dictionnaire[nbString.substring(nbString.length - 6, nbString.length - 3).replace(/^0{1,2}/, '')].replaceAll(' ', '-').replace('cents', 'cent')
} else if (nbString.substring(nbString.length - 6, nbString.length - 3).length > 0) {
classeDesMilliers = dictionnaire[nbString.substring(nbString.length - 6, nbString.length - 3).replace(/^0{1,2}/, '')].replaceAll(' ', '-')
}
let classeDesUnites = ''
if (nbString.substring(nbString.length - 3, nbString.length).length > 0) {
classeDesUnites = dictionnaire[nbString.substring(nbString.length - 3, nbString.length).replace(/^0{1,2}/, '')].replaceAll(' ', '-')
}
let result = ''
if (classeDesMilliards.length > 1) {
classeDesMilliards === 'un' ? result += classeDesMilliards + '-milliard' : result += classeDesMilliards + '-milliards'
if (classeDesMillions !== 'zéro' || classeDesMilliers !== 'zéro' || classeDesUnites !== 'zéro') {
result += '-'
}
}
if (classeDesMillions.length > 1 && classeDesMillions !== 'zéro') {
classeDesMillions === 'un' ? result += classeDesMillions + '-million' : result += classeDesMillions + '-millions'
if (classeDesMilliers !== 'zéro' || classeDesUnites !== 'zéro') {
result += '-'
}
}
if (classeDesMilliers.length > 1 && classeDesMilliers !== 'zéro') {
classeDesMilliers === 'un' ? result += 'mille' : result += classeDesMilliers + '-mille'
if (classeDesUnites !== 'zéro') {
result += '-'
}
}
if (classeDesUnites.length > 1 && classeDesUnites !== 'zéro') {
result += classeDesUnites
}
result = result.replace('deux-cents-mille', 'deux-cent-mille')
result = result.replace('trois-cents-mille', 'trois-cent-mille')
result = result.replace('quatre-cents-mille', 'quatre-cent-mille')
result = result.replace('cinq-cents-mille', 'cinq-cent-mille')
result = result.replace('six-cents-mille', 'six-cent-mille')
result = result.replace('sept-cents-mille', 'sept-cent-mille')
result = result.replace('huit-cents-mille', 'huit-cent-mille')
result = result.replace('neuf-cents-mille', 'neuf-cent-mille')
return result
}
/**
* @author Jean-Claude Lhote
* @param {number} min Valeur minimum pour la solution
* @param {number} max Valeur maximum pour la solution
* Cette fonction produit aléatoirement un tirage de 5 nombres, une solution, un tableau contenant les calculs successifs, une chaine contenant l'expression mathador correspondante
* @returns {array} [tirage=[a,b,c,d,e],solution (compris entre min et max),operationsSuccessives=[string1,string2,string3,string4,string5],expression]
* les string1 à 5 ainsi que l'expresion sont ) mettre en mode maths.
* sert dans les exercices CM019,
*/
export function TrouverSolutionMathador (
min,
max,
A = 1,
B = 4,
C = 8,
D = 3,
E = 5
) {
let eureka
let a
let b
let c
let d
let e
let tirage
let nombresRestants
let operationsRestantes
let expressionEnCoursF
let expressionEnCoursD
let op
let part1f
let part2f
let part1d
let part2d
let operationsSuccessives = []
let solution
const listeChoix = [
1,
2,
2,
3,
3,
4,
4,
4,
4,
5,
6,
6,
6,
6,
7,
7,
8,
8,
8,
8,
9,
9,
9,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20
]
eureka = false
const nbDetermines = arguments.length - 2
while (eureka === false) {
tirage = []
if (nbDetermines < 1) a = parseInt(choice(listeChoix))
else a = A
if (nbDetermines < 2) { b = parseInt(choice(listeChoix, [13, 14, 15, 16, 17, 18, 19, 20, a])) } else b = B
if (nbDetermines < 3) {
c = parseInt(
choice(listeChoix, [12, 13, 14, 15, 16, 17, 18, 19, 20, a, b])
)
} else c = C
if (nbDetermines < 4) {
d = parseInt(
choice(listeChoix, [12, 13, 14, 15, 16, 17, 18, 19, 20, b, c])
)
} else d = D
if (nbDetermines < 5) { e = parseInt(choice(listeChoix, [12, 13, 14, 15, 16, 17, 18, 19, 20])) } else e = E
tirage.push(a, b, c, d, e)
nombresRestants = shuffle(tirage)
operationsRestantes = ['\\times', '+', '-', '\\div']
operationsRestantes = shuffle(operationsRestantes)
expressionEnCoursF = [
`${nombresRestants[0]}`,
`${nombresRestants[1]}`,
`${nombresRestants[2]}`,
`${nombresRestants[3]}`,
`${nombresRestants[4]}`
]
expressionEnCoursD = [
`${nombresRestants[0]}`,
`${nombresRestants[1]}`,
`${nombresRestants[2]}`,
`${nombresRestants[3]}`,
`${nombresRestants[4]}`
]
while (nombresRestants.length > 1) {
b = nombresRestants.pop()
a = nombresRestants.pop()
part2f = expressionEnCoursF.pop()
part1f = expressionEnCoursF.pop()
part2d = expressionEnCoursD.pop()
part1d = expressionEnCoursD.pop()
op = operationsRestantes.pop()
if (op === '\\times') {
c = a * b
expressionEnCoursF.push(`${part1f}${op}${part2f}`)
expressionEnCoursD.push(`${part1d}${op}${part2d}`)
nombresRestants.push(c)
} else if (op === '\\div') {
if (a % b === 0) {
c = a / b
if (part1f[0] === '\\') {
part1f = part1f.substring(6, part1f.length)
part1f = part1f.substring(0, part1f.length - 7)
}
if (part2f[0] === '\\') {
part2f = part2f.substring(6, part2f.length)
part2f = part2f.substring(0, part2f.length - 7)
}
expressionEnCoursF.push(`\\dfrac{${part1f}}{${part2f}}`)
expressionEnCoursD.push(`${part1d}${op}${part2d}`)
nombresRestants.push(c)
} else break
} else if (op === '-') {
if (a > b) {
c = a - b
expressionEnCoursF.push(
`\\left(${part1f}${op}${part2f}\\right)`
)
expressionEnCoursD.push(
`\\left(${part1d}${op}${part2d}\\right)`
)
nombresRestants.push(c)
} else break
} else if (op === '+') {
c = a + b
if (part2f.substring(0, 2) === '\\l') {
part2f = part2f.substring(6, part2f.length)
part2f = part2f.substring(0, part2f.length - 7)
}
expressionEnCoursF.push(`\\left(${part1f}${op}${part2f}\\right)`)
if (part2d.substring(0, 2) === '\\l') {
part2d = part2d.substring(6, part2d.length)
part2d = part2d.substring(0, part2d.length - 7)
}
expressionEnCoursD.push(`\\left(${part1d}${op}${part2d}\\right)`)
nombresRestants.push(c)
}
operationsSuccessives.push(`${a}` + op + `${b}=${c}`)
}
if (nombresRestants.length === 1 && operationsRestantes.length === 0) {
solution = nombresRestants[0]
if (solution >= min && solution <= max) {
eureka = true
if (
expressionEnCoursF[0][0] === '\\' &&
expressionEnCoursF[0][1] === 'l'
) {
expressionEnCoursF[0] = expressionEnCoursF[0].substring(
6,
expressionEnCoursF[0].length
)
expressionEnCoursF[0] = expressionEnCoursF[0].substring(
0,
expressionEnCoursF[0].length - 7
)
}
if (
expressionEnCoursD[0][0] === '\\' &&
expressionEnCoursD[0][1] === 'l'
) {
expressionEnCoursD[0] = expressionEnCoursD[0].substring(
6,
expressionEnCoursD[0].length
)
expressionEnCoursD[0] = expressionEnCoursD[0].substring(
0,
expressionEnCoursD[0].length - 7
)
}
return [
tirage,
solution,
operationsSuccessives,
expressionEnCoursF,
expressionEnCoursD
]
} else operationsSuccessives = []
} else operationsSuccessives = []
}
}
// Gestion du fichier à télécharger
export function telechargeFichier (text, filename) {
const element = document.createElement('a')
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text))
element.setAttribute('download', filename)
element.style.display = 'none'
document.body.appendChild(element)
element.click()
document.body.removeChild(element)
}
// Gestion des styles LaTeX
/**
* Renvoie un texte avec le préambule d'un fichier LaTeX
* @param {string} Le titre de l'entête
* @author Rémi Angot
*/
export function introLatex (entete = 'Exercices', listePackages = '') {
let isImpressionRectoVerso = false
const checkBoxImpressionRectoVerso = document.getElementById('impression_recto_verso')
if (checkBoxImpressionRectoVerso !== null) isImpressionRectoVerso = checkBoxImpressionRectoVerso.checked
if (entete === '') { entete = 'Exercices' }
return `\\documentclass[${isImpressionRectoVerso ? 'twoside,' : ''}12pt,svgnames]{article}
\\usepackage[a4paper,left=1.5cm,right=1.5cm,top=2cm,bottom=2cm]{geometry}
%\\usepackage[utf8]{inputenc}
%\\usepackage[T1]{fontenc}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% EXIT WARNING DÛ À LA COMPILATION XETEX %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\\usepackage{ifxetex}
\\ifxetex
\\usepackage{fontspec}
\\else
\\usepackage[T1]{fontenc}
\\usepackage[utf8]{inputenc}
\\usepackage{lmodern}
\\fi
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\\usepackage[french]{babel}
\\usepackage{multicol}
\\usepackage{calc}
\\usepackage{enumerate}
\\usepackage{enumitem}
\\usepackage{graphicx}
\\usepackage{tabularx}
%\\usepackage[autolanguage]{numprint}
\\usepackage[autolanguage,np]{numprint}
\\usepackage{hyperref}
\\usepackage{amsmath,amsfonts,amssymb,mathrsfs}
\\usepackage{cancel}
\\usepackage{textcomp}
\\usepackage{gensymb}
\\usepackage{eurosym}
%\\DeclareUnicodeCharacter{20AC}{\\euro{}} %Incompatible avec XeLaTeX
\\usepackage{fancyhdr,lastpage}
\\pagestyle{fancy}
\\usepackage{fancybox}
\\usepackage{setspace}
\\usepackage{colortbl}
\\usepackage{xcolor}
\\definecolor{nombres}{cmyk}{0,.8,.95,0}
\\definecolor{gestion}{cmyk}{.75,1,.11,.12}
\\definecolor{gestionbis}{cmyk}{.75,1,.11,.12}
\\definecolor{grandeurs}{cmyk}{.02,.44,1,0}
\\definecolor{geo}{cmyk}{.62,.1,0,0}
\\definecolor{algo}{cmyk}{.69,.02,.36,0}
\\definecolor{correction}{cmyk}{.63,.23,.93,.06}
\\usepackage{pgf,tikz}
\\usetikzlibrary{babel,arrows,calc,fit,patterns,plotmarks,shapes.geometric,shapes.misc,shapes.symbols,shapes.arrows,
shapes.callouts, shapes.multipart, shapes.gates.logic.US,shapes.gates.logic.IEC, er, automata,backgrounds,chains,topaths,trees,petri,mindmap,matrix, calendar, folding,fadings,through,positioning,scopes,decorations.fractals,decorations.shapes,decorations.text,decorations.pathmorphing,decorations.pathreplacing,decorations.footprints,decorations.markings,shadows}
\\setlength{\\parindent}{0mm}
\\renewcommand{\\arraystretch}{1.5}
\\newcounter{exo}
\\setcounter{exo}{0}
\\newcommand{\\exo}[1]{
\\stepcounter{exo}
\\subsection*{Exercice \\no{\\theexo} \\textmd{\\normalsize #1}}
}
\\renewcommand{\\labelenumi}{\\textbf{\\theenumi{}.}}
\\renewcommand{\\labelenumii}{\\textbf{\\theenumii{}.}}
\\newcommand{\\version}[1]{\\fancyhead[R]{Version #1}}
\\setlength{\\fboxsep}{3mm}
\\newenvironment{correction}{\\newpage\\fancyhead[C]{\\textbf{Correction}}\\setcounter{exo}{0}}{\\clearpage}
\\fancyhead[C]{\\textbf{${entete}}}
\\fancyfoot{}
\\fancyfoot[R]{\\scriptsize Coopmaths.fr -- CC-BY-SA}
\\setlength{\\headheight}{14.5pt}
${preambulePersonnalise(listePackages)}
\\begin{document}
`
}
/**
* Renvoie un texte avec le préambule d'un fichier LaTeX
* @param {string} Le titre de l'entête
* @author Rémi Angot
*/
export function introLatexCan (entete = 'Course aux nombres', listePackages = '') {
let isImpressionRectoVerso = false
const checkBoxImpressionRectoVerso = document.getElementById('impression_recto_verso')
if (checkBoxImpressionRectoVerso !== null) isImpressionRectoVerso = checkBoxImpressionRectoVerso.checked
if (entete === '') { entete = 'Course aux nombres' }
// return `\\documentclass[12pt, landscape]{article}
return `\\documentclass[${isImpressionRectoVerso ? 'twoside,' : ''}12pt,svgnames]{article}
\\usepackage[left=1.5cm,right=1.5cm,top=2cm,bottom=2cm]{geometry}
%\\usepackage[utf8]{inputenc}
%\\usepackage[T1]{fontenc}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% EXIT WARNING DÛ À LA COMPILATION XETEX %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\\usepackage{ifxetex}
\\ifxetex
\\usepackage{fontspec}
\\else
\\usepackage[T1]{fontenc}
\\usepackage[utf8]{inputenc}
\\usepackage{lmodern}
\\fi
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\\usepackage[french]{babel}
\\usepackage{multicol}
\\usepackage{calc}
\\usepackage{enumerate}
\\usepackage{enumitem}
\\usepackage{graphicx}
\\usepackage{tabularx}
%\\usepackage[autolanguage]{numprint}
\\usepackage[autolanguage,np]{numprint}
\\usepackage{hyperref}
\\usepackage{amsmath,amsfonts,amssymb,mathrsfs}
\\usepackage{cancel}
\\usepackage{textcomp}
\\usepackage{gensymb}
\\usepackage{eurosym}
%\\DeclareUnicodeCharacter{20AC}{\\euro{}} %Incompatible avec XeLaTeX
\\usepackage{fancyhdr,lastpage}
\\pagestyle{fancy}
\\usepackage{fancybox}
\\usepackage{setspace}
\\usepackage{colortbl}
\\usepackage{xcolor}
\\definecolor{nombres}{cmyk}{0,.8,.95,0}
\\definecolor{gestion}{cmyk}{.75,1,.11,.12}
\\definecolor{gestionbis}{cmyk}{.75,1,.11,.12}
\\definecolor{grandeurs}{cmyk}{.02,.44,1,0}
\\definecolor{geo}{cmyk}{.62,.1,0,0}
\\definecolor{algo}{cmyk}{.69,.02,.36,0}
\\definecolor{correction}{cmyk}{.63,.23,.93,.06}
\\usepackage{pgf,tikz}
\\usetikzlibrary{babel,arrows,calc,fit,patterns,plotmarks,shapes.geometric,shapes.misc,shapes.symbols,shapes.arrows,
shapes.callouts, shapes.multipart, shapes.gates.logic.US,shapes.gates.logic.IEC, er, automata,backgrounds,chains,topaths,trees,petri,mindmap,matrix, calendar, folding,fadings,through,positioning,scopes,decorations.fractals,decorations.shapes,decorations.text,decorations.pathmorphing,decorations.pathreplacing,decorations.footprints,decorations.markings,shadows}
\\setlength{\\parindent}{0mm}
\\renewcommand{\\arraystretch}{1.5}
\\newcounter{exo}
\\setcounter{exo}{0}
\\newcommand{\\exo}[1]{
\\stepcounter{exo}
\\subsection*{Exercice \\no{\\theexo} \\textmd{\\normalsize #1}}
}
\\renewcommand{\\labelenumi}{\\textbf{\\theenumi{}.}}
\\renewcommand{\\labelenumii}{\\textbf{\\theenumii{}.}}
\\newcommand{\\version}[1]{\\fancyhead[R]{Version #1}}
\\setlength{\\fboxsep}{3mm}
\\newenvironment{correction}{\\newpage\\fancyhead[C]{\\textbf{Correction}}\\setcounter{exo}{0}}{}
\\fancyhead[C]{}
\\fancyfoot{}
\\fancyfoot[R]{\\scriptsize Coopmaths.fr -- CC-BY-SA}
\\setlength{\\headheight}{14.5pt}
\\fancypagestyle{premierePage}
{
\\fancyhead[C]{\\textsc{${entete}}}
}
${preambulePersonnalise(listePackages)}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% SPÉCIFIQUE SUJETS CAN %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\\usepackage{longtable}
\\tikzset{
mybox/.style={
rectangle,
drop shadow,
inner sep=17pt,
draw=gray,
shade,
top color=gray,
every shadow/.append style={fill=gray!40},
bottom color=gray!20
}
}
\\newcommand\\MyBox[2][]{%
\\tikz\\node[mybox,#1] {#2};
}
% Un compteur pour les questions CAN
\\newcounter{nbEx}
% Pour travailler avec les compteurs
\\usepackage{totcount}
\\regtotcounter{nbEx}
% Une checkmark !
\\def\\checkmark{\\tikz\\fill[scale=0.4](0,.35) -- (.25,0) -- (1,.7) -- (.25,.15) -- cycle;}
% Repiqué sans vergogne dans lemanuel TikZ pour l'impatient
\\def\\arete{3} \\def\\epaisseur{5} \\def\\rayon{2}
\\newcommand{\\ruban}{(0,0)
++(0:0.57735*\\arete-0.57735*\\epaisseur+2*\\rayon)
++(-30:\\epaisseur-1.73205*\\rayon)
arc (60:0:\\rayon) -- ++(90:\\epaisseur)
arc (0:60:\\rayon) -- ++(150:\\arete)
arc (60:120:\\rayon) -- ++(210:\\epaisseur)
arc (120:60:\\rayon) -- cycle}
\\newcommand{\\dureeCan}{[Temps total à modifier juste après le \\textbackslash begin\\{document\\}]}
\\newcommand{\\titreSujetCan}{\\textbf{[Ligne ci-dessous à modifier juste après le \\textbackslash begin\\{document\\}]\\\\Sujet niveau NN - Mois Année}}
\\newcommand{\\mobiusCan}{
% Repiqué sans vergogne dans lemanuel TikZ pour l'impatient
\\begin{tikzpicture}[very thick,top color=white,bottom color=gray,scale=1.2]
\\shadedraw \\ruban;
\\shadedraw [rotate=120] \\ruban;
\\shadedraw [rotate=-120] \\ruban;
\\draw (-60:4) node[scale=5,rotate=30]{CAN};
\\draw (180:4) node[scale=3,rotate=-90]{MathALEA};
\\clip (0,-6) rectangle (6,6); % pour croiser
\\shadedraw \\ruban;
\\draw (60:4) node [gray,xscale=2.5,yscale=2.5,rotate=-30]{CoopMaths};
\\end{tikzpicture}
}
\\newcommand{\\pageDeGardeCan}[1]{
% #1 --> nom du compteur pour le nombre de questions
%\\vspace*{10mm}
\\textsc{Nom} : \\makebox[.35\\linewidth]{\\dotfill} \\hfill \\textsc{Prénom} : \\makebox[.35\\linewidth]{\\dotfill}
\\vspace{10mm}
\\textsc{Classe} : \\makebox[.33\\linewidth]{\\dotfill} \\hfill
\\MyBox{\\Large\\textsc{Score} : \\makebox[.15\\linewidth]{\\dotfill} / \\total{#1}}
\\par\\medskip \\hrulefill \\par
\\checkmark \\textit{\\textbf{Durée : \\dureeCan~minutes}}
\\smallskip
\\checkmark \\textit{L'épreuve comporte \\total{#1} questions.}
\\smallskip
\\checkmark \\textit{L'usage de la calculatrice et du brouillon sont interdits.}
\\smallskip
\\checkmark \\textit{Il n'est pas permis d'écrire des calculs intermédiaires.}
\\par \\hrulefill \\par\\vspace{5mm}
\\begin{center}
\\textsc{\\titreSujetCan}
\\par\\vspace{5mm}
\\mobiusCan
\\end{center}
}
% Structure globale pour les tableaux des livrets CAN
\\newcommand{\\structureTableauCan}[1]{
% #1 --> corps de tableau
\\renewcommand*{\\arraystretch}{2.5}
\\begin{spacing}{1.1}
\\begin{longtable}{|>{\\columncolor{gray!20}\\centering}m{0.05\\textwidth}|>{\\centering}m{0.45\\textwidth}|>{\\centering}m{0.35\\textwidth}|>{\\centering}p{0.1\\textwidth}|}%
\\hline
\\rowcolor{gray!20}\\#&Énoncé&Réponse&Jury\\tabularnewline \\hline
%\\endfirsthead
%\\hline
%\\rowcolor{gray!20}\\#&Énoncé&Réponse&Jury\\tabularnewline \\hline
%\\endhead
#1
\\end{longtable}
\\end{spacing}
\\renewcommand*{\\arraystretch}{1}
}
\\begin{document}
\\thispagestyle{premierePage}
% Décomenter et modifier les deux lignes suivantes pour ajuster les textes
%\\renewcommand{\\dureeCan}{ma durée en minutes ici}
%\\renewcommand{\\titreSujetCan}{\\textbf{mon titre ici}}
`
}
/**
* Renvoie un texte avec le préambule d'un fichier LaTeX avec le style CoopMaths
* @author Rémi Angot
*/
export function introLatexCoop (listePackages) {
let isImpressionRectoVerso = false
const checkBoxImpressionRectoVerso = document.getElementById('impression_recto_verso')
if (checkBoxImpressionRectoVerso !== null) isImpressionRectoVerso = checkBoxImpressionRectoVerso.checked
const introLatexCoop = `\\documentclass[${isImpressionRectoVerso ? 'twoside,' : ''}12pt,svgnames]{article}
\\usepackage[left=1.5cm,right=1.5cm,top=4cm,bottom=2cm]{geometry}
%\\usepackage[utf8]{inputenc}
%\\usepackage[T1]{fontenc}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% EXIT WARNING DÛ À LA COMPILATION XETEX %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\\usepackage{ifxetex}
\\ifxetex
\\usepackage{fontspec}
\\else
\\usepackage[T1]{fontenc}
\\usepackage[utf8]{inputenc}
\\usepackage{lmodern}
\\fi
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\\usepackage[french]{babel}
\\usepackage{hyperref}
\\usepackage{multicol}
\\usepackage{calc}
\\usepackage{enumerate}
\\usepackage{enumitem}
\\usepackage{graphicx}
\\usepackage{tabularx}
%\\usepackage[autolanguage]{numprint}
\\usepackage[autolanguage,np]{numprint}
\\usepackage{amsmath,amsfonts,amssymb,mathrsfs}
\\usepackage{cancel}
\\usepackage{textcomp}
\\usepackage{gensymb}
\\usepackage{eurosym}
%\\DeclareUnicodeCharacter{20AC}{\\euro{}} %Incompatible avec XeLaTeX
\\usepackage{fancyhdr,lastpage}
\\pagestyle{fancy}
\\usepackage{fancybox}
\\usepackage{setspace}
\\usepackage{xcolor}
\\usepackage{pgf,tikz} % Pour les images et figures géométriques
\\usetikzlibrary{babel,arrows,calc,fit,patterns,plotmarks,shapes.geometric,shapes.misc,shapes.symbols,shapes.arrows,
shapes.callouts, shapes.multipart, shapes.gates.logic.US,shapes.gates.logic.IEC, er, automata,backgrounds,chains,topaths,trees,petri,mindmap,matrix, calendar, folding,fadings,through,positioning,scopes,decorations.fractals,decorations.shapes,decorations.text,decorations.pathmorphing,decorations.pathreplacing,decorations.footprints,decorations.markings,shadows}
\\renewcommand{\\headrulewidth}{0pt}
\\renewcommand{\\footrulewidth}{0pt}
\\fancyhead[L]{}
\\fancyhead[R]{}
%%% COULEURS %%%
\\definecolor{nombres}{cmyk}{0,.8,.95,0}
\\definecolor{gestion}{cmyk}{.75,1,.11,.12}
\\definecolor{gestionbis}{cmyk}{.75,1,.11,.12}
\\definecolor{grandeurs}{cmyk}{.02,.44,1,0}
\\definecolor{geo}{cmyk}{.62,.1,0,0}
\\definecolor{algo}{cmyk}{.69,.02,.36,0}
\\definecolor{correction}{cmyk}{.63,.23,.93,.06}
\\usepackage{colortbl}
\\arrayrulecolor{couleur_theme} % Couleur des filets des tableaux
%%% MISE EN PAGE %%%
\\setlength{\\parindent}{0mm}
\\renewcommand{\\arraystretch}{1.5}
\\renewcommand{\\labelenumi}{\\textbf{\\theenumi{}.}}
\\renewcommand{\\labelenumii}{\\textbf{\\theenumii{}.}}
\\setlength{\\fboxsep}{3mm}
\\setlength{\\headheight}{14.5pt}
\\spaceskip=2\\fontdimen2\\font plus 3\\fontdimen3\\font minus3\\fontdimen4\\font\\relax %Pour doubler l'espace entre les mots
\\newcommand{\\numb}[1]{ % Dessin autour du numéro d'exercice
\\begin{tikzpicture}[overlay,yshift=-.3cm,scale=.8]
\\draw[fill=couleur_numerotation,couleur_numerotation](-.3,0)rectangle(.5,.8);
\\draw[line width=.05cm,couleur_numerotation,fill=white] (0,0)--(.5,.5)--(1,0)--(.5,-.5)--cycle;
\\node[couleur_numerotation] at (.5,0) { \\large \\bfseries #1};
\\draw (-.4,.8) node[white,anchor=north west]{\\bfseries EX};
\\end{tikzpicture}
}
%%% NUMEROS DES EXERCICES %%%
\\usepackage{titlesec} % Le titre de section est un numéro d'exercice avec sa consigne alignée à gauche.
\\titleformat{\\section}{}{\\numb{\\arabic{section}}}{1cm}{\\hspace{0em}}{}
\\newcommand{\\exo}[1]{ % Un exercice est une nouvelle section avec la consigne écrite en caractêres normaux
\\section{\\textmd{#1}}
\\medskip
}
%%% ENVIRONNEMENTS - CADRES %%%
\\usepackage[framemethod=tikz]{mdframed}
\\newmdenv[linecolor=couleur_theme, linewidth=3pt,topline=true,rightline=false,bottomline=false,frametitlerule=false,frametitlefont={\\color{couleur_theme}\\bfseries},frametitlerulewidth=1pt]{methode}
\\newmdenv[startcode={\\setlength{\\multicolsep}{0cm}\\setlength{\\columnsep}{.2cm}\\setlength{\\columnseprule}{0pt}\\vspace{0cm}},linecolor=white, linewidth=3pt,innerbottommargin=10pt,innertopmargin=5pt,innerrightmargin=20pt,splittopskip=20pt,splitbottomskip=10pt,everyline=true,tikzsetting={draw=couleur_theme,line width=4pt,dashed,dash pattern= on 10pt off 10pt},frametitleaboveskip=-.6cm,frametitle={\\tikz\\node[anchor= east,rectangle,fill=white]{\\textcolor{couleur_theme}{\\raisebox{-.3\\height}{}\\; \\bfseries \\Large Objectifs}};}]{objectif}
\\newmdenv[startcode={\\colorlet{couleur_numerotation}{correction}\\renewcommand{\\columnseprulecolor}{\\color{correction}}
\\setcounter{section}{0}\\arrayrulecolor{correction}},linecolor=white, linewidth=4pt,innerbottommargin=10pt,innertopmargin=5pt,splittopskip=20pt,splitbottomskip=10pt,everyline=true,frametitle=correction,tikzsetting={draw=correction,line width=3pt,dashed,dash pattern= on 15pt off 10pt},frametitleaboveskip=-.4cm,frametitle={\\tikz\\node[anchor= east,rectangle,fill=white]{\\; \\textcolor{correction}{\\raisebox{-.3\\height}{}\\; \\bfseries \\Large Corrections}};}]{correction}
\\newmdenv[roundcorner=0,linewidth=0pt,frametitlerule=false, backgroundcolor=gray!40,leftmargin=8cm]{remarque}
% echelle pour le dé
\\def \\globalscale {0.04}
% abscisse initiale pour les chevrons
\\def \\xini {3}
\\newcommand{\\theme}[4]
{
%\\theme{nombres|gestion|grandeurs|geo|algo}{Texte (entrainement, évaluation, mise en route...}{numéro de version ou vide}{titre du thême et niveau}
\\fancyhead[C]{
%Tracé du dé
\\begin{tikzpicture}[y=0.80pt, x=0.80pt, yscale=-\\globalscale, xscale=\\globalscale,remember picture, overlay, shift={(current page.north west)},xshift=17cm,yshift=9.5cm,fill=couleur_theme]
%%%%Arc supérieur gauche%%%%
\\path[fill](523,1424)..controls(474,1413)and(404,1372)..(362,1333)..controls(322,1295)and(313,1272)..(331,1254)..controls(348,1236)and(369,1245)..(410,1283)..controls(458,1328)and(517,1356)..(575,1362)..controls(635,1368)and(646,1375)..(643,1404)..controls(641,1428)and(641,1428)..(596,1430)..controls(571,1431)and(538,1428)..(523,1424)--cycle;
%%%%Dé face supérieur%%%%
\\path[fill](512,1272)..controls(490,1260)and(195,878)..(195,861)..controls(195,854)and(198,846)..(202,843)..controls(210,838)and(677,772)..(707,772)..controls(720,772)and(737,781)..(753,796)..controls(792,833)and(1057,1179)..(1057,1193)..controls(1057,1200)and(1053,1209)..(1048,1212)..controls(1038,1220)and(590,1283)..(551,1282)..controls(539,1282)and(521,1278)..(512,1272)--cycle;
%%%%Dé faces gauche et droite%%%%
\\path[fill](1061,1167)..controls(1050,1158)and(978,1068)..(900,967)..controls(792,829)and(756,777)..(753,756)--(748,729)--(724,745)..controls(704,759)and(660,767)..(456,794)..controls(322,813)and(207,825)..(200,822)..controls(193,820)and(187,812)..(187,804)..controls(188,797)and(229,688)..(279,563)..controls(349,390)and(376,331)..(391,320)..controls(406,309)and(462,299)..(649,273)..controls(780,254)and(897,240)..(907,241)..controls(918,243)and(927,249)..(928,256)..controls(930,264)and(912,315)..(889,372)..controls(866,429)and(848,476)..(849,477)..controls(851,479)and(872,432)..(897,373)..controls(936,276)and(942,266)..(960,266)..controls(975,266)and(999,292)..(1089,408)..controls(1281,654)and(1290,666)..(1290,691)..controls(1290,720)and(1104,1175)..(1090,1180)..controls(1085,1182)and (1071,1176)..(1061,1167)--cycle;
%%%%Arc inférieur bas%%%%
\\path[fill](1329,861)..controls(1316,848)and(1317,844)..(1339,788)..controls(1364,726)and(1367,654)..(1347,591)..controls(1330,539)and(1338,522)..(1375,526)..controls(1395,528)and(1400,533)..(1412,566)..controls(1432,624)and(1426,760)..(1401,821)..controls(1386,861)and(1380,866)..(1361,868)..controls(1348,870)and(1334,866)..(1329,861)--cycle;
%%%%Arc inférieur gauche%%%%
\\path[fill](196,373)..controls(181,358)and(186,335)..(213,294)..controls(252,237)and(304,190)..(363,161)..controls(435,124)and(472,127)..(472,170)..controls(472,183)and(462,192)..(414,213)..controls(350,243)and(303,283)..(264,343)..controls(239,383)and(216,393)..(196,373)--cycle;
\\end{tikzpicture}
\\begin{tikzpicture}[remember picture,overlay]
\\node[anchor=north east,inner sep=0pt] at ($(current page.north east)+(0,-.8cm)$) {};
\\node[anchor=east, fill=white] at ($(current page.north east)+(-18.8,-2.3cm)$) {\\footnotesize \\bfseries{MathALEA}};
\\end{tikzpicture}
\\begin{tikzpicture}[line cap=round,line join=round,remember picture, overlay, shift={(current page.north west)},yshift=-8.5cm]
\\fill[fill=couleur_theme] (0,5) rectangle (21,6);
\\fill[fill=couleur_theme] (\\xini,6)--(\\xini+1.5,6)--(\\xini+2.5,7)--(\\xini+1.5,8)--(\\xini,8)--(\\xini+1,7)-- cycle;
\\fill[fill=couleur_theme] (\\xini+2,6)--(\\xini+2.5,6)--(\\xini+3.5,7)--(\\xini+2.5,8)--(\\xini+2,8)--(\\xini+3,7)-- cycle;
\\fill[fill=couleur_theme] (\\xini+3,6)--(\\xini+3.5,6)--(\\xini+4.5,7)--(\\xini+3.5,8)--(\\xini+3,8)--(\\xini+4,7)-- cycle;
\\node[color=white] at (10.5,5.5) {\\LARGE \\bfseries{ \\MakeUppercase{ #4}}};
\\end{tikzpicture}
\\begin{tikzpicture}[remember picture,overlay]
\\node[anchor=north east,inner sep=0pt] at ($(current page.north east)+(0,-.8cm)$) {};
\\node[anchor=east, fill=white] at ($(current page.north east)+(-2,-1.5cm)$) {\\Huge \\textcolor{couleur_theme}{\\bfseries{\\#}} \\bfseries{#2} \\textcolor{couleur_theme}{\\bfseries \\MakeUppercase{#3}}};
\\end{tikzpicture}
}
\\fancyfoot[R]{
%\\scriptsize Coopmaths.fr -- CC-BY-SA
\\begin{tikzpicture}[remember picture,overlay]
\\node[anchor=south east] at ($(current page.south east)+(-2,0.25cm)$) {\\scriptsize {\\bfseries \\href{https://coopmaths.fr/}{Coopmaths.fr} -- \\href{http://creativecommons.fr/licences/}{CC-BY-SA}}};
\\end{tikzpicture}
\\begin{tikzpicture}[line cap=round,line join=round,remember picture, overlay,xscale=0.5,yscale=0.5, shift={(current page.south west)},xshift=35.7cm,yshift=-6cm]
\\fill[fill=couleur_theme] (\\xini,6)--(\\xini+1.5,6)--(\\xini+2.5,7)--(\\xini+1.5,8)--(\\xini,8)--(\\xini+1,7)-- cycle;
\\fill[fill=couleur_theme] (\\xini+2,6)--(\\xini+2.5,6)--(\\xini+3.5,7)--(\\xini+2.5,8)--(\\xini+2,8)--(\\xini+3,7)-- cycle;
\\fill[fill=couleur_theme] (\\xini+3,6)--(\\xini+3.5,6)--(\\xini+4.5,7)--(\\xini+3.5,8)--(\\xini+3,8)--(\\xini+4,7)-- cycle;
\\end{tikzpicture}
}
\\fancyfoot[C]{}
\\colorlet{couleur_theme}{#1}
\\colorlet{couleur_numerotation}{couleur_theme}
\\def\\iconeobjectif{icone-objectif-#1}
\\def\\urliconeomethode{icone-methode-#1}
}
\\newcommand{\\version}[1]{
\\fancyhead[R]{
\\begin{tikzpicture}[remember picture,overlay]
\\node[anchor=north east,inner sep=0pt] at ($(current page.north east)+(-.5,-.5cm)$) {\\large \\textcolor{couleur_theme}{\\bfseries V#1}};
\\end{tikzpicture}
}
}
${preambulePersonnalise(listePackages)}
%%%%%%%%%%%%%%%%%%%%%%%%
%%% Fin du préambule %%%
%%%%%%%%%%%%%%%%%%%%%%%%
`
return introLatexCoop
}
export function preambulePersonnalise (listePackages) {
let result = ''
for (const packages of listePackages) {
switch (packages) {
case 'axe_gradues':
result += `
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Gestion des axes gradués (Olivier Lacroix) %%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\\usepackage{xparse}
\\usepackage{ifthen}
\\usepackage{xargs}
\\newboolean{demiDroite}
\\newboolean{affichePointilles}
\\newboolean{affichePoint}
\\newboolean{afficheGraduations}
\\makeatletter
\\newtoks\\@tabtoks
\\providecommand\\addtabtoks[1]{\\@tabtoks\\expandafter{\\the\\@tabtoks#1}}
\\providecommand*\\resettabtoks{\\@tabtoks{}}
\\providecommand*\\printtabtoks{\\the\\@tabtoks}
\\makeatother
\\DeclareDocumentCommand \\placePoints%
{ > { \\SplitList { | } } m }%
{\\ProcessList {#1} {\\mycommand}}
\\newcommand{\\mycommand}[1]{
\\def\\temp{#1}
\\expandafter\\placePointsDeuxArg\\temp
}
\\def\\placePointsDeuxArg#1,#2{\\draw (#1,0) node{\\Large $\\times$} node[above=.2] {\\ensuremath{#2}};}
\\newcommandx{\\axeGradueFraction}[5][5=]{
\\begin{tikzpicture}[xscale=#4,>=latex]
\\def\\Xmin{#1}
\\def\\Xmax{#2}
\\def\\Decoupage{#3}
\\ifthenelse { \\equal {#5} {} }
{%pas d'argument optionnel, on trace juste l'axe ci-dessous
}
{% un nombre est à placer sur l'axe avec son label
\\placePoints{#5}
%\\draw (#5,-.08) -- (#5,.08) node[above] {#6};
}
% Xfleche de l'axe
\\pgfmathparse{\\Xmax+0.2}\\let\\Xfleche\\pgfmathresult;
% début du segment représentant l'axe numéro 1
\\ifthenelse{\\equal{\\Xmin}{0}}
{
\\def\\Xorigine{\\Xmin}
}
{
\\pgfmathparse{\\Xmin-0.5}\\let\\Xorigine\\pgfmathresult;
% pour la déco :
\\draw (\\Xmin-1/\\Decoupage,-.05) -- (\\Xmin-1/\\Decoupage,.05);
}
\\pgfmathparse{int(\\Xmax-1)}\\let\\XmaxMoinsUn\\pgfmathresult;
% construction de la droite
\\draw[->,>=latex] (\\Xorigine,0) -- (\\Xfleche,0);
\\foreach \\x in {\\Xmin,...,\\XmaxMoinsUn}{
\\draw (\\x,-.1) -- (\\x,.1) node[below=.3] {\\x};
\\foreach \\y in {1,...,\\Decoupage}{
\\pgfmathparse{\\x+\\y/\\Decoupage}\\let\\Xgrad\\pgfmathresult;
\\draw (\\Xgrad,-.05) -- (\\Xgrad,.05);
}
};
% dernière graduation à la mano
\\draw (\\Xmax,-.1) -- (\\Xmax,.1) node[below=.3] {\\Xmax};
\\end{tikzpicture}
}
\\newcommand{\\axesZoom}[5]{
{} \\hfill
\\begin{tikzpicture}
\\def\\XA{#1} % nombre (positif pour l'instant) à placer (avec deux décimales)
\\def\\Nom{#2} % nom du point à placer. Laisser vide si vous ne souhaitez pas voir le point
\\def\\Xmin{#3} % première valeur de x entière sur l'axe
\\setboolean{affichePointilles}{true} % affiche les pointillés indiquant le grossissement
\\setboolean{affichePoint}{#4} % Est ce que le point doit apparaître sur la construction.
\\setboolean{afficheGraduations}{#5} % Est ce que l'on gradue tous les axes ou seulement \\Xmin et \\Xmax sur le premier axe (si false)
\\setboolean{demiDroite}{true} %Par défaut, on construit des demi-droites pour les 6èmes, si Xmin=0 ou si une des décimales l'exige.
\\ifthenelse{\\boolean{demiDroite}}
{
\\def\\DebordementAGauche{0} % mettre 0 pour une demi-droite graduée partant de l'origine
}
{
\\def\\DebordementAGauche{0.5} % mettre 0.5 dans les autres cas.
}
\\pgfmathparse{int(\\Xmin+10)}\\let\\Xmax\\pgfmathresult; % Xmax vaut toujours Xmin+10
\\pgfmathparse{int(\\XA)}\\let\\Unites\\pgfmathresult;
\\pgfmathparse{int((\\XA-\\Unites)*10)}\\let\\Dixiemes\\pgfmathresult;
\\pgfmathparse{int(round((\\XA-\\Unites.\\Dixiemes)*100))}\\let\\Centiemes\\pgfmathresult;
\\pgfmathparse{int(\\Unites+1)}\\let\\UnitesMaj\\pgfmathresult;
\\pgfmathparse{int(\\Dixiemes+1)}\\let\\DixiemesMaj\\pgfmathresult;
\\pgfmathparse{int(\\Centiemes+1)}\\let\\CentiemesMaj\\pgfmathresult;
\\pgfmathparse{\\Xmax+1}\\let\\Xfleche\\pgfmathresult;
\\ifthenelse{\\equal{\\Xmin}{0}}
{
\\def\\Xorigine{\\Xmin}
}
{
\\pgfmathparse{\\Xmin-0.5}\\let\\Xorigine\\pgfmathresult;
}
\\pgfmathparse{int(\\Xmax-1)}\\let\\XmaxMoinsUn\\pgfmathresult;
\\pgfmathparse{int(\\Xmin+1)}\\let\\XminPlusUn\\pgfmathresult;
\\draw[->,>=latex] (\\Xorigine,0) -- (\\Xfleche,0);
\\foreach \\x in {\\XminPlusUn,...,\\XmaxMoinsUn}{
\\ifthenelse{\\boolean{afficheGraduations}}
{
\\draw (\\x,-.1) -- (\\x,.1) node[above] {\\x};
}
{
\\draw (\\x,-.1) -- (\\x,.1);
}
};
\\foreach \\x in {1,...,9}{
\\draw (\\Unites.\\x,-.05) -- (\\Unites.\\x,.05);
}
\\draw (\\Xmin,-.1) -- (\\Xmin,.1) node[above] {\\Xmin};
\\draw (\\Xmax,-.1) -- (\\Xmax,.1) node[above] {\\Xmax};
\\ifthenelse{\\not\\equal{\\Unites}{0}}
{
\\pgfmathparse{\\Xmin-0.5}\\let\\Xorigine\\pgfmathresult;
}{}
\\draw[->,>=latex] (\\Xorigine,-2) -- (\\Xfleche,-2);
\\foreach \\x in {1,...,9}{
\\pgfmathparse{int(\\Xmin+\\x)}\\let\\X\\pgfmathresult;
\\ifthenelse{\\boolean{afficheGraduations}}
{
\\draw (\\X,-2.1) -- (\\X,-1.9) node[above] {\\Unites,\\x};
}
{
\\draw (\\X,-2.1) -- (\\X,-1.9);
}
\\pgfmathparse{int(\\Dixiemes+\\Xmin)+\\x/10}\\let\\Xtirets\\pgfmathresult;
\\draw (\\Xtirets,-2.05) -- (\\Xtirets,-1.95);
};
\\ifthenelse{\\boolean{afficheGraduations}}
{
\\draw (\\Xmax,-2.1) -- (\\Xmax,-1.9) node[above] {\\UnitesMaj};
\\draw (\\Xmin,-2.1) -- (\\Xmin,-1.9) node[above] {\\Unites};
}
{
\\draw (\\Xmax,-2.1) -- (\\Xmax,-1.9) ;
\\draw (\\Xmin,-2.1) -- (\\Xmin,-1.9) ;
}
\\pgfmathparse{int(\\Dixiemes+\\Xmin)}\\let\\XGaucheAxeBis\\pgfmathresult;
\\pgfmathparse{int(\\XGaucheAxeBis+1)}\\let\\XDroitAxeBis\\pgfmathresult;
\\ifthenelse{\\boolean{affichePointilles}}
{
\\draw[dashed] (\\Unites,0) -- (\\Xmin,-2);
\\draw[dashed] (\\UnitesMaj,0) -- (\\Xmax,-2);
\\draw[dashed] (\\XGaucheAxeBis,-2) -- (\\Xmin,-4);
\\draw[dashed] (\\XDroitAxeBis,-2) -- (\\Xmax,-4);
}{}
\\ifthenelse{\\not\\equal{\\Dixiemes}{0}}
{
\\pgfmathparse{\\Xmin-0.5}\\let\\Xorigine\\pgfmathresult;
}{}
\\draw[->,>=latex] (\\Xorigine,-4) -- (\\Xfleche,-4);
\\foreach \\x in {1,...,9}{
\\pgfmathparse{int(\\Xmin+\\x)}\\let\\X\\pgfmathresult;
\\ifthenelse{\\boolean{afficheGraduations}}
{
\\draw (\\X,-4.1) -- (\\X,-3.9) node[above] {\\Unites,\\Dixiemes\\x};
}
{
\\draw (\\X,-4.1) -- (\\X,-3.9) ;
}
};
\\ifthenelse{\\boolean{afficheGraduations}}
{
\\ifthenelse{\\equal{\\Dixiemes}{9}}
{
\\draw (\\Xmax,-4.1) -- (\\Xmax,-3.9) node[above] {\\UnitesMaj};
}
{
\\draw (\\Xmax,-4.1) -- (\\Xmax,-3.9) node[above] {\\Unites,\\DixiemesMaj};
}
\\ifthenelse{\\equal{\\Dixiemes}{0}}
{
\\draw (\\Xmin,-4.1) -- (\\Xmin,-3.9) node[above] {\\Unites};
}
{
\\draw (\\Xmin,-4.1) -- (\\Xmin,-3.9) node[above] {\\Unites,\\Dixiemes};
}
}
{
\\ifthenelse{\\equal{\\Dixiemes}{9}}
{
\\draw (\\Xmax,-4.1) -- (\\Xmax,-3.9);
}
{
\\draw (\\Xmax,-4.1) -- (\\Xmax,-3.9) ;
}
\\ifthenelse{\\equal{\\Dixiemes}{0}}
{
\\draw (\\Xmin,-4.1) -- (\\Xmin,-3.9) ;
}
{
\\draw (\\Xmin,-4.1) -- (\\Xmin,-3.9) ;
}
\\pgfmathparse{int(\\Centiemes+\\Xmin)}\\let\\XGaucheAxeTer\\pgfmathresult;
\\draw (\\XGaucheAxeTer,-4) node[below] {\\Nom};
}
\\ifthenelse{\\boolean{affichePoint}}
{
\\draw (\\XA,0) node{\\Large $\\times$} node[below] {\\Nom};
\\draw (\\XGaucheAxeBis.\\Centiemes,-2) node{\\Large $\\times$} node[below] {\\Nom};
}{}
\\end{tikzpicture}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Fin de la gestion des axes gradués %%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
}
`
break
case 'bclogo':
result += '\\usepackage[tikz]{bclogo}'
break
case 'tkz-euclide':
result += '\\usepackage{tkz-euclide}'
break
case 'bac':
case 'crpe':
result += '\\usepackage{scratch3}'
break
case 'dnb':
case 'e3c':
// result += `
// \\usepackage{fourier}
// \\usepackage[scaled=0.875]{helvet}
// \\renewcommand{\\ttdefault}{lmtt}
// \\usepackage[normalem]{ulem}
// \\usepackage{diagbox}
// \\usepackage{fancybox}
// \\usepackage{booktabs}
// \\usepackage{pifont}
// \\usepackage{multirow}
// \\usepackage{dcolumn}
// \\usepackage{lscape}
// \\usepackage{graphics,graphicx}
// \\usepackage{pstricks,pst-plot,pst-tree,pstricks-add}
// \\usepackage{scratch}
// \\renewcommand{\\theenumi}{\\textbf{\\arabic{enumi}}}
// \\renewcommand{\\labelenumi}{\\textbf{\\theenumi.}}
// \\renewcommand{\\theenumii}{\\textbf{\\alph{enumii}}}
// \\renewcommand{\\labelenumii}{\\textbf{\\theenumii.}}
// \\newcommand{\\vect}[1]{\\overrightarrow{\\,\\mathstrut#1\\,}}
// \\def\\Oij{$\\left(\\text{O}~;~\\vect{\\imath},~\\vect{\\jmath}\\right)$}
// \\def\\Oijk{$\\left(\\text{O}~;~\\vect{\\imath},~\\vect{\\jmath},~\\vect{k}\\right)$}
// \\def\\Ouv{$\\left(\\text{O}~;~\\vect{u},~\\vect{v}\\right)$}
// `
result += `
%%%%% FONTS %%%%%
%\\usepackage{fourier}
\\usepackage{fourier-otf} % car compilation avec xetex
\\usepackage[scaled=0.875]{helvet}
\\renewcommand{\\ttdefault}{lmtt}
\\usepackage{pifont} % symboles
%%%%% MISE EN PAGE %%%%%
\\usepackage{makeidx}
\\usepackage{lscape} % format paysage
%%%%% MISE EN FORME %%%%%
\\usepackage[normalem]{ulem} % souligner
\\usepackage{booktabs} % tableaux de qualité
%\\usepackage[dvips]{hyperref} % hyperlien pour le passage par la compilation dvips
%%%%% MATHS %%%%%
\\usepackage{diagbox} % des diagonales dans une cellule de tableau
\\usepackage{multirow} % fusionner plusieurs lignes de tableau
\\usepackage{dcolumn} % aligner des décimaux dans un tableau
%\\usepackage{marvosym} %c'est pour le symbole euro : code \\EUR{}
%\\usepackage[np]{numprint} % affichage formaté des nombres
%%%%%%% SCRATCH %%%%%%%
% Par défaut pour les anciens sujets c'est le package scratch qui est chargé
% Les packages scratch et scratch3 sont incompatibles
% Il convient donc de commenter l'un d'eux selon les besoins
%
% à noter que le package scratch3 requiert simplekv et tikz qui sont automatiquement chargés en cas de besoin
%\\usepackage{scratch}
% Le package scratch est obsolète. On le remplace par le pckage scratch3
% Compatibilité avec les anciens sources tex à vérifier
\\usepackage{scratch3}
%%%%% FIGURES %%%%%
\\usepackage{graphics} % à distinguer du package graphicx
\\usepackage{framed} % decoration background
%%%%%%% PSTRICKS %%%%%%%
\\usepackage{pstricks,pst-plot,pst-tree,pstricks-add}
\\usepackage{pst-eucl} % permet de faire des dessins de géométrie simplement
\\usepackage{pst-text}
\\usepackage{pst-node,pst-all}
\\usepackage{pst-func,pst-math,pst-bspline,pst-3dplot} %%% POUR LE BAC %%%
%%%%%%% TIKZ %%%%%%%
\\usepackage{tkz-tab,tkz-fct}
\\usepackage{tkz-euclide}
\\usepackage[tikz]{bclogo}
\\usetikzlibrary{shadows,decorations.markings}
\\usetikzlibrary{decorations.pathreplacing}
%\\usepackage{tikz} % arbre en proba
%\\usetikzlibrary{trees} % arbre en proba
\\usepackage{forest} % arbre en proba
%%%%%%% TRACÉS FONNCTIONS %%%%%%%
\\usepackage{pgfplots}
\\pgfplotsset{compat=1.17}
%%%%% PROGRAMMATION %%%%%
\\usepackage{xkeyval,ifthen}
%%%%% COMMANDES SPRECIFIQUES %%%%%
\\usepackage{esvect} %%% POUR LE BAC %%%
\\newcommand{\\vvt}[1]{\\vv{\\text{#1}}} %%% POUR LE BAC %%%
\\newcommand{\\vectt}[1]{\\overrightarrow{\\,\\mathstrut\\text{#1}\\,}} %%% POUR LE BAC %%%
\\newcommand{\\textding}[1]{\\text{\\ding{#1}}}
%\\newcommand{\\euro}{\\eurologo{}}
\\renewcommand{\\pstEllipse}[5][]{% arc d'ellipse pour le sujet de Polynésie septembre 2013
\\psset{#1}
\\parametricplot{#4}{#5}{#2\\space t cos mul #3\\space t sin mul}
}
%%%%%%% NOTATIONS DES ENSEMBLES %%%%%%%
\\newcommand{\\R}{\\mathbb{R}}
\\newcommand{\\N}{\\mathbb{N}}
\\newcommand{\\D}{\\mathbb{D}}
\\newcommand{\\Z}{\\mathbb{Z}}
\\newcommand{\\Q}{\\mathbb{Q}}
%\\newcommand{\\C}{\\mathbb{C}}
%%%%% TRACÉS DANS UN REPÈRE %%%%%
\\newcommand{\\vect}[1]{\\overrightarrow{\\,\\mathstrut#1\\,}}
\\def\\Oij{$\\left(\\text{O}~;~\\vect{\\imath},~\\vect{\\jmath}\\right)$}
\\def\\Oijk{$\\left(\\text{O}~;~\\vect{\\imath},~\\vect{\\jmath},~\\vect{k}\\right)$}
\\def\\Ouv{$\\left(\\text{O}~;~\\vect{u},~\\vect{v}\\right)$}
\\newcommand{\\e}{\\mathrm{\\,e\\,}} %%% POUR LE BAC %%% le e de l'exponentielle
\\newcommand{\\ds}{\\displaystyle} %%% POUR LE BAC %%%
%%%%% PROBABILITÉS %%%%%
% Structure servant à avoir l'événement et la probabilité.
\\def\\getEvene#1/#2\\endget{$#1$}
\\def\\getProba#1/#2\\endget{$#2$}
%%%%% NOMBRES PREMIERS %%%%%
\\input{xlop} % JM pour les opérations
%%% Table des nombres premiers %%%%
\\newcount\\primeindex
\\newcount\\tryindex
\\newif\\ifprime
\\newif\\ifagain
\\newcommand\\getprime[1]{%
\\opcopy{2}{P0}%
\\opcopy{3}{P1}%
\\opcopy{5}{try}
\\primeindex=2
\\loop
\\ifnum\\primeindex<#1\\relax
\\testprimality
\\ifprime
\\opcopy{try}{P\\the\\primeindex}%
\\advance\\primeindex by1
\\fi
\\opadd*{try}{2}{try}%
\\ifnum\\primeindex<#1\\relax
\\testprimality
\\ifprime
\\opcopy{try}{P\\the\\primeindex}%
\\advance\\primeindex by1
\\fi
\\opadd*{try}{4}{try}%
\\fi
\\repeat
}
\\newcommand\\testprimality{%
\\begingroup
\\againtrue
\\global\\primetrue
\\tryindex=0
\\loop
\\opidiv*{try}{P\\the\\tryindex}{q}{r}%
\\opcmp{r}{0}%
\\ifopeq \\global\\primefalse \\againfalse \\fi
\\opcmp{q}{P\\the\\tryindex}%
\\ifoplt \\againfalse \\fi
\\advance\\tryindex by1
\\ifagain
\\repeat
\\endgroup
}
%%% Décomposition en nombres premiers %%%
\\newcommand\\primedecomp[2][nil]{%
\\begingroup
\\opset{#1}%
\\opcopy{#2}{NbtoDecompose}%
\\opabs{NbtoDecompose}{NbtoDecompose}%
\\opinteger{NbtoDecompose}{NbtoDecompose}%
\\opcmp{NbtoDecompose}{0}%
\\ifopeq
Je refuse de décomposer zéro.
\\else
\\setbox1=\\hbox{\\opdisplay{operandstyle.1}%
{NbtoDecompose}}%
{\\setbox2=\\box2{}}%
\\count255=1
\\primeindex=0
\\loop
\\opcmp{NbtoDecompose}{1}\\ifopneq
\\opidiv*{NbtoDecompose}{P\\the\\primeindex}{q}{r}%
\\opcmp{0}{r}\\ifopeq
\\ifvoid2
\\setbox2=\\hbox{%
\\opdisplay{intermediarystyle.\\the\\count255}%
{P\\the\\primeindex}}%
\\else
\\setbox2=\\vtop{%
\\hbox{\\box2}
\\hbox{%
\\opdisplay{intermediarystyle.\\the\\count255}%
{P\\the\\primeindex}}}
\\fi
\\opcopy{q}{NbtoDecompose}%
\\advance\\count255 by1
\\setbox1=\\vtop{%
\\hbox{\\box1}
\\hbox{%
\\opdisplay{operandstyle.\\the\\count255}%
{NbtoDecompose}}
}%
\\else
\\advance\\primeindex by1
\\fi
\\repeat
\\hbox{\\box1
\\kern0.5\\opcolumnwidth
\\opvline(0,0.75){\\the\\count255.25}
\\kern0.5\\opcolumnwidth
\\box2}%
\\fi
\\endgroup
}
% pour les corrections LG Ceci est commenté pour le préambule de mathalea car un environnement remarque existe déjà
%\\newcommand{\\remarque}[1]{
%\\begin{bclogo}[logo=\\bctrombone,couleur=gray!5,ombre,epBord=0.8]{Remarque:}%
% {#1}
%\\end{bclogo}}
%%%%% VÉRIFIER L'UTILITÉ %%%%%
%\\renewcommand{\\theenumi}{\\textbf{\\arabic{enumi}}}
%\\renewcommand{\\labelenumi}{\\textbf{\\theenumi.}}
%\\renewcommand{\\theenumii}{\\textbf{\\alph{enumii}}}
%\\renewcommand{\\labelenumii}{\\textbf{\\theenumii.}}
%Tapuscrit : Denis Vergès
`
break
default:
result += `\\usepackage{${packages}}\n`
}
}
return result
}
/**
* Charge scratchblocks puis sa traduction fr
* retourne une promesse rejetée en cas de pb de chargement (à gérer par l'appelant)
* @return {Promise}
*/
export async function scratchTraductionFr () {
await loadScratchblocks()
window.scratchblocks.loadLanguages({
fr: {
commands: {
'move %1 steps': 'avancer de %1 pas',
'turn @turnRight %1 degrees': 'tourner @turnRight de %1 degrés',
'turn @turnLeft %1 degrees': 'tourner @turnLeft de %1 degrés',
'point in direction %1': "s'orienter à %1",
'point towards %1': "s'orienter vers %1",
'go to x:%1 y:%2': 'aller à x: %1 y: %2',
'go to %1': 'aller à %1',
'glide %1 secs to x:%2 y:%3': 'glisser en %1 secondes à x: %2 y: %3',
'glide %1 secs to %2': 'glisser en %1 secondes à %2',
'change x by %1': 'ajouter %1 à x',
'set x to %1': 'mettre x à %1',
'change y by %1': 'ajouter %1 à y',
'set y to %1': 'mettre y à %1',
'set rotation style %1': 'fixer le sens de rotation %1',
'say %1 for %2 seconds': 'dire %1 pendant %2 secondes',
'say %1': 'dire %1',
'think %1 for %2 seconds': 'penser à %1 pendant %2 secondes',
'think %1': 'penser à %1',
show: 'montrer',
hide: 'cacher',
'switch costume to %1': 'basculer sur le costume %1',
'next costume': 'costume suivant',
'next backdrop': 'arrière-plan suivant',
'switch backdrop to %1': "basculer sur l'arrière-plan %1",
'switch backdrop to %1 and wait': "basculer sur l'arrière-plan %1 et attendre",
'change %1 effect by %2': "ajouter %2 à l'effet %1",
'set %1 effect to %2': "mettre l'effet %1 à %2",
'clear graphic effects': 'annuler les effets graphiques',
'change size by %1': 'ajouter %1 à la taille',
'set size to %1%': 'mettre la taille à %1 % de la taille initiale',
'go to %1 layer': "aller à l'%1 plan",
'go %1 %2 layers': "déplacer de %2 plans vers l'%1",
'start sound %1': 'jouer le son %1',
'clear sound effects': 'annuler tous les effets sonores',
'play sound %1 until done': "jouer le son %1 jusqu'au bout",
'stop all sounds': 'arrêter tous les sons',
'play drum %1 for %2 beats': 'jouer du tambour %1 pendant %2 temps',
'rest for %1 beats': 'faire une pause pendant %1 temps',
'play note %1 for %2 beats': 'jouer la note %1 pendant %2 temps',
'set instrument to %1': "choisir l'instrument n° %1",
'change volume by %1': 'ajouter %1 au volume',
'set volume to %1%': 'mettre le volume à %1%',
'change tempo by %1': 'ajouter %1 au tempo',
'set tempo to %1': 'mettre le tempo à %1',
'erase all': 'effacer tout',
stamp: 'estampiller',
'pen down': "stylo en position d'écriture",
'pen up': 'relever le stylo',
'set pen color to %1': 'mettre la couleur du stylo à %1',
'change pen color by %1': 'ajouter %1 à la couleur du stylo',
'set pen %1 to %2': 'mettre la %1 du stylo à %2',
'change pen %1 by %2': 'ajouter %2 à la %1 du stylo',
'change pen shade by %1': "ajouter %1 à l'intensité du stylo",
'set pen shade to %1': "mettre l'intensité du stylo à %1",
'change pen size by %1': 'ajouter %1 à la taille du stylo',
'set pen size to %1': 'mettre la taille du stylo à %1',
'when @greenFlag clicked': 'quand @greenFlag est cliqué',
'when %1 key pressed': 'quand la touche %1 est pressée',
'when this sprite clicked': 'quand ce sprite est cliqué',
'when stage clicked': 'quand la scène est cliquée',
'when backdrop switches to %1': "quand l'arrière-plan bascule sur %1",
'when %1 > %2': 'quand le %1 > %2',
'when I receive %1': 'quand je reçois %1',
'broadcast %1': 'envoyer à tous %1',
'broadcast %1 and wait': 'envoyer à tous %1 et attendre',
'wait %1 seconds': 'attendre %1 secondes',
'repeat %1': 'répéter %1 fois',
forever: 'répéter indéfiniment',
'if %1 then': 'si %1 alors',
'wait until %1': "attendre jusqu'à ce que %1",
'repeat until %1': "répéter jusqu'à ce que %1",
'stop %1': 'stop %1',
'when I start as a clone': 'quand je commence comme un clone',
'create clone of %1': 'créer un clone de %1',
'delete this clone': 'supprimer ce clone',
'ask %1 and wait': 'demander %1 et attendre',
'turn video %1': 'vidéo %1',
'set video transparency to %1%': 'mettre la transparence vidéo sur %1',
'when video motion > %1': 'quand mouvement vidéo > %1',
'reset timer': 'réinitialiser le chronomètre',
'set %1 to %2': 'mettre %1 à %2',
'change %1 by %2': 'ajouter %2 à %1',
'show variable %1': 'montrer la variable %1',
'hide variable %1': 'cacher la variable %1',
'add %1 to %2': 'ajouter %1 à %2',
'delete %1 of %2': "supprimer l'élément %1 de %2",
'delete all of %1': 'supprimer tous les éléments de la liste %1',
'if on edge, bounce': 'rebondir si le bord est atteint',
'insert %1 at %2 of %3': 'insérer %1 en position %2 de %3',
'replace item %1 of %2 with %3': "remplacer l'élément %1 de la liste %2 par %3",
'show list %1': 'montrer la liste %1',
'hide list %1': 'cacher la liste %1',
'x position': 'abscisse x',
'y position': 'ordonnée y',
direction: 'direction',
'costume #': 'numéro de costume',
'costume %1': '%1 du costume',
size: 'taille',
'backdrop name': "nom de l'arrière-plan",
'backdrop %1': "%1 de l'arrière-plan",
'backdrop #': "numéro de l'arrière-plan",
volume: 'volume',
tempo: 'tempo',
'touching %1?': 'touche le %1 ?',
'touching color %1?': 'couleur %1 touchée ?',
'color %1 is touching %2?': 'couleur %1 touche %2 ?',
'distance to %1': 'distance de %1',
answer: 'réponse',
'key %1 pressed?': 'touche %1 pressée ?',
'mouse down?': 'souris pressée ?',
'mouse x': 'souris x',
'mouse y': 'souris y',
'set drag mode %1': 'mettre mode de glissement à %1',
loudness: 'volume sonore',
'video %1 on %2': 'vidéo %1 sur %2',
timer: 'chronomètre',
'%1 of %2': '%1 de %2',
'current %1': '%1 actuelle',
'days since 2000': 'jours depuis 2000',
username: "nom d'utilisateur",
'%1 + %2': '%1 + %2',
'%1 - %2': '%1 - %2',
'%1 * %2': '%1 * %2',
'%1 / %2': '%1 / %2',
'pick random %1 to %2': 'nombre aléatoire entre %1 et %2',
'%1 < %2': '%1 < %2',
'%1 = %2': '%1 = %2',
'%1 > %2': '%1 > %2',
'%1 and %2': '%1 et %2',
'%1 or %2': '%1 ou %2',
'not %1': 'non %1',
'join %1 %2': 'regrouper %1 et %2',
'letter %1 of %2': 'lettre %1 de %2',
'length of %1': 'longueur de %1',
'%1 mod %2': '%1 modulo %2',
'round %1': 'arrondi de %1',
'%1 contains %2?': '%1 contient %2 ?',
'item %1 of %2': 'élément %1 de %2',
'item # of %1 in %2': 'position de %1 dans %2',
'turn %1 on': 'allumer le moteur %1',
'turn %1 off': 'éteindre le moteur %1',
'set %1 power to %2': 'mettre la puissance du moteur %1 à %2',
'set %1 direction to %2': 'mettre la direction du moteur %1 à %2',
'when distance %1 %2': 'quand la distance %1 %2',
distance: 'distance',
'turn %1 on for %2 seconds': 'allumer le moteur %1 pendant %2 secondes',
'set light color to %1': 'mettre la couleur de la lampe à %1',
'play note %1 for %2 seconds': 'jouer la note %1 pendant %2 secondes',
'when tilted %1': 'quand incliné %1',
'tilt angle %1': "angle d'inclinaison %1",
else: 'sinon',
'user id': "id de l'utilisateur",
'loud?': 'fort ?'
},
dropdowns: {},
ignorelt: [],
soundEffects: [
'hauteur',
'stéréo gauche/droite'
],
osis: [
'autres scripts dans sprite'
],
definePrefix: [
'définir'
],
defineSuffix: [],
palette: {
Motion: 'Mouvement',
Looks: 'Apparence',
Sound: 'Son',
Events: 'Événements',
Control: 'Contrôle',
Sensing: 'Capteurs',
Operators: 'Opérateurs',
Variables: 'Variables',
'My Blocks': 'Mes Blocs'
},
math: [
'abs',
'plancher',
'plafond',
'racine',
'sin',
'cos',
'tan',
'asin',
'acos',
'atan',
'ln',
'log',
'e^',
'10^'
],
aliases: {
'tourner gauche de %1 degrés': 'turn @turnLeft %1 degrees',
'tourner droite de %1 degrés': 'turn @turnRight %1 degrees',
'quand le drapeau vert pressé': 'when @greenFlag clicked',
fin: 'end'
},
name: 'Français',
percentTranslated: 100
}
})
}
export function dataTailleDiaporama (exercice) {
if (context.vue !== 'diap') {
return ''
} else if (exercice.tailleDiaporama !== 1) {
return `data-taille = "${exercice.tailleDiaporama}"`
}
}
function dataTaille (taille) {
if (context.vue !== 'diap' || taille === 1) {
return ''
} else if (taille !== 1) {
return `data-taille = "${taille}"`
}
}
/**
* Donne une liste d'entiers relatifs dont on connait la somme.
* @example > listeEntiersSommeConnue(4,10,-2)
* < [1,-2,6,5]
* @param {int} nbElements Nombre d'éléments de la liste
* @param {int} total Somme des éléments de la liste (peut être un nombre négatif)
* @param {int} [valMin = 1] Valeur minimale de chaque élément (peut être un nombre négatif)
* @return {Array} Liste d'entiers relatifs
* @author Frédéric PIOU
*/
export function listeEntiersSommeConnue (nbElements, total, valMin = 1) {
const liste = []
liste.push(randint(valMin, total - (nbElements - 1) * valMin))
for (let j = 1; j < nbElements - 1; j++) {
liste.push(randint(liste[j - 1] + valMin, total - (nbElements - j - 1) * valMin))
}
liste.push(total)
for (let j = nbElements - 1; j > 0; j--) {
liste[j] = liste[j] - liste[j - 1]
}
return liste
}
/**
* @param {string} expression expression parsée
* @returns expression en LaTeX avec multication implicite
* @author Jean-Léon Henry
*/
export function prettyTex (expression) {
return expression.toTex({ implicit: 'hide' }).replaceAll('\\cdot', '')
}