Parcours
/
Crystal
Crystal
/
Exercices
/
Partie d'échecs
Partie d'échecs

Partie d'échecs

Exercice d'apprentissage

Introduction

Un intervalle représente l'ensemble des valeurs comprises entre deux valeurs. Les types les plus courants qui prennent en charge les intervalles sont Int, Char et String. Ils servent à beaucoup de choses : créer rapidement une collection, découper des strings, vérifier si une valeur se trouve dans un intervalle, ou encore itérer. On les crée avec l'opérateur d'intervalle .. ou ... (respectivement inclusif et exclusif).

1..5  # A range containing 1, 2, 3, 4, 5
1...5 # A range containing 1, 2, 3, 4

Ces deux opérateurs d'intervalle permettent de créer des intervalles qui incluent ou excluent la valeur de fin, ce qui peut être utile quand on travaille par exemple avec des indices commençant à zéro.

On peut aussi créer des intervalles avec l'initialiseur Range.

Range.new(1, 5) # A range containing 1, 2, 3, 4, 5
Note

Quand tu crées un intervalle en Crystal avec les opérateurs .. ou ... et que tu veux appeler une méthode dessus, il faut entourer l'intervalle de parenthèses. Sinon, la méthode sera appelée sur le deuxième argument de l'opérateur d'intervalle.

(1..5).size # => 5
1..5.size # => Error: undefined method 'size' for Int32

Récupère des sous-chaînes

Pour découper une string, on peut se servir de l'opérateur d'intervalle afin d'en extraire une sous-chaîne. Il suffit de créer un intervalle avec l'indice de début et l'indice de fin de la sous-chaîne.

"Hello World"[0..4] # => "Hello"
"Hello World"[6..10] # => "World"

On peut aussi utiliser des indices négatifs pour récupérer la sous-chaîne à partir de la fin de la string.

"Hello World"[-5..-1] # => "World"
"Hello World"[6..-4] # => "Wo"

Méthodes des intervalles

Les intervalles disposent d'un ensemble de méthodes pour les manipuler. On peut par exemple s'en servir pour calculer la somme de toutes les valeurs de l'intervalle ou pour vérifier qu'il contient une valeur.

Méthode Description Exemple
sum Renvoie la somme de toutes les valeurs de l'intervalle (1..5).sum # => 15
size Renvoie la taille de l'intervalle (1..5).size # => 5
includes? Renvoie true si l'intervalle contient la valeur donnée, sinon false (1..5).includes?(3) # => true

Intervalles sans fin et sans début

Un intervalle peut être sans fin ou sans début. Dans un intervalle sans fin ou sans début, la valeur de début ou de fin vaut nil, mais ce nil peut être omis au moment de définir l'intervalle.

Les intervalles sans début et sans fin sont pratiques quand on veut, par exemple, découper une string depuis le début ou jusqu'à la fin.

"Hello World"[0..] # => "Hello World"
"Hello World"[4..] # => "o World"
"Hello World"[..5] # => "Hello"
Caution

S'il n'est pas utilisé sur une collection, un intervalle sans fin peut produire une séquence infinie s'il n'est pas employé avec prudence.

Intervalles de Char

On peut utiliser des Char dans les intervalles, ce qui permet d'obtenir un ensemble de caractères compris entre deux caractères. C'est par exemple pratique quand on veut récupérer l'alphabet.

'a'..'z' # A range containing ['a', 'b', 'c', ..., 'z']

Intervalles de strings

On peut aussi utiliser des strings dans les intervalles, ce qui permet d'obtenir un ensemble de strings entre deux strings. Leur comportement est toutefois légèrement différent de celui de Char quand on utilise plusieurs caractères dans un intervalle de strings. Il peut devenir déroutant avec des intervalles de strings plus complexes : reste donc prudent.

("aa".."az") # A range containing ["aa", "ab", "ac", ..., "az"]

Instructions

En passionné d'échecs, tu veux écrire ta propre version du jeu. Certes, il existe sans doute déjà plein d'implémentations d'échecs en ligne, mais la tienne sera unique !

Tu commences par implémenter un système de déplacement de base pour les pièces.

La partie d'échecs se joue sur un échiquier de huit cases de large et huit cases de long. Les cases sont identifiées par une lettre et un nombre.

1. Définis les intervalles des rangs et des colonnes

Le jeu devra stocker les rangs de l'échiquier. Les rangs sont les lignes de l'échiquier et sont numérotés de 1 à 8.

Le jeu devra aussi stocker les colonnes de l'échiquier. Les colonnes sont identifiées par les lettres de A à H.

Définis les constantes Chess::RANKS et Chess::FILES qui stockent respectivement l'intervalle des rangs et celui des colonnes.

Chess::RANKS
# => 1..8

Chess::FILES
# => 'A'..'H'

2. Vérifie si une case est valide

Le jeu devra vérifier si une case est valide. Une case est valide si son rang et sa colonne se trouvent dans les intervalles des rangs et des colonnes.

Définis la méthode Chess.valid_square? qui prend les arguments rank, un entier représentant le rang, et file, un caractère représentant la colonne. La méthode doit renvoyer true si le rang et la colonne sont dans les intervalles des rangs et des colonnes, et renvoyer false sinon.

Chess.valid_square?(1, 'A')
# => true

3. Récupère le surnom du joueur

Le jeu devra récupérer le surnom du joueur. Le surnom est constitué des deux premiers caractères du prénom du joueur et des deux derniers caractères de son nom de famille. Le surnom doit être en majuscules.

Définis la méthode Chess.nickname qui prend les arguments first_name, une string contenant le prénom du joueur, et last_name, une string contenant son nom de famille. La méthode doit renvoyer le surnom du joueur sous forme de string en majuscules.

Chess.nickname("John", "Doe")
# => "JOOE"

4. Crée le message de déplacement

Le jeu devra créer un message pour un déplacement, qui indique quel joueur s'est déplacé vers quelle case. Le message doit utiliser le surnom du joueur et la case vers laquelle il s'est déplacé. Le jeu doit aussi déterminer si le déplacement est valide en vérifiant que la colonne et le rang de la case se trouvent dans les intervalles des colonnes et des rangs.

Si le déplacement est valide, le message doit être : "{nickname} moved to {square}" Si le déplacement n'est pas valide, le message doit être : "{nickname} attempted to move to {square}, but that is not a valid square"

Définis la méthode Chess.move_message qui prend les arguments first_name, une string contenant le prénom du joueur, last_name, une string contenant son nom de famille, et square, une string contenant la case vers laquelle le joueur s'est déplacé. La méthode doit renvoyer le message du déplacement sous forme de string.

Chess.move_message("John", "Doe", "A1")
# => "JOOE moved to A1"
Modifie via GitHub Le lien s'ouvre dans une nouvelle fenêtre ou un nouvel onglet
Crystal Exercism

Prêt à commencer Partie d'échecs ?

Inscris-toi sur Exercism pour apprendre et maîtriser Crystal avec 26 concepts142 exercices, et un vrai mentorat humain, le tout gratuitement.