|
@@ -0,0 +1,204 @@
|
|
|
|
+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 += '<div class="grid">';
|
|
|
|
+ // 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 += '<div class="cell"><div class="line"></div>';
|
|
|
|
+ if (elt) {
|
|
|
|
+ let ballColor = this.color[i][Math.trunc(cptBall/changeColor)];
|
|
|
|
+ if (ballColor == null) {
|
|
|
|
+ ballColor = this.color[i][this.color[i].length - 1];
|
|
|
|
+ }
|
|
|
|
+ html += '<div class="ball ' + ballColor + '" data-line="' + i + '" data-col="' + j + '" onclick="bouleClick(this)"></div>';
|
|
|
|
+ cptBall++;
|
|
|
|
+ }
|
|
|
|
+ html += '</div>';
|
|
|
|
+ }
|
|
|
|
+ html += '</div>';
|
|
|
|
+ }
|
|
|
|
+ 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 bouleClick(elt) {
|
|
|
|
+ const boulier = Boulier.instance;
|
|
|
|
+ if (boulier == null) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ const line = parseInt(elt.getAttribute('data-line'));
|
|
|
|
+ const col = parseInt(elt.getAttribute('data-col'));
|
|
|
|
+ boulier.move(line, col);
|
|
|
|
+ boulier.render();
|
|
|
|
+}
|