L'article suivant fait partie d'une série. Pour plus d'articles dans cette série, voir Clonage du jeu 2048 en Ruby. Pour le code complet et final, voir l'essentiel.
Maintenant que nous savons comment l'algorithme fonctionnera, il est temps de penser aux données sur lesquelles cet algorithme fonctionnera. Il y a deux choix principaux ici: un appartement tableau d'une sorte, ou un tableau à deux dimensions. Chacun a ses avantages, mais avant de prendre une décision, nous devons tenir compte de quelque chose.
Puzzles SECS
Une technique courante pour travailler avec des puzzles basés sur une grille où vous devez rechercher des modèles comme celui-ci consiste à en écrire un version de l'algorithme qui fonctionne sur le puzzle de gauche à droite, puis faites pivoter le puzzle entier autour de quatre fois. De cette façon, l'algorithme ne doit être écrit qu'une seule fois et il ne doit fonctionner que de gauche à droite. Cette réduit considérablement la complexité et la taille de la partie la plus difficile de ce projet.
Puisque nous allons travailler sur le puzzle de gauche à droite, il est logique que les lignes soient représentées par des tableaux. Lors de la création d'un tableau à deux dimensions dans Rubis (ou, plus précisément, comment vous voulez que cela soit traité et ce que les données signifient réellement), vous devez décider si vous voulez une pile de lignes (où chaque ligne de la grille est représentée par un tableau) ou une pile de colonnes (où chaque colonne est un tableau). Puisque nous travaillons avec des lignes, nous choisirons des lignes.
Comment ce tableau 2D est tourné, nous y reviendrons après avoir réellement construit un tel tableau.
Construction de tableaux bidimensionnels
La méthode Array.new peut prendre un argument définissant la taille du tableau souhaité. Par exemple, Tableau.nouveau (5) créera un tableau de 5 objets nil. Le deuxième argument vous donne une valeur par défaut, donc Tableau.nouveau (5, 0) vous donnera le tableau [0,0,0,0,0]. Alors, comment créez-vous un tableau à deux dimensions?
La mauvaise façon, et la façon dont je vois les gens essayer souvent est de dire Array.new (4, Array.new (4, 0)). En d'autres termes, un tableau de 4 lignes, chaque ligne étant un tableau de 4 zéros. Et cela semble fonctionner au premier abord. Cependant, exécutez le code suivant:
Ça a l'air simple. Créez un tableau 4x4 de zéros, définissez l'élément en haut à gauche sur 1. Mais imprimez-le et nous obtenons…
Il a mis toute la première colonne à 1, qu'est-ce qui donne? Lorsque nous avons créé les tableaux, l'appel le plus interne à Array.new est appelé en premier, créant une seule ligne. Une seule référence à cette ligne est ensuite dupliquée 4 fois pour remplir le tableau le plus externe. Chaque ligne fait alors référence au même tableau. Changez-en un, changez-les tous.
Au lieu de cela, nous devons utiliser le troisième façon de créer un tableau dans Ruby. Au lieu de passer une valeur à la méthode Array.new, nous passons un bloc. Le bloc est exécuté chaque fois que la méthode Array.new a besoin d'une nouvelle valeur. Donc, si vous deviez dire Array.new (5) {gets.chomp}, Ruby s'arrêtera et demandera une entrée 5 fois. Donc, tout ce que nous devons faire est simplement de créer un nouveau tableau à l'intérieur de ce bloc. Nous nous retrouvons donc avec Array.new (4) {Array.new (4,0)}. Essayons à nouveau ce cas de test.
Et il fait exactement ce que vous attendez.
Ainsi, même si Ruby ne prend pas en charge les tableaux bidimensionnels, nous pouvons toujours faire ce dont nous avons besoin. N'oubliez pas que le tableau de niveau supérieur contient les références aux sous-tableaux, et chaque sous-tableau doit faire référence à un tableau différent de valeurs.
Ce que ce tableau représente dépend de vous. Dans notre cas, ce tableau est disposé en lignes. Le premier index est la ligne que nous indexons, de haut en bas. Pour indexer la rangée supérieure du puzzle, nous utilisons un [0], pour indexer la ligne suivante, nous utilisons un [1]. Pour indexer une tuile spécifique dans la deuxième ligne, nous utilisons a [1] [n]. Cependant, si nous avions décidé des colonnes… ce serait la même chose. Ruby n'a aucune idée de ce que nous faisons avec ces données, et comme il ne prend pas techniquement en charge les tableaux bidimensionnels, ce que nous faisons ici est un hack. N'y accédez que par convention et tout se tiendra. Oubliez ce que les données en dessous sont censées faire et tout peut s'effondrer très rapidement.