import Exercice from '../Exercice.js'
import { colorToLatexOrHTML, mathalea2d } from '../../modules/2dGeneralites.js'
import { context } from '../../modules/context.js'
import { choice, combinaisonListes, listeQuestionsToContenu, randint, stringNombre, texteEnCouleur, numAlpha } from '../../modules/outils.js'
import { centreGraviteTriangle, droite, point, polygone, rotation, symetrieAxiale, texteParPointEchelle, translation, vecteur } from '../../modules/2d.js'
import { propositionsQcm } from '../../modules/interactif/questionQcm.js'
import { symetrieAnimee } from '../../modules/2dAnimation.js'
export const titre = 'Utiliser des symétries axiales en pavage triangulaire'
export const interactifReady = true
export const interactifType = 'qcm'
export const amcReady = true
export const amcType = 'AMCHybride'
/**
* Référence 6G25-1
* Relecture : Novembre 2021 par EE
*/
export const uuid = '49cb2'
export const ref = '6G25-1'
export default function SymetrieAxialePavageTriangulaire () {
'use strict'
Exercice.call(this)
this.titre = 'Symétrie axiale dans un pavage de triangles équilatéraux'
this.nbQuestionsModifiable = false // désactive le formulaire nombre de questions
this.nbCols = 1 // Le nombre de colonnes dans l'énoncé LaTeX
this.nbColsCorr = 1// Le nombre de colonne pour la correction LaTeX
this.pasDeVersionLatex = false // mettre à true si on ne veut pas de l'exercice dans le générateur LaTeX
this.pas_de_version_HMTL = false // mettre à true si on ne veut pas de l'exercice en ligne
this.nbQuestions = 3
this.nbQuestionsModifiable = false
// Voir la Classe Exercice pour une liste exhaustive des propriétés disponibles.
context.fenetreMathalea2d = [0, -0.1, 15, 10]
this.sup = false
// on Choisit trois axes parmi les possibilités prédéfinies... 6 types d'axes laissant le pavage invariant
// un axe horizontal passe par les sommets 0 de deux triangles d'indices 2n et 2n+2 (sauf si 2n%14=12)
// un axe vertical passe par les centres de gravités de deux triangles d'indice i et i+13 (sauf si i%14=0)
// un axe parallèle à [AC] passe par les sommets 0 de deux triangles d'indices 2n et 2n+14
// un axe parallèle à [BC] passe par les sommets 0 de deux triangles d'indices 2n et 2n+12 (sauf si 2n%14=0)
// un axe perpendiculaire à [BC] passe par les centres de gravité de deux triangles d'indice 2n et 2n+1
// un axe perpendiculaire à [AC] passe par les centres de gravité de deux triangles d'indice 2n+1 et 2n+2 (sauf si (2n+1)%14=13)
const axes = [ // contient des couples de numéros dont seront tirés les deux points servant à définir l'axe
[[32, 34], [46, 48], [60, 62], [74, 76]], // axes horizontaux
[[46, 59], [47, 60], [48, 61], [49, 62], [50, 63], [51, 64]], // axes verticaux
[[32, 46], [34, 48], [36, 50], [38, 52]], // axes // à [AC]
[[44, 56], [46, 58], [48, 60], [50, 62], [52, 64], [54, 66]], // axes // à [BC]
[[4, 5], [2, 3], [0, 1], [14, 15], [28, 29]], // axes perpendiculaires à [BC]
[[42, 31], [43, 44], [56, 45], [57, 58], [70, 59], [71, 72]] // axes perpendiculaires à [AC]
]
// fonction qui choisit un triangle selon le type d'axe et sa position retourne le triangle choisi, son image et des distracteurs pour un QCM
const choisitTriangle = function (typeAxe, index) { // retourne {antecedent: number, image: number, distracteurs: [number]}
let figA
let antecedent
let rangM // rangée de l'antécédent
let rangN // rangée de l'image
let rangA // rangée de l'axe
let deltaRang
let image
const distracteurs = []
switch (typeAxe) {
case 0:
figA = axes[typeAxe][index][0] - axes[typeAxe][index][0] % 14 // figA est le triangle en tête de rangée dont le point A définit l'axe
rangA = Math.floor(figA / 14)
if (rangA < 4) { // On est avec un axe bas...
if (rangA < 3) {
antecedent = randint(0, rangA - 1) * 14 + randint(6, 13)
} else {
antecedent = randint(1, rangA - 1) * 14 + randint(8, 13)
}
} else { // on est avec un axe haut ...
if (rangA > 4) {
antecedent = randint(rangA, 6) * 14 + randint(0, 7)
} else {
antecedent = randint(rangA, 5) * 14 + randint(0, 7)
}
}
rangM = Math.floor(antecedent / 14)
deltaRang = rangA - rangM
if (deltaRang > 0) { // l'axe est au dessus de l'antécédent
image = antecedent + (deltaRang - 1) * 26 + 13
distracteurs.push(image - 13)
if (image + 13 < 98) distracteurs.push(image + 13)
distracteurs.push(image - deltaRang * 2 + 1, image + deltaRang * 2 - 1)
} else { // l'axe est en dessous de l'antécédent
image = antecedent + deltaRang * 26 - 13
distracteurs.push(image + 13)
if (image - 13 > 0) distracteurs.push(image - 13)
distracteurs.push(image + deltaRang * 2 - 1, image - deltaRang * 2 + 1)
}
break
case 1:
figA = axes[typeAxe][index][0] % 13 // figA est le triangle en pied de verticale dont le centre de gravité est sur l'axe
rangA = figA // le numéro c'est aussi le rang de gauche à droite
// sur la rangée rangM, rangA + rangM*13 est le numéro de la figure croisée par l'axe
rangM = randint(2, 5) // on choisit la rangée de l'antécédent
if (rangA < 10) { // On est avec un axe à gauche
// l'antécédent doit être choisit entre rangM*14 et rangA +rangM*13
antecedent = randint(rangM * 14 + 1, rangA + rangM * 13 - 1)
} else { // on est avec un axe à droite
// l'antécédent doit être choisit entre rangA +rangM*13 et rangM*14-1
antecedent = randint(rangA + rangM * 13 + 1, rangA + rangM * 14)
}
deltaRang = rangA + rangM * 13 - antecedent
if (deltaRang > 0) { // l'axe est à droite de l'antécédent
image = rangA + rangM * 13 + deltaRang
distracteurs.push(image - 1)
if (image + 13 < 98) distracteurs.push(image + 13)
if (image - 13 > 0) {
if (image % 14 === 13) {
distracteurs.push(image - 2)
} else {
if (choice([false, true])) {
distracteurs.push(image - 13)
} else {
distracteurs.push(image - 14)
}
}
}
if (image % 14 !== 13) distracteurs.push(image + 1)
} else { // l'axe est à gauche de l'antécédent
image = rangA + rangM * 13 + deltaRang
distracteurs.push(image + 1)
if (image + 14 < 98) {
if (image % 14 === 0) {
distracteurs.push(image + 14)
} else {
distracteurs.push(image + 13)
}
}
if (image - 13 > 0) distracteurs.push(image - 13)
if (image % 14 !== 0) distracteurs.push(image - 1)
}
break
case 2: // axe parallèle à [AC]
figA = axes[typeAxe][index][0] % 14 // figA est le triangle de la première rangée dont le côté [AC] définit l'axe
rangA = figA >> 1 // le rang de gauche à droite est le numéro de la figure divisé par 2 car il n'y a que les figures paires qui comptent ici
// sur la rangée rangM, rangA + rangM*13 est le numéro de la figure croisée par l'axe
rangM = randint(rangA, 6 - rangA) // on choisit la rangée verticale de l'antécédent
if (rangA < 4) { // On est avec un axe à gauche
// l'antécédent doit être choisit entre rangM*14 et 2*(rangA-1) + rangM*14
antecedent = randint(rangM * 14, (rangA - 1) * 2 + rangM * 14)
} else { // on est avec un axe à droite
// l'antécédent doit être choisit entre rangA*2 + 1 + rangM*14 et rangM*14+(rangA+1)*2
antecedent = randint(rangA * 2 + 1 + rangM * 14, rangM * 14 + (rangA + 1) * 2)
}
deltaRang = rangA - ((antecedent % 14 - antecedent % 2) >> 1)
// l'axe est à droite de l'antécédent
image = antecedent - 10 * deltaRang - 1 + 12 * (antecedent % 2) // ne me demandez pas d'où je sors ça !!!
distracteurs.push(image - 1)
if (deltaRang > 0) {
distracteurs.push(antecedent + 2 * (deltaRang + 1))
} else {
distracteurs.push(antecedent + 3 * (deltaRang - 1))
}
if (image - 13 > 0) {
if (image % 14 === 13) {
distracteurs.push(image - 2)
} else {
distracteurs.push(image - 13)
}
} else {
distracteurs.push(image + 13)
}
if (image % 14 !== 13) distracteurs.push(image + 1)
break
case 3:
figA = axes[typeAxe][index][0] // figA un nombre pair entre 44 et 54 inclus. l'axe passe par son sommet gauche
rangA = (figA - 42) >> 1 // le rang de gauche à droite. rangA va de 1 à 6 inclus
if (rangA < 4) { // l'antécédent sera à gauche de l'axe
rangM = randint(0, Math.min(2 + rangA, 6)) // on choisit la rangée verticale de l'antécédent
// l'antécédent doit être choisit entre 0 et ?
antecedent = rangM * 14 + 2 * randint(0, 2 + rangA - rangM)
} else { // l'antécédent sera à droite de l'axe
rangM = randint(rangA - 2, 6) // on choisit la rangée verticale de l'antécédent
// l'antécédent doit être choisit entre rangA*2 + 1 + rangM*14 et rangM*14+(rangA+1)*2
antecedent = rangM * 14 + randint(rangA * 2, 13)
}
rangN = antecedent % 14
rangN -= rangN % 2
rangN = rangN / 2
deltaRang = rangA - rangN + 3 - rangM
// l'axe est à droite de l'antécédent
image = antecedent + 16 * deltaRang - 15 - 2 * (antecedent % 2) // ne me demandez pas d'où je sors ça !!!
if (image > 0) {
distracteurs.push(image - 1)
}
if (image < 97) {
distracteurs.push(image + 1)
}
if (image - 13 > 0) {
if (image % 14 === 13) {
distracteurs.push(image - 2)
} else {
distracteurs.push(image - 13)
}
} else {
distracteurs.push(image + 14)
}
if (image + 13 < 97) {
if (image % 14 === 0) {
distracteurs.push(image + 2)
} else {
distracteurs.push(image + 13)
}
}
break
case 4:
figA = axes[typeAxe][index][0] // figA un nombre pair entre 44 et 54 inclus. l'axe passe par son sommet gauche
rangA = figA % 14 // le rang de gauche à droite. rangA va de 1 à 6 inclus
if (index < 2) { // l'antécédent sera sous l'axe qui est sous la diagonale
rangM = randint(0, 3 + index) // on choisit la rangée verticale de l'antécédent
antecedent = rangM * 14 + randint((3 + rangM - index) * 2, 13)
} else if (index > 2) { // l'antécédent sera au dessus de l'axe qui est au dessus
rangM = randint(index, 6) // on choisit la rangée verticale de l'antécédent
antecedent = rangM * 14 + randint(0, rangM + 2 * (4 - index))
} else { // l'antécédent est partout sauf sur la diagonale car c'est l'axe
rangM = randint(0, 6)
antecedent = rangM * 14 + randint(0, 13, [rangM * 2, rangM * 2 + 1, rangM * 2 - 1])
}
deltaRang = 4 - index * 2 + 16 * rangM - (antecedent >> 1) * 2 // Vaudrait mieux que ça marche... je ne sais pas où je vais chercher tout ça !
if (deltaRang > 0) {
deltaRang >>= 1
} else {
deltaRang = -((-deltaRang) >> 1)
}
// l'axe est à droite de l'antécédent
image = antecedent - 12 * deltaRang
if (image > 0) {
distracteurs.push(image - 1)
}
if (image < 97) {
distracteurs.push(image + 1)
}
if (image - 13 > 0) {
if (image % 14 === 13) {
distracteurs.push(image - 2)
} else {
distracteurs.push(image - 13)
}
} else {
distracteurs.push(image + 14)
}
if (image + 13 < 97) {
if (image % 14 === 0) {
distracteurs.push(image + 2)
} else {
distracteurs.push(image + 13)
}
}
break
case 5:
figA = axes[typeAxe][index][0] // figA un nombre pair entre 44 et 54 inclus. l'axe passe par son sommet gauche
rangA = Math.floor(figA / 14) // le rang de gauche à droite. rangA va de 1 à 6 inclus
if (index < 4) { // l'antécédent sera sous l'axe
rangM = randint(1, rangA - 2) // on choisit la rangée verticale de l'antécédent
rangN = randint(rangA - rangM, 4 * (rangA - rangM) + 2 * (figA % 2) - 2)
antecedent = rangM * 14 + rangN
} else { // l'antécédent sera au dessus de l'axe
rangM = randint(rangA - 1, 5) // on choisit la rangée verticale de l'antécédent
rangN = randint(4 * (rangA - rangM) + 2 * (figA % 2) + 2, 12)
antecedent = rangM * 14 + rangN
}
deltaRang = 44 + 14 * (index >> 1) + 2 * (index % 2) + 10 * (rangM - rangA) - (antecedent >> 1) * 2 // Vaudrait mieux que ça marche... je ne sais pas où je vais chercher tout ça !
if (deltaRang > 0) {
deltaRang >>= 1
} else {
deltaRang = -((-deltaRang) >> 1)
}
// l'axe est à droite de l'antécédent
image = antecedent + 14 * deltaRang - 14 * (1 + antecedent % 2)
if (image > 0) {
distracteurs.push(image - 1)
}
if (image < 97) {
distracteurs.push(image + 1)
}
if (image - 13 > 0) {
if (image % 14 === 13) {
distracteurs.push(image - 2)
} else {
distracteurs.push(image - 13)
}
} else {
distracteurs.push(image + 14)
}
if (image + 13 < 97) {
if (image % 14 === 0) {
distracteurs.push(image + 2)
} else {
distracteurs.push(image + 13)
}
}
break
}
return { antecedent, image, distracteurs }
}
this.nouvelleVersion = function (numeroExercice) {
this.listeQuestions = [] // tableau contenant la liste des questions
this.listeCorrections = []
this.autocorrection = []
const objetsEnonce = []
let paramsEnonce = {}
let texte = ''
let texteCorr = ''
let typesDeQuestionsDisponibles
const scaleFigure = 1
// construction du pavage triangulaire
const triAngles = [{}] // tableau des triangles { tri: polygone (le triangle), gra: point(son centre de gravité), num: texteParPoint(son numéro)} l'indice du triangle est son numéro
const images = []
const A = point(0, 0, '')
const B = point(1.2, 0, '')
const C = rotation(B, A, 60, '')
const v = vecteur(1.2, 0)
const w = rotation(vecteur(1.2, 0), A, 60)
triAngles[0] = { tri: polygone(A, B, C), gra: centreGraviteTriangle(A, B, C) }
triAngles[1] = { tri: rotation(triAngles[0].tri, B, -60), gra: rotation(triAngles[0].gra, B, -60) }
for (let i = 0; i < 7; i++) {
if (i !== 0) {
triAngles[i * 2] = { tri: translation(triAngles[(i - 1) * 2].tri, v), gra: translation(triAngles[(i - 1) * 2].gra, v) }
triAngles[i * 2 + 1] = { tri: translation(triAngles[(i - 1) * 2 + 1].tri, v), gra: translation(triAngles[(i - 1) * 2 + 1].gra, v) }
}
for (let j = 1; j < 7; j++) {
triAngles[i * 2 + j * 14] = { tri: translation(triAngles[i * 2 + (j - 1) * 14].tri, w), gra: translation(triAngles[i * 2 + (j - 1) * 14].gra, w) }
triAngles[i * 2 + 1 + j * 14] = { tri: translation(triAngles[i * 2 + 1 + (j - 1) * 14].tri, w), gra: translation(triAngles[i * 2 + 1 + (j - 1) * 14].gra, w) }
}
}
for (let i = 0; i < triAngles.length; i++) {
triAngles[i].n = texteParPointEchelle(stringNombre(i), triAngles[i].gra, 'milieu', 'black', 0.5)
objetsEnonce.push(triAngles[i].tri, triAngles[i].n)
}
paramsEnonce = { xmin: 0, ymin: -0.1, xmax: 15, ymax: 10, pixelsParCm: 30 * scaleFigure, zoom: 1.5, scale: scaleFigure * 0.7, mainlevee: false }
if (!this.sup) {
this.nbQuestions = 3
typesDeQuestionsDisponibles = [0, 1, 2]
} else {
this.nbQuestions = 6
typesDeQuestionsDisponibles = [0, 1, 2, 3, 4, 5]
}
const listeTypesDeQuestions = combinaisonListes(typesDeQuestionsDisponibles, 3)
const couleurs = ['blue', 'green', 'red', 'gray', 'magenta', 'purple']
let M
let N
const d = []
const question = []
let choix
for (let i = 0; i < this.nbQuestions; i++) {
choix = randint(0, axes[listeTypesDeQuestions[i]].length - 1)
switch (listeTypesDeQuestions[i]) { // ici on définit les 3 axes
case 0: // axe horizontal
case 2: // axe parallèle à [AC]
case 3: // axe parallèle à [BC]
M = triAngles[axes[listeTypesDeQuestions[i]][choix][0]].tri.listePoints[0]
N = triAngles[axes[listeTypesDeQuestions[i]][choix][1]].tri.listePoints[0]
d[i] = droite(M, N, `$(d_${i + 1})$`, couleurs[i])
d[i].epaisseur = 3
d[i].opacite = 0.6
break
case 1: // axe vertical
case 4: // axe perpendiculaire à [BC]
case 5: // axe perpendiculaire à [AC]
M = triAngles[axes[listeTypesDeQuestions[i]][choix][0]].gra
N = triAngles[axes[listeTypesDeQuestions[i]][choix][1]].gra
d[i] = droite(M, N, `$(d_${i + 1})$`, couleurs[i])
d[i].epaisseur = 3
d[i].opacite = 0.6
break
}
objetsEnonce.push(d[i])
// ici on choisit les figures et on crée les questions
question[i] = choisitTriangle(listeTypesDeQuestions[i], choix)
triAngles[question[i].antecedent].tri.couleurDeRemplissage = colorToLatexOrHTML(couleurs[i])
triAngles[question[i].antecedent].tri.opaciteDeRemplissage = 0.7
}
this.introduction = mathalea2d(paramsEnonce, objetsEnonce)
for (let i = 0; i < this.nbQuestions; i++) {
texte = `${texteEnCouleur("Quelle est l'image de la figure " + question[i].antecedent + " par la symétrie axiale d'axe " + d[i].nom + ' ?', couleurs[i])}`
texteCorr = `${texteEnCouleur("L'image de la figure " + question[i].antecedent + " par la symétrie axiale d'axe " + d[i].nom + ' est la figure ' + question[i].image + '.', couleurs[i])}`
if (context.isAmc) {
if (i === 0) {
this.autoCorrection[0] = {
enonce: this.introduction + '\\\\\n' + numAlpha(0) + texte + '\\\\\n',
propositions: [
{
type: 'qcmMono',
propositions: [
{
texte: question[i].image,
statut: true,
feedback: ''
}
]
}
]
}
} else {
this.autoCorrection[0].enonce += `${numAlpha(i)} ${texte} \\\\\n`
this.autoCorrection[0].propositions.push({
type: 'qcmMono',
propositions: [
{
texte: question[i].image,
statut: true,
feedback: ''
}
]
})
}
for (let j = 0; j < question[i].distracteurs.length; j++) {
this.autoCorrection[0].propositions[i].propositions.push({
texte: question[i].distracteurs[j],
statut: false,
feedback: ''
})
}
} else {
this.autoCorrection[i] = {
enonce: (context.isAmc ? this.introduction + '\\\\' + texte : texte),
propositions: [{
texte: question[i].image,
statut: true,
feedback: ''
}
]
}
for (let j = 0; j < question[i].distracteurs.length; j++) {
this.autoCorrection[i].propositions.push({
texte: question[i].distracteurs[j],
statut: false,
feedback: ''
})
}
}
objetsEnonce.push(symetrieAnimee(triAngles[question[i].antecedent].tri, d[i], `id="anim${numeroExercice}-${i}" dur="2s" repeatCount="2" `))
images[i] = symetrieAxiale(triAngles[question[i].antecedent].tri, d[i])
images[i].couleurDeRemplissage = colorToLatexOrHTML(couleurs[i])
images[i].opaciteDeRemplissage = 0.3
objetsEnonce.push(images[i])
// On ajoute au texte de la correction, la figure de la correction
// texteCorr += mathalea2d(paramsCorrection, objetsCorrection)
if (this.interactif && !context.isAmc) {
texte += '<br>' + propositionsQcm(this, i).texte
}
this.listeQuestions.push(texte)
this.listeCorrections.push(texteCorr)
}
listeQuestionsToContenu(this) // On envoie l'exercice à la fonction de mise en page
// this.contenuCorrection += '<br>' + mathalea2d(paramsEnonce, objetsEnonce)
this.contenuCorrection += mathalea2d(paramsEnonce, objetsEnonce)
if (context.isHtml) {
for (let i = 0; i < this.nbQuestions; i++) {
this.contenuCorrection += `<br><button class="btn ui labeled icon button" style="margin:10px" onclick="document.getElementById('anim${numeroExercice}-${i}').beginElement()"><i class="redo circle icon"></i>Relancer l'animation de la symétrie par rapport à ${d[i].nom}</button>`
}
}
}
this.besoinFormulaireCaseACocher = ['Nombre d\'axes de symétrie = 6 si coché, 3 sinon', false]
}