legacy/outils/compteEstBon/CompteEstBon.js

function simplifie (ch) {
  // ((2*7)*4)+3 ==> 2*4*7+3

  function maxtab (tab) {
    // [0,1,2,2,2,1,1,0,0] ==> renvoie 2
    let max = -1
    for (let k = 0; k < tab.length; k++) {
      if (tab[k] > max) max = tab[k]
    }
    return max
  }

  function sommetab (tab) {
    // [0,1,2,2,2,1,1,0,0] ==> renvoie 2
    let s = 0
    for (let k = 0; k < tab.length; k++) {
      s += tab[k]
    }
    return s
  }

  function nbnulstab (tab) {
    let nb = 0
    for (let k = 0; k < tab.length; k++) {
      if (tab[k] == 0) nb++
    }
    return nb
  }

  function expression (ch) {
    // 3*7 ==> [true,3,7,2]
    // 3*6*4 ==> [true,3,4,6,2]
    // 2*6+5 ==> [false]

    function estdans (liste, ch) {
      // estdans(["+","*"],"4+5*4*6"] renvoie [1,2]
      const retour = [0, 0, 0, 0]
      for (let k = 0; k < ch.length; k++) {
        for (let p = 0; p < liste.length; p++) {
          if (liste[p] == ch.charAt(k)) {
            retour[p]++
          }
        }
      }
      return retour
    }

    function nboperations (ch) {
      // 3*7+5==> [2,false] car pas les mêmes
      // 2+5+3 ==> [2,true] car les mêmes

      const tab = estdans(['+', '-', '*', '/'], ch)
      // const max = maxtab(tab)
      const som = sommetab(tab)
      // si som=max alors il n’y a qu’une seule operation
      const nb = 4 - nbnulstab(tab)

      if (nb === 1) return [som, true]
      return [som, false]
    }

    let ope = ch.indexOf('+')
    if (ope === -1) ope = ch.indexOf('-')
    if (ope === -1) ope = ch.indexOf('*')
    if (ope === -1) ope = ch.indexOf('/')
    ope = ch.charAt(ope)//*

    const tab = nboperations(ch)

    if (!tab[1]) return [false]
    let operande1 = ch.substring(0, ch.indexOf(ope))
    let operande2 = ch.substring(1 + ch.indexOf(ope))
    let o3
    if (Number(operande2) < Number(operande1)) {
      o3 = operande2
      operande2 = operande1
      operande1 = o3
    }

    return [operande1, operande2, ope]
  }

  function interieur (ch) {
    // ((2*7)*4)+3 ==> [1;5]
    let n = 0
    const poids = []
    for (let k = 0; k < ch.length; k++) {
      if (ch.charAt(k) == '(') { n++ }
      if (ch.charAt(k) == ')') { n-- }
      poids[k] = n
    }
    const max = maxtab(poids)

    const chpoids = poids.join('')

    const i1 = chpoids.indexOf(max)
    const i2 = chpoids.indexOf((max - 1), i1)

    // rangement des termes de la parenthese interieure
    const ssch = ch.substring(i1 + 1, i2)

    const tab = expression(ssch)//

    // le même opérateur
    // premier cas  ((expression) +
    if ((ch.charAt(i1 - 1) == '(') && (ch.charAt(i2 + 1) == '+')) {
      ch = ch.substring(0, i1 - 1) + tab[0] + tab[2] + tab[1] + ch.substring(i2) + 1
    }
    // 2e cas  ((expression) *
    if ((ch.charAt(i1 - 1) == '(') && (ch.charAt(i2 + 1) == '*')) {
      ch = ch.substring(0, i1) + tab[0] + tab[2] + tab[1] + ch.substring(i2 + 1)
    }
  }

  interieur(ch)
  return ch
} // simplifie

/**
 * À documenter
 * @param tirage
 * @param compte
 * @param ope
 * @constructor
 */
function CompteEstBon (tirage, compte, ope) {
  if (tirage.length <= 1) {
    this.solution = 'impossible'
    return
  }
  if (tirage.length >= 7) {
    this.solution = 'impossible2'
    return
  }

  const that = this

  this.tirage = tirage
  this.noeuds = []
  this.compte = compte
  this.ceb = false
  this.ope = ope // si 4 opérations
  // 3 on enlève la division
  // 2 on enlève la multiplication est la fdivision
  this.choix = [
    [], // tirage de longueur 0
    [], // tirage de longueur 1, pas moyen d’en prendre 2
    [[0, 1]],
    [[0, 1], [0, 2], [1, 2]],
    [[0, 1], [0, 2], [0, 3], [1, 2], [1, 3], [2, 3]],
    [[0, 1], [0, 2], [0, 3], [0, 4], [1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]],
    [[0, 1], [0, 2], [0, 3], [0, 4], [0, 5], [1, 2], [1, 3], [1, 4], [1, 5], [2, 3], [2, 4], [2, 5], [3, 4], [3, 5], [4, 5]]
  ]
  this.solutions = []
  const objetcomptebon = this

  function Noeud (objet) {
    // un noeud est un tirage
    // objet = {tirage,numero,numpere,numenfants,i1,i2,op}
    this.letirage = objet.letirage
    this.numero = objet.numero
    this.numeropere = objet.numeropere
    this.numenfants = objet.numenfants
    this.i1 = objet.i1
    this.i2 = objet.i2
    this.op = objet.op
    this.ceb = false

    for (let k = 0; k < objet.letirage.length; k++) {
      if (objet.letirage[k] == objetcomptebon.compte) {
        this.ceb = true

        if (k == 0) objetcomptebon.solutions.push(objet.numero)
      }
    }

    if (this.numero == 1) {
      for (let k = 0; k < objet.letirage.length; k++) {
        if (objet.letirage[k] == objetcomptebon.compte) {
          this.ceb = true
          objetcomptebon.solutions.push(this.numero)
        }
      }
    }
  }

  solvecompte(-1, tirage)

  // this.noeuds[1] = new Noeud({letirage:tirage,numero:1,numeropere:0,numenfants:[],i1:-1,i2:-1,op:""});

  function solvecompte (numeropere, tirage) {
    if ((that.tirage.length == 6) && (that.ceb == true)) {
      return
    }
    // objet = {tirage,i1,i2,y,op,numpere}
    if (numeropere == -1) {
      // sommet du graphe : le tirage passé en paramètre au constructeur CompteEstBon
      objetcomptebon.noeuds[1] = new Noeud({
        letirage: tirage,
        numero: 1,
        numeropere: 0,
        numenfants: [],
        i1: -1,
        i2: -1,
        op: ''
      })
      solvecompte(1, tirage)
    } else {
      for (let k = 0; k < objetcomptebon.choix[tirage.length].length; k++) {
        const couple = objetcomptebon.choix[tirage.length][k]
        let max
        if (that.ope == 3) max = 2
        if (that.ope == 4) max = 4
        if (that.ope == 2) max = 1
        for (let ope = 0; ope <= max; ope++) {
          if (!((ope == 2) && (tirage[couple[0]] == 1 || tirage[couple[1]] == 1))) {
            const ob = objetcomptebon.operation(ope, tirage[couple[0]], tirage[couple[1]])
            if (ob.valide) {
              const autretirage = objetcomptebon.nouveautirage(tirage, couple[0], couple[1], ob.res)
              const num = objetcomptebon.noeuds.length

              objetcomptebon.noeuds.push(new Noeud({
                letirage: autretirage,
                numero: num,
                numeropere,
                numenfants: [],
                i1: couple[0],
                i2: couple[1],
                op: ope
              }))
              if (objetcomptebon.noeuds[objetcomptebon.noeuds.length - 1].ceb) {
                that.ceb = true
              }
              objetcomptebon.noeuds[numeropere].numenfants.push(num)
              solvecompte(num, autretirage)
            }
          }
        }
      }
    }
  }
}

// effectue l’operation x ope y et renvoie o.res
// si le résultat n’est pas valide alors l’objet renvoyé contient o.valide = false;
CompteEstBon.prototype.operation = function (ope, x, y) {
  function divise (x, y) {
    // 5,2 = 2,5 donc renvoie FALSE
    const toto = x / y
    if (Math.abs(Math.round(toto) - toto) < 0.0000001) return true
    return false
  }

  const objetretour = { valide: true, res: 0 }
  switch (ope) {
    case 0:
      objetretour.res = x + y
      break
    case 1:
      if (x - y <= 0) objetretour.valide = false
      else objetretour.res = x - y
      break
    case 2:
      objetretour.res = x * y
      break
    case 3:
      if (divise(x, y) == false) objetretour.valide = false
      else objetretour.res = Math.round(x / y)
      break
    case 4:
      if (divise(y, x) == false) objetretour.valide = false
      else objetretour.res = Math.round(y / x)
      break
  }
  return objetretour
}

// remplace les éléments i1 et i2 du tableau tirage par y
CompteEstBon.prototype.nouveautirage = function (tab, i1, i2, y) {
  const nouveautirage = []
  nouveautirage.push(y)
  for (let k = 0; k < tab.length; k++) {
    if ((k != i1) && (k != i2)) nouveautirage.push(tab[k])
  }
  return nouveautirage
}

CompteEstBon.prototype.debug = function debug () {
  /// /objet = {tirage,numero,numpere,numenfants,i1,i2,op}
  let ch = ''
  for (let k = 1; k < this.noeuds.length; k++) {
    ch += 'noeud ' + k + '\n'
    ch += '[' + this.noeuds[k].letirage + '] numero:' + this.noeuds[k].numero + ' pere:' + this.noeuds[k].numeropere + ' enf:' +
      this.noeuds[k].numenfants + ' param:(' + this.noeuds[k].i1 + ' ' + this.noeuds[k].i2 + ' ' + this.noeuds[k].op + ') ceb=' + this.noeuds[k].ceb
    ch += '\n'
  }
  return ch
}

CompteEstBon.prototype.affichenoeud = function (k) {
  return '[' + this.noeuds[k].letirage + '] numero:' + this.noeuds[k].numero + ' pere:' + this.noeuds[k].numeropere + ' enf:' +
    this.noeuds[k].numenfants + ' param:(' + this.noeuds[k].i1 + ' ' + this.noeuds[k].i2 + ' ' + this.noeuds[k].op + ') ceb=' + this.noeuds[k].ceb
}

CompteEstBon.prototype.affichesolutions = function (bool) {
  const objet = this
  let tabascendants = []

  function retourneexpression (ope, a, b) {
    switch (ope) {
      case 0:
        return a + '+' + b
      case 1:
        return a + '-' + b
      case 2:
        return a + '*' + b
      case 3:
        return a + '/' + b
      case 4:
        return b + '/' + a
    }
  }

  function ascendants (n) {
    tabascendants.push(n)
    if (objet.noeuds[n].numeropere != 0) {
      ascendants(objet.noeuds[n].numeropere)
    }
  }

  function nouveautab (tab, i1, i2, ope) {
    const ntab = []
    ntab.push('(' + retourneexpression(ope, tab[i1], tab[i2]) + ')')
    for (let k = 0; k < tab.length; k++) {
      if ((k != i1) && (k != i2)) ntab.push(tab[k])
    }
    return ntab
  }

  let result = ''

  if (this.solution === 'impossible') return 'Au moins 2 opérandes'
  if (this.solution === 'impossible2') return 'Pas plus de 3 opérandes'

  if (!this.solutions.length) {
    let min = 1000
    let numeromeilleur = 0
    for (let k = 1; k < this.noeuds.length; k++) {
      if (Math.abs(this.noeuds[k].letirage[0] - this.compte) < min) {
        numeromeilleur = k
        min = Math.abs(this.noeuds[k].letirage[0] - this.compte)
      }
    }

    ascendants(numeromeilleur)
    let tab = objet.noeuds[tabascendants[tabascendants.length - 1]].letirage
    result = 'Pas de solution.<br> La plus proche est:<br>'
    for (let k = tabascendants.length - 2; k >= 0; k--) {
      const Enfant = objet.noeuds[tabascendants[k]]
      tab = nouveautab(tab, Enfant.i1, Enfant.i2, Enfant.op)
    }
    result += this.noeuds[numeromeilleur].letirage[0] + ' =  ' + simplifie(tab[0].substring(1, tab[0].length - 1)) + '\n'
    return result
  }

  tabascendants = []

  if (bool) {
    result = ''
    for (let j = 0; j < this.solutions.length; j++) {
      tabascendants = []
      ascendants(this.solutions[j])

      let tab = objet.noeuds[tabascendants[tabascendants.length - 1]].letirage
      for (let k = tabascendants.length - 2; k >= 0; k--) {
        const Enfant = objet.noeuds[tabascendants[k]]
        tab = nouveautab(tab, Enfant.i1, Enfant.i2, Enfant.op)
      }
      result += this.compte + ' = ' + simplifie(tab[0].substring(1, tab[0].length - 1)) + '<br>'
    }
    return result
  }

  // bool est false
  ascendants(this.solutions[0])
  result = 'Le compte est bon : <br>'
  let tab = objet.noeuds[tabascendants[tabascendants.length - 1]].letirage
  for (let k = tabascendants.length - 2; k >= 0; k--) {
    const Enfant = objet.noeuds[tabascendants[k]]
    tab = nouveautab(tab, Enfant.i1, Enfant.i2, Enfant.op)
  }
  result += this.compte + ' = ' + simplifie(tab[0].substring(1, tab[0].length - 1)) + '\n'
  return result
}

export default CompteEstBon