import Exercice from '../Exercice.js'
import { mathalea2d, colorToLatexOrHTML } from '../../modules/2dGeneralites.js'
import { listeQuestionsToContenu, contraindreValeur, randint, choice, shuffle } from '../../modules/outils.js'
import { droite, longueur, papierPointe, point, symetrieAxiale, tracePoint } from '../../modules/2d.js'
import { context } from '../../modules/context.js'
import { pointCliquable } from '../../modules/2dinteractif.js'
export const titre = 'Compléter un nuage de points symétriques'
export const dateDePublication = '18/12/2021'
export const interactifReady = true
export const interactifType = 'custom'
export const amcReady = true
export const amcType = 'AMCOpenNum'
/**
* Symétrie axiale sur papier pointé
* Ref 6G24-4
* @author Jean-Claude Lhote
* Publié le 18/12/2021
*/
export const uuid = '07f8a'
export const ref = '6G24-4'
export default function CompleterParSymetrie6e () {
Exercice.call(this) // Héritage de la classe Exercice()
this.consigne = ''
this.nbQuestions = 1
this.nbCols = 1
this.nbColsCorr = 1
this.sup = 1
this.sup2 = 1
this.sup3 = true
this.nouvelleVersion = function () {
this.sup = contraindreValeur(1, 5, this.sup, 1)
this.sup2 = contraindreValeur(1, 4, this.sup2, 1)
this.listeQuestions = [] // Liste de questions
this.listeCorrections = [] // Liste de questions corrigées
this.autoCorrection = []
const couples = []
const pointsCliquables = [[]]
let pointsPossibles
const objetsEnonce = []
const objetsCorrection = []
const pointsChoisis = []
const pointsAffiches = []
const pointsEnPlusCorr = []
const pointsNonSolution = []
const pointsSolution = []
const pointsCliques = []
const changeAxe = []
const typeDePapier = ['quad', 'quad', 'hexa', 'equi'] // l'élément 0 sera changé aléatoirement pour correspondre au type mélange (this.sup2 % 4)
for (let i = 0, cpt = 0, papier, image, d, j, trouve, texte, texteCorr, nbCouplesComplets; i < this.nbQuestions && cpt < 50;) {
typeDePapier[0] = typeDePapier[1 + i % 3]
// on remet à vide tous les tableaux utilisés pour la question suivante
objetsEnonce[i] = []
objetsCorrection[i] = []
pointsChoisis.length = 0
pointsAffiches.length = 0
pointsEnPlusCorr.length = 0
pointsNonSolution[i] = []
pointsSolution[i] = []
pointsCliquables[i] = []
pointsCliques[i] = []
couples.length = 0
changeAxe[i] = this.sup3 ? 0 : randint(-2, 2, 0)
papier = papierPointe({ xmin: 0, ymin: 0, xmax: 10, ymax: 10, type: typeDePapier[this.sup2 === 4 ? 0 : this.sup2] })
objetsEnonce[i].push(papier)
switch (this.sup === 5 ? randint(1, 4) : this.sup) {
case 1:
if (typeDePapier[(this.sup2 === 5 ? 0 : this.sup2)] === 'quad') {
d = droite(point(5 + changeAxe[i] / 2, 0), point(5 + changeAxe[i] / 2, 10))
} else {
d = droite(point(4.33 + 0.866 * changeAxe[i], 0), point(4.33 + 0.866 * changeAxe[i], 10))
}
break
case 2:
if (typeDePapier[(this.sup2 === 4 ? 0 : this.sup2)] === 'quad') {
d = droite(point(0, 5 + changeAxe[i] / 2), point(10, 5 + changeAxe[i] / 2))
} else {
d = droite(point(0, 5.5 + changeAxe[i] / 2), point(10, 5.5 + changeAxe[i] / 2))
}
break
case 3:
if (typeDePapier[(this.sup2 === 4 ? 0 : this.sup2)] === 'quad') {
d = droite(point(0, 1 + changeAxe[i]), point(9 - changeAxe[i], 10))
} else {
d = droite(point(0, 3 + changeAxe[i]), point(8.66, 8 + changeAxe[i]))
}
break
case 4:
if (typeDePapier[(this.sup2 === 4 ? 0 : this.sup2)] === 'quad') {
d = droite(point(0, 10 - changeAxe[i]), point(10 - changeAxe[i], 0))
} else {
d = droite(point(0, 8 + changeAxe[i]), point(8.66, 3 + changeAxe[i]))
}
break
}
d.epaisseur = 2
d.color = context.isHtml ? colorToLatexOrHTML('blue') : colorToLatexOrHTML('black')
objetsEnonce[i].push(d)
pointsPossibles = papier.listeCoords.slice()
// on prépare les points cliquables pour la version interactive
// over, out et click sont des ojets pour le style css des évènements de la souris, radius, width, color, size, style sont les paramètres possibles pour la trace du point
if (this.interactif && context.isHtml) {
for (let p = 0; p < papier.listeCoords.length; p++) {
pointsCliquables[i].push(pointCliquable(papier.listeCoords[p][0], papier.listeCoords[p][1], { radius: 0.2, color: 'red', width: 2, opacite: 0.7 }))
}
}
while (pointsPossibles.length > 1) { // si il n'en reste qu'un, on ne peut pas trouver de symétrique
image = symetrieAxiale(point(pointsPossibles[0][0], pointsPossibles[0][1]), d)
j = 1
trouve = false
while (j < pointsPossibles.length && !trouve) {
// si l'image est proche d'un point, c'est qu'on a deux symétriques donc un couple potentiel.
if (longueur(image, point(pointsPossibles[j][0], pointsPossibles[j][1])) < 0.5) {
trouve = true
} else j++
}
if (trouve) {
// on stocke le couple de symétrique en modifiant aléatoirement l'ordre.
couples.push(choice([true, false]) ? [pointsPossibles[0], pointsPossibles[j]] : [pointsPossibles[j], pointsPossibles[0]])
pointsPossibles.splice(j, 1) // on retire d'abord le points d'indice j
pointsPossibles.splice(0, 1) // puis le point d'indice 0
} else {
pointsPossibles.splice(0, 1) // Le point d'indice 0 n'a pas de symétrique, on le retire
}
}
// la liste des couples est prête, on va pouvoir choisir les points affichés et ceux qu'on n'affiche pas.
const nbCouplesChoisis = randint(8, 12)
const couplesChoisis = shuffle(couples).splice(0, nbCouplesChoisis)
for (let p = 0; p < couplesChoisis.length; p++) {
pointsChoisis.push(couplesChoisis[p][0], couplesChoisis[p][1])
}
nbCouplesComplets = randint(2, 5)
for (let p = 0; p < pointsChoisis.length; p += 2) {
if (p < nbCouplesComplets) { // On affiche un certains nombre de couples
pointsAffiches.push(point(pointsChoisis[p][0], pointsChoisis[p][1]))
pointsAffiches.push(point(pointsChoisis[p + 1][0], pointsChoisis[p + 1][1]))
} else { // et on affiche un seul des points pour les couples restants
pointsAffiches.push(point(pointsChoisis[p][0], pointsChoisis[p][1]))
pointsEnPlusCorr.push(point(pointsChoisis[p + 1][0], pointsChoisis[p + 1][1]))
}
}
for (let p = 0; p < pointsAffiches.length; p++) {
objetsEnonce[i].push(tracePoint(pointsAffiches[p]))
}
for (let p = 0; p < pointsEnPlusCorr.length; p++) {
objetsCorrection[i].push(tracePoint(pointsEnPlusCorr[p], 'red'))
}
for (let p = 0; p < pointsCliquables[i].length; p++) {
trouve = false
let q = 0
while (q < pointsEnPlusCorr.length && !trouve) {
if (longueur(pointsEnPlusCorr[q], pointsCliquables[i][p].point) < 0.1) {
trouve = true
pointsSolution[i].push(pointsCliquables[i][p])
} else {
q++
}
}
if (!trouve) {
pointsNonSolution[i].push(pointsCliquables[i][p])
}
}
texte = context.isAmc
? 'Voici une grille contenant des points et un axe de symétrie.<br>Ajouter un minimum de points afin que la figure soit symétrique par rapport à l\'axe.<br>Écrire le nombre de points ajoutés dans le cadre. Coder ensuite ce nombre de points.<br>'
: 'Voici une grille contenant des points et un axe de symétrie.<br>Ajouter un minimum de points afin que la figure soit symétrique par rapport à l\'axe.<br>'
// On prépare la figure...
texte += mathalea2d({ xmin: -1, ymin: -1, xmax: 11, ymax: 11, scale: 0.7 }, ...objetsEnonce[i], ...pointsCliquables[i])
if (this.interactif && context.isHtml) {
texte += `<div id="resultatCheckEx${this.numeroExercice}Q${i}"></div>`
}
texteCorr = mathalea2d({ xmin: -1, ymin: -1, xmax: 11, ymax: 11, scale: 0.5, style: 'inline' }, ...objetsEnonce, ...objetsCorrection[i])
if (context.isAmc) {
this.autoCorrection[i] = {
enonce: texte,
propositions: [
{
texte: texteCorr,
statut: 1,
feedback: '',
sanscadre: false
}
],
reponse: {
valeur: [pointsEnPlusCorr.length],
param: {
digits: 2,
signe: false,
decimals: 0,
vertical: true
}
}
}
}
if (this.questionJamaisPosee(i, nbCouplesChoisis, nbCouplesComplets, pointsChoisis[0][0], pointsChoisis[0][1])) {
this.listeQuestions.push(texte)
this.listeCorrections.push(texteCorr)
i++
}
cpt++
}
this.correctionInteractive = (i) => {
let resultat
let aucunMauvaisPointsCliques = true
for (const monPoint of pointsNonSolution[i]) {
if (monPoint.etat) {
aucunMauvaisPointsCliques = false
pointsCliques[i].push(tracePoint(monPoint.point, 'red')) // ça c'est pour éventuellement modifier la correction avec les points cliqués par l'utilisateur.
}
monPoint.stopCliquable()
}
for (const monPoint of pointsSolution[i]) {
if (!monPoint.etat) aucunMauvaisPointsCliques = false
else pointsCliques[i].push(tracePoint(monPoint.point, 'red')) // ça c'est pour éventuellement modifier la correction avec les points cliqués par l'utilisateur.
monPoint.stopCliquable()
}
const divFeedback = document.querySelector(`#resultatCheckEx${this.numeroExercice}Q${i}`)
for (let j = 0; j < pointsSolution[i].length; j++) {
pointsSolution[i][j].stopCliquable()
}
let etat = true
for (let k = 0; k < pointsSolution[i].length; k++) {
etat = etat && pointsSolution[i][k]
}
if (aucunMauvaisPointsCliques && etat) {
divFeedback.innerHTML = '😎'
resultat = 'OK'
} else {
divFeedback.innerHTML = '☹️'
resultat = 'KO'
}
// this.listeCorrections[i] = mathalea2d({ xmin: -1, ymin: -1, xmax: 11, ymax: 11, scale: 0.7, style: 'inline' }, ...objetsEnonce[i], ...pointsCliques[i]) + mathalea2d({ xmin: -1, ymin: -1, xmax: 11, ymax: 11, scale: 0.5, style: 'inline' }, ...objetsEnonce, ...objetsCorrection[i])
// le contenu est déjà prêt. Il faudra modifier les <svg> à postéreiori...
return resultat
}
listeQuestionsToContenu(this)
}
this.besoinFormulaireNumerique = ['Type d\'axes', 5, '1 : Axe vertical\n2 : Axe horizontal\n3 : Axe oblique /\n4 : Axe oblique \\\n5 : Mélange']
this.besoinFormulaire2Numerique = ['Type de papier pointé', 4, '1 : Carrés\n2 : Hexagones\n3 : Triangles équilatéraux\n4 : Mélange']
this.besoinFormulaire3CaseACocher = ['Axe centré', true]
}