class Boulier { static instance = null; static colors = { red: "Rouge", pink: "Rose", purple: "Violet", indigo: "Indigo", blue: "Bleu", cyan: "Cyan", green: "Vert", lime: "Lime", yellow: "Jaune", amber: "Ambre", orange: "Orange" }; static setup(elt, nbLine, nbBoule) { Boulier.instance = new Boulier(elt, nbLine, nbBoule); return Boulier.instance; } static get(elt, nbLine, nbBoule) { if (Boulier.instance != null) { return Boulier.instance; } else if (elt != null && nbLine != null && nbBoule != null) { return Boulier.setup(elt, nbLine, nbBoule); } else { return false; } } static isSaved() { return localStorage.getItem('boulier-ball') != null; } static load(elt) { if (Boulier.instance == null) { Boulier.setup(elt, 1, 1); } const instance = Boulier.get(); instance.load(); return instance; } static clear() { localStorage.clear(); } constructor(elt, nbLine, nbBall) { const emptySpace = Math.floor(nbBall / 2); this._elt = elt; this._callback = null; this._ball = nbBall; this.boulier = []; this.color = []; for (let i = 0; i < nbLine; i++) { const line = [] for (let j = 0; j < nbBall + emptySpace; j++) { line.push(j < nbBall); } this.boulier.push(line); this.color.push(['red']); } } save() { localStorage.setItem('boulier-data', JSON.stringify(this.boulier)); localStorage.setItem('boulier-color', JSON.stringify(this.color)); localStorage.setItem('boulier-ball', this._ball); } load() { this.boulier = JSON.parse(localStorage.getItem('boulier-data')); this.color = JSON.parse(localStorage.getItem('boulier-color')); this._ball = parseInt(localStorage.getItem('boulier-ball')); } move(line, col) { // Vérifie les paramètres if (this.boulier.length <= line || this.boulier[line].length <= col || ! this.boulier[line][col]) { return false; } let data = this.boulier[line]; // Détermine s'il faut bouger les boules vers la gauche ou la droite let right = true; for (let i = col; i < data.length; i++) { if (!data[i]) { right = false; break; } } // Si les mouvement est vers la droite, on inverse la ligne if (right) { data = data.reverse(); col = data.length - col - 1; } // Compte le nombre de boule à deplacer et l'index de l'endroit où faire le déplacement let cpt = 0; let gap = false; let index = null; for (let i = col; i < data.length; i++) { if (!gap && data[i]) { cpt++; data[i] = false; } else if (gap && data[i]) { index = i - 1; break; } else { gap = true; } } if (index == null) { index = data.length - 1; } // Déplace les boules for (let i = 0; i < cpt; i++) { data[index - i] = true; } // Si le mouvement était vers la droite, on remet la ligne dans le bon sens if (right) { data = data.reverse(); } // Callback if (this._callback != null && typeof this._callback === 'function') { this._callback(Boulier.instance); } } reset() { for(let i = 0; i < this.boulier.length; i++) { this.move(i, this.boulier[i].length - 1); } } render() { let html = ''; for (let i = 0; i < this.boulier.length; i++) { html += '
'; // Boule let cptBall = 0; let changeColor = Math.round(this._ball / this.color[i].length); for(let j = 0; j < this.boulier[i].length; j++) { const elt = this.boulier[i][j]; html += '
'; if (elt) { let ballColor = this.color[i][Math.trunc(cptBall/changeColor)]; if (ballColor == null) { ballColor = this.color[i][this.color[i].length - 1]; } html += '
'; cptBall++; } html += '
'; } html += '
'; } this._elt.innerHTML = html; } onChange(callback) { this._callback = callback; } tostring() { let str = ''; for (const line of this.boulier) { str += '-|'; for (const boule of line) { if (boule) { str += 'o'; } else { str += '-'; } } str += '|-\n'; } return str; } print() { console.log(this.tostring()); } } function ballClick(elt) { const instance = Boulier.instance; if (instance == null) { return; } const line = parseInt(elt.getAttribute('data-line')); const col = parseInt(elt.getAttribute('data-col')); instance.move(line, col); instance.render(); } function allowDrop(evt) { evt.preventDefault(); } function ballDrag(evt) { const line = parseInt(evt.target.getAttribute('data-line')); const col = parseInt(evt.target.getAttribute('data-col')); evt.dataTransfer.setData("text", line + ";" + col); } function ballDrop(evt, elt) { evt.preventDefault(); // Récupère l'instance const instance = Boulier.instance; if (instance == null) { return; } // Recupère les infos de la balle et de la destination const line = parseInt(elt.getAttribute('data-line')); const col = parseInt(elt.getAttribute('data-col')); const split = evt.dataTransfer.getData("text").split(';'); const ballLine = parseInt(split[0]); const ballCol = parseInt([split[1]]); // Vérifie si le cas est valide if (line != ballLine || col == ballCol) { return; } let right = true; for (let i = ballCol; i < instance.boulier[line].length; i++) { if (!instance.boulier[line][i]) { right = false; break; } } if ((right && col > ballCol) || (!right && col < ballCol)) { return; } // Bouge instance.move(ballLine, ballCol); instance.render(); }