Taquin Google Sheets (Apps Script)

Développer un taquin pour Google Sheets sur une feuille est possible mais le déplacement des images reste tout de même un peu lent pour pouvoir jouer convenablement (pour des déplacements instantanés, préférez la version JavaScript du taquin).

Dans ce cas, le code Google Apps Script du jeu est probablement bien plus intéressant que le jeu en lui-même.


Aperçu du taquin

taquin google sheets png

Vous pouvez copier ce document Google Sheets à partir de cette page.

Code du jeu

/***************************************************************/
/**  Taquin créé par Sébastien Mathier - Sheets-Pratique.com  **/
/***************************************************************/

const tabRajoutsLig = [0, 0, 1, -1];
const tabRajoutsCol = [-1, 1, 0, 0];

const f = SpreadsheetApp.getActiveSheet();
const tabImages = f.getImages();

// Nouvelle partie
function nouvellePartie() {

  let grille = [[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11], [12, 13, 14, '']];
  
  // Mélange des images (en déplaçant aléatoirement les images adjacentes dans la case vide)
  for (let n = 0; n < 9999; n++) {
    const ligDepart = Math.floor(Math.random() * 4);
    const colDepart = Math.floor(Math.random() * 4);
    
    // Si pas la case vide
    if (grille[ligDepart][colDepart] != '') {
      
      // Test pour chaque côté de la case
      for (let i = 0; i < 4; i++) {
        const lig = ligDepart + tabRajoutsLig[i];
        const col = colDepart + tabRajoutsCol[i];
        
        // Si position valide
        if (lig >= 0 && lig <= 3 && col >= 0 && col <= 3) {
          
          // Si la case vide
          if (grille[lig][col] === '') {
            [grille[lig][col], grille[ligDepart][colDepart]] = [grille[ligDepart][colDepart], grille[lig][col]];
            break;
          }
        }
      }
    }
  }
  
  // Déplacement des images
  for (const [cle, img] of tabImages.entries()) {
    const num = img.getAltTextTitle();

    // Si la dernière image
    if (num == 15) {
      img.setAnchorCell(f.getRange('Y2'));
      
    // Si une autre image
    } else {
      fin:
      for (const [lig, tabLigne] of grille.entries()) {
        for (const [col, numero] of tabLigne.entries()) {
          if (numero == num) {
            img.setAnchorCell(f.getRange(lig + 2, col + 2));
            break fin;
          }
        }
      }
    }
  }
  
  // Enregistrement de la grille
  setGrille(grille);
}

// Action au clic sur une image
function imageClic(numero) {

  let ligClic, colClic;
  let grille = getGrille();
  
  // Position de l'image cliquée dans la grille
  fin:
  for (const [lig, tabLigne] of grille.entries()) {
    for (const [col, num] of tabLigne.entries()) {

      // Si l'image cliquée
      if (num == numero) {
        ligClic = lig;
        colClic = col;
        break fin;
      }
    }
  }
  
  // Si la partie est déjà finie
  if (grille[3][3] == 15) {
    Browser.msgBox('Cliquez sur le bouton "Nouvelle partie" pour jouer.');
    return;
  }

  // Test pour chaque côté de la case
  for (let i = 0; i < 4; i++) {
    const lig = ligClic + tabRajoutsLig[i];
    const col = colClic + tabRajoutsCol[i];
    
    // Si une position valide
    if (lig >= 0 && lig <= 3 && col >= 0 && col <= 3) {

      // Si la case vide
      if (grille[lig][col] === '') {
        tabImages[numToCle(numero)].setAnchorCell(f.getRange(lig + 2, col + 2));
        [grille[lig][col], grille[ligClic][colClic]] = [grille[ligClic][colClic], grille[lig][col]];
        break;
      }
    }
  }
  
  // Test si c'est terminé
  let termine = true;
  fin:
  for (const [lig, tabLigne] of grille.entries()) {
    for (const [col, numero] of tabLigne.entries()) {
      let num = col + lig * 4;
      num = num == 15 ? '' : num;
      if (numero != num) {
        termine = false;
        break fin;
      }
    }
  }

  // Fin
  if (termine) {
    Browser.msgBox('Félicitations !');
    tabImages[14].setAnchorCell(f.getRange('E5'));
    grille[3][3] = 15;
  }
  
  // Enregistrement de la grille
  setGrille(grille);
}

// Enregistrement de la grille
function setGrille(grille) {
  PropertiesService.getUserProperties().setProperties({'grille': JSON.stringify(grille)}, true);
}

// Récupération de la grille
function getGrille() {
  return JSON.parse(PropertiesService.getUserProperties().getProperty('grille'));
}

// Renvoie la clé de tabImages en fonction du numéro d'une image
const numToCle = num => num - 1 >= 0 ? num - 1 : 15;

// Fonctions associées aux images
const imageClic0 = () => imageClic(0);
const imageClic1 = () => imageClic(1);
const imageClic2 = () => imageClic(2);
const imageClic3 = () => imageClic(3);
const imageClic4 = () => imageClic(4);
const imageClic5 = () => imageClic(5);
const imageClic6 = () => imageClic(6);
const imageClic7 = () => imageClic(7);
const imageClic8 = () => imageClic(8);
const imageClic9 = () => imageClic(9);
const imageClic10 = () => imageClic(10);
const imageClic11 = () => imageClic(11);
const imageClic12 = () => imageClic(12);
const imageClic13 = () => imageClic(13);
const imageClic14 = () => imageClic(14);