Los ejercicios de práctica son ejercicios diseñados para que los estudiantes resuelvan un problema arbitrario, con el objetivo de que pongan en práctica los conceptos que han aprendido hasta ahora.
¿Te interesa añadir tu primer ejercicio de práctica a un track? Consulta la documentación sobre cómo añadir un ejercicio de práctica o mira nuestro vídeo de introducción 👇
Puedes crear rápidamente la estructura de un nuevo ejercicio de práctica ejecutando los siguientes comandos desde el directorio raíz del track:
bin/fetch-configlet
bin/configlet create --practice-exercise <slug>
Para obtener más información, consulta la documentación de configlet create
Los metadatos de un ejercicio de práctica se definen en la clave exercises.practice del archivo config.json. Los metadatos definen el UUID, el slug y más cosas del ejercicio.
{
"exercises": {
"practice": [
{
"uuid": "8ba15933-29a2-49b1-a9ce-70474bad3007",
"slug": "leap",
"name": "Leap",
"practices": ["if-statements", "numbers", "operator-precedence"],
"prerequisites": ["if-statements", "numbers"],
"difficulty": 1
}
]
}
}
practicesLa clave practices debe listar los slugs de los conceptos que este ejercicio de práctica permite practicar activamente a un estudiante.
strings). En esos casos, recomendamos elegir unos cuantos ejercicios buenos que hagan que la gente piense en esos conceptos de formas interesantes. Por ejemplo, ejercicios que requieran UTF-8, concatenación de strings, enumeración de caracteres, etc., serían todos buenos ejemplos.prerequisitesLa clave prerequisites enumera los conceptos que un estudiante debe haber completado para poder acceder a este ejercicio de práctica.
strings, optional-params, implicit-return.loops o recursion), el mantenedor debe elegir el enfoque con el que quiera desbloquear el ejercicio, teniendo en cuenta el recorrido del estudiante por el track. Por ejemplo, en el caso de loops/recursion, podría pensar que este ejercicio es una buena práctica temprana de loops o que preferiría dejarlo para más adelante y enseñar recursion. También puede usar un analyzer para animar al estudiante a probar un enfoque alternativo: «Buen trabajo resolviéndolo con bucles. También podrías probar a resolverlo usando recursión.»Cada ejercicio de práctica tiene su propio directorio dentro del directorio exercises/practice del track. El nombre del directorio del ejercicio de práctica debe coincidir con la propiedad slug del ejercicio de práctica, tal y como se define en el archivo config.json.
Un ejercicio de práctica tiene cuatro tipos de archivos:
Estos archivos se muestran al estudiante para ayudarle a entender el ejercicio.
.docs/introduction.md: presenta el contexto y los antecedentes del ejercicio (opcional).docs/introduction.append.md: texto de introducción adicional para añadir después de la introducción existente (opcional).docs/instructions.md: proporciona las instrucciones del ejercicio (obligatorio).docs/instructions.append.md: texto de introducción adicional para añadir después de las instrucciones existentes (opcional).docs/hints.md: proporciona pistas al estudiante para ayudarle a desbloquearse en el ejercicio (opcional)Estos archivos no se muestran al estudiante, sino que se usan para definir los metadatos del ejercicio.
.meta/config.json: contiene metainformación sobre el ejercicio (obligatorio).meta/design.md: describe el diseño del ejercicio (opcional).meta/tests.toml: contiene información sobre qué tests están implementados (opcional)Estos archivos describen enfoques para el ejercicio.
.approaches/introduction.md: introducción a los enfoques más comunes para el ejercicio (opcional).approaches/config.json: metadatos de los enfoques (opcional).approaches/<approach-slug>/content.md: descripción del enfoque (opcional).approaches/<approach-slug>/snippet.txt: fragmento que muestra el enfoque (opcional)Estos archivos describen artículos para el ejercicio.
.articles/config.json: metadatos de los artículos (opcional).articles/<article-slug>/content.md: descripción del artículo (opcional).articles/<article-slug>/snippet.md: fragmento que muestra el artículo (opcional)Los archivos específicos del lenguaje, como los archivos de implementación y de tests. Los nombres de estos archivos son específicos de cada track.
exercises
└── practice
└── isogram
├── .approaches
| ├── for-loop
| | ├── content.md
| | └── snippet.txt
| ├── config.json
| └── introduction.md
├── .articles
| ├── performance
| | ├── content.md
| | └── snippet.md
| └── config.json
├── .docs
| ├── introduction.md
| ├── instructions.md
| └── hints.md
├── .meta
| ├── config.json
| ├── design.md
| ├── tests.toml
| └── Example.cs (implementación de ejemplo)
├── Isogram.cs (implementación stub)
└── IsogramTests.cs (tests)
.docs/introduction.md
Propósito: Presentar al estudiante el contexto y los antecedentes del ejercicio.
Presencia: Obligatorio si el ejercicio implementa un ejercicio de Problem Specifications con un archivo introduction.md
Si el ejercicio implementa un ejercicio de Problem Specifications, el contenido de este archivo debe coincidir con el archivo introduction.md del ejercicio de Problem Specifications. configlet tiene una funcionalidad para sincronizar automáticamente el contenido de este archivo.
Si el ejercicio no se basa en un ejercicio de Problem Specifications, ten en cuenta lo siguiente:
Para nosotros es muy importante que el contenido de Exercism sea seguro para todo el mundo, así que a menudo pecamos de prudentes a la hora de decidir si una historia es apropiada o no. Aunque somos cuidadosos con lo que fusionamos, sabemos que es difícil ser consciente de lo que puede resultar problemático, así que siempre daremos por hecho que actúas de buena fe y haremos todo lo posible por detectar cualquier problema en la revisión de una forma no confrontativa. Si quieres que revisemos una historia contigo, menciona a @exercism/leadership y la veremos juntos. Estos son algunos puntos orientativos:
# Introduction
Bob is a lackadaisical teenager. In conversation, his responses are very limited.
.docs/introduction.append.md
Propósito: Texto de introducción adicional para añadir después de la introducción existente.
Presencia: Opcional
En algunos casos (poco frecuentes), es posible que quieras ampliar el archivo introduction.md del ejercicio, por ejemplo cuando el ejercicio ha implementado tests que no cubren las instrucciones existentes.
Un track que no quiera que Bob admita mensajes que no sean ASCII podría añadir lo siguiente:
# Introduction append
## Note
As part of his teenage rebellion, Bob has decided to only communicate using ASCII.
Los archivos append deben empezar con un encabezado H1. Este encabezado no se muestra, pero debe estar presente de todos modos. Al encabezado H1 suele seguirle un encabezado H2, que ayuda a separar el contenido genérico del específico del track.
.docs/instructions.md
Propósito: Proporcionar las instrucciones del ejercicio.
Presencia: Obligatorio
Si el ejercicio implementa un ejercicio de Problem Specifications, el contenido de este archivo debe coincidir con el archivo instructions.md del ejercicio de Problem Specifications (o el archivo description.md si no hay un archivo instructions.md). configlet tiene una funcionalidad para sincronizar automáticamente el contenido de este archivo.
Si el ejercicio no se basa en un ejercicio de Problem Specifications, ten en cuenta lo siguiente:
Para nosotros es muy importante que el contenido de Exercism sea seguro para todo el mundo, así que a menudo pecamos de prudentes a la hora de decidir si una historia es apropiada o no. Aunque somos cuidadosos con lo que fusionamos, sabemos que es difícil ser consciente de lo que puede resultar problemático, así que siempre daremos por hecho que actúas de buena fe y haremos todo lo posible por detectar cualquier problema en la revisión de una forma no confrontativa. Si quieres que revisemos una historia contigo, menciona a @exercism/leadership y la veremos juntos. Estos son algunos puntos orientativos:
# Instructions
Bob answers 'Sure.' if you ask him a question, such as "How are you?".
He answers 'Whoa, chill out!' if you YELL AT HIM (in all capitals).
He answers 'Calm down, I know what I'm doing!' if you yell a question at him.
He says 'Fine. Be that way!' if you address him without actually saying anything.
He answers 'Whatever.' to anything else.
.docs/instructions.append.md
Propósito: Texto de instrucciones adicional para añadir después de las instrucciones existentes.
Presencia: Opcional
En algunos casos (poco frecuentes), es posible que quieras ampliar el archivo instructions.md del ejercicio, por ejemplo cuando el ejercicio ha implementado tests que no cubren las instrucciones existentes.
# Instructions append
## Note
Bob's conversational partner is a purist when it comes to written communication and always follows normal rules regarding sentence punctuation in English.
Los archivos append deben empezar con un encabezado H1. Este encabezado no se muestra, pero debe estar presente de todos modos. Al encabezado H1 suele seguirle un encabezado H2, que ayuda a separar el contenido genérico del específico del track.
.docs/hints.md
Propósito: Proporcionar pistas al estudiante para ayudarle a desbloquearse en un ejercicio.
Presencia: Opcional
## General.Ver las pistas no será un camino «recomendado» y lo desaconsejaremos (con suavidad) a menos que el estudiante no pueda avanzar sin ellas. Así pues, conviene tener en cuenta que el estudiante que las lea estará un poco confundido o abrumado y quizá frustrado.
## General
- There are many [built-in methods][integers] to simplify working with integers.
[integers]: https://ruby-doc.org/core-2.7.0/Integer.html
Propósito: Describir el diseño del ejercicio.
Presencia: Opcional
Este archivo contiene información sobre el diseño del ejercicio, que incluye cosas como su objetivo, sus objetivos didácticos, lo que no hay que enseñar y más.
Existe para informar a los futuros mantenedores o colaboradores sobre el alcance y las limitaciones de un ejercicio, y así evitar la tendencia natural a que los ejercicios se vuelvan más complejos con el tiempo.
# Design
## Goal
The goal of this exercise is help students practice how to work with strings.
## Notes
This exercise does not contain any error handling tests.
.meta/config.json
Propósito: Contener metainformación sobre el ejercicio.
Presencia: Obligatorio
Este archivo contiene metainformación sobre el ejercicio:
authors: los nombres de usuario de GitHub del autor o los autores del ejercicio (opcional)
contributors: los nombres de usuario de GitHub del colaborador o los colaboradores del ejercicio (opcional)
files: las ubicaciones de los archivos usados en este ejercicio, relativas al directorio del ejercicio (obligatorio)
solution: el o los archivos de implementación stub (obligatorio)test: el o los archivos de tests (obligatorio)example: el o los archivos de implementación de ejemplo (obligatorio)editor: archivos adicionales que se muestran como solo lectura en el editor (opcional)invalidator: archivos que, cuando cambian, hacen que una solución quede desactualizada (opcional)language_versions: requisitos de versión del lenguaje (opcional)blurb: una descripción breve de este ejercicio. Su longitud debe ser <= 350. No se admite Markdown (obligatorio)source: la fuente en la que se basa este ejercicio (opcional)source_url: la URL de la fuente en la que se basa este ejercicio (opcional)test_runner: indica si las soluciones de este ejercicio deben probarse en el test runner. Su valor predeterminado es true si no se especifica. (opcional)representer: metainformación relacionada con cómo el representer procesa este archivo (opcional)
version: un número entero para la versión del representer que se usará en el ejercicio (obligatorio si la clave padre está presente)icon: el slug del icono (consulta la lista completa de iconos). Si no se especifica, se usará el slug del ejercicio (opcional)custom: cualquier dato no estándar específico del ejercicio. Se puede usar para personalizar el comportamiento de las herramientas del track en cada ejercicio (opcional)Si alguien es a la vez autor y colaborador, inclúyelo solo como autor.
{
"authors": ["FSharpForever"],
"files": {
"solution": ["Bob.fs"],
"test": ["BobTests.fs"],
"example": [".meta/Example.fs"]
},
"blurb": "Bob is a lackadaisical teenager. In conversation, his responses are very limited"
}
Ten en cuenta que:
language_versions es un string de formato libre que los tracks pueden usar e interpretar como quieran.Propósito: Contener información sobre qué tests están implementados.
Presencia: Opcional
Este archivo contiene información sobre qué tests están implementados, siempre que el ejercicio tenga tests definidos en su archivo canonical-data.json dentro del repositorio problem-specifications.
Existe para ayudar a los mantenedores a llevar un registro de qué tests están implementados y para documentar (opcionalmente) por qué cierto test no lo está. También se puede usar para detectar tests sin implementar.
La herramienta configlet se encarga de actualizar y sincronizar este archivo con los datos del repositorio problem-specifications mediante el comando configlet sync. Al sincronizar, configlet preguntará, para cada test sin implementar, si se debe incluir o no.
# This is an auto-generated file.
#
# Regenerating this file via `configlet sync` will:
# - Recreate every `description` key/value pair
# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications
# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion)
# - Preserve any other key/value pair
#
# As user-added comments (using the # character) will be removed when this file
# is regenerated, comments can be added via a `comment` key.
[3e5c30a8-87e2-4845-a815-a49671ade970]
description = "empty strand"
[a0ea42a6-06d9-4ac6-828c-7ccaccf98fec]
description = "can count one nucleotide in single-character input"
[eca0d565-ed8c-43e7-9033-6cefbf5115b5]
description = "strand with repeated nucleotide"
[40a45eac-c83f-4740-901a-20b22d15a39f]
description = "strand with multiple nucleotides"
[b4c47851-ee9e-4b0a-be70-a86e343bd851]
description = "strand with invalid nucleotides"
include = false
comment = "error handling omitted on purpose"
.approaches/introduction.md
Propósito: Introducción a los enfoques más comunes para el ejercicio
Presencia: Opcional
Este archivo describe los enfoques más comunes para el ejercicio. Consulta la documentación para obtener más información sobre qué debe incluir este archivo.
# Introduction
The key to this exercise is to deal with C# strings being immutable, which means that a `string`'s value cannot be changed.
Therefore, to reverse a string you'll need to create a _new_ `string`.
## Using LINQ
```csharp
public static string Reverse(string input)
{
return new string(input.Reverse().ToArray());
}
```
For more information, check the [LINQ approach][approach-linq].
## Which approach to use?
If readability is your primary concern (and it usually should be), the LINQ-based approach is hard to beat.
.approaches/config.json
Propósito: Metadatos de los enfoques
Presencia: Opcional (obligatorio cuando existe una introducción de enfoques o un enfoque)
Este archivo contiene metainformación sobre los enfoques del ejercicio:
introduction: los nombres de usuario de GitHub del autor o los autores de la introducción de los enfoques del ejercicio (opcional)
authors: los nombres de usuario de GitHub del autor o los autores de la introducción de los enfoques del ejercicio (obligatorio)
contributors: los nombres de usuario de GitHub del colaborador o los colaboradores de la introducción de los enfoques del ejercicio (opcional)
approaches: un array que enumera los enfoques detallados (opcional)
uuid: un UUID V4 que identifica el enfoque de forma única. El UUID debe ser único tanto dentro del track como en todos los tracks, y no debe cambiar nuncaslug: el slug del enfoque, que es un string en minúsculas y en kebab-case. El slug debe ser único entre todos los slugs de enfoques del track. Su longitud debe ser <= 255.title: el título del enfoque. Su longitud debe ser <= 255.blurb: una descripción breve de este enfoque. Su longitud debe ser <= 350. No se admite Markdown (obligatorio)authors: los nombres de usuario de GitHub del autor o los autores del enfoque del ejercicio (obligatorio)
contributors: los nombres de usuario de GitHub del colaborador o los colaboradores del enfoque del ejercicio (opcional)
tags: especifica las condiciones para que una entrega se vincule a un enfoque. (opcional)
all: un array de etiquetas que deben estar todas presentes en una entrega (opcional, salvo que any no tenga elementos)any: un array de etiquetas del que al menos una debe estar presente en una entrega (opcional, salvo que all no tenga elementos)not: ninguna de las etiquetas debe estar presente en una entrega (opcional){
"introduction": {
"authors": ["erikschierboom"]
},
"approaches": [
{
"uuid": "448fb2b4-18ab-4e55-aa54-ad4ed6d5f7f6",
"slug": "span",
"title": "Use Span<T>",
"blurb": "Use Span<T> to efficiently reverse a string.",
"authors": ["erikschierboom"]
}
]
}
.approaches/<approach-slug>/content.md
Propósito: Descripción detallada del enfoque
Presencia: Opcional (obligatorio para los enfoques)
Este archivo contiene una descripción detallada del enfoque. Consulta la documentación para obtener más información sobre qué debe incluir este archivo.
# Span
```csharp
Span<char> chars = stackalloc char[input.Length];
for (var i = 0; i < input.Length; i++)
{
chars[input.Length - 1 - i] = input[i];
}
return new string(chars);
```
This `Span<T>` approach uses a `for` loop.
.approaches/<approach-slug>/snippet.txt
Propósito: Fragmento que muestra el enfoque
Presencia: Opcional (obligatorio para los enfoques)
Este archivo contiene un fragmento pequeño que muestra el enfoque. El fragmento se muestra en la página «Dig Deeper» de un ejercicio.
Su número de líneas debe ser <= 8.
Consulta la documentación para obtener más información sobre qué debe incluir este archivo.
Span<char> chars = stackalloc char[input.Length];
for (var i = 0; i < input.Length; i++)
{
chars[input.Length - 1 - i] = input[i];
}
return new string(chars);
.article/config.json
Propósito: Metadatos de los artículos
Presencia: Opcional (obligatorio cuando existe un artículo)
Este archivo contiene metainformación sobre los artículos del ejercicio:
articles: un array que enumera los artículos detallados (opcional)
uuid: un UUID V4 que identifica el artículo de forma única. El UUID debe ser único tanto dentro del track como en todos los tracks, y no debe cambiar nuncaslug: el slug del artículo, que es un string en minúsculas y en kebab-case. El slug debe ser único entre todos los slugs de artículos del track. Su longitud debe ser <= 255.title: el título del artículo. Su longitud debe ser <= 255.blurb: una descripción breve de este artículo. Su longitud debe ser <= 350. No se admite Markdown (obligatorio)authors: los nombres de usuario de GitHub del autor o los autores del artículo del ejercicio (obligatorio)
contributors: los nombres de usuario de GitHub del colaborador o los colaboradores del artículo del ejercicio (opcional)
{
"articles": [
{
"uuid": "6db71962-62d5-448b-a980-c20ae41013ed",
"slug": "performance",
"title": "Optimizing performance",
"blurb": "Explore how to most efficiently reverse a string and what the trade-offs are.",
"authors": ["erikschierboom"]
}
]
}
.articles/<article-slug>/content.md
Propósito: Descripción detallada del enfoque
Presencia: Opcional (obligatorio para los enfoques)
Este archivo contiene una descripción detallada del enfoque. Consulta la documentación para obtener más información sobre qué debe incluir este archivo.
# Performance
In this document, we'll find out which approach is the most performant one.
## Benchmark results
| Method | Mean | Error | StdDev | Median | Allocated |
| -----: | --------: | --------: | --------: | --------: | --------: |
| Linq | 29.133 ns | 0.5865 ns | 0.5486 ns | 28.984 ns | 80 B |
| Array | 4.806 ns | 0.4999 ns | 1.4739 ns | 3.967 ns | - |
.articles/<article-slug>/snippet.txt
Propósito: Fragmento que muestra el enfoque
Presencia: Opcional (obligatorio para los artículos)
Este archivo contiene un fragmento pequeño que muestra el artículo. El fragmento se muestra en la página «Dig Deeper» de un ejercicio.
Su número de líneas debe ser <= 8.
Consulta la documentación para obtener más información sobre qué debe incluir este archivo.
| Method | Mean | Allocated |
| -----: | --------: | --------: |
| Linq | 29.133 ns | 80 B |
| Array | 4.806 ns | - |
Propósito: Proporcionar un punto de partida para los estudiantes.
Presencia: Obligatorio
"files.solution" del archivo .meta/config.json.using System;
public static class Isogram
{
public static bool IsIsogram(string word)
{
throw new NotImplementedException("You need to implement this function.");
}
}
Propósito: Verificar que una solución es correcta.
Presencia: Obligatorio
"files.test" del archivo .meta/config.json.using Xunit;
public class IsogramTest
{
[Fact]
public void Empty_string() =>
Assert.True(Isogram.IsIsogram(""));
[Fact(Skip = "Remove this Skip property to run this test")]
public void Isogram_with_only_lower_case_characters() =>
Assert.True(Isogram.IsIsogram("isogram"));
[Fact(Skip = "Remove this Skip property to run this test")]
public void Word_with_one_duplicated_character() =>
Assert.False(Isogram.IsIsogram("eleven"));
}
Propósito: Proporcionar una implementación de ejemplo que pasa todos los tests.
Presencia: Obligatorio
"files.example" del archivo .meta/config.json.using System.Linq;
public static class Isogram
{
public static bool IsIsogram(string word)
{
var lowerCaseLetters = word.ToLower().Where(char.IsLetter).ToList();
return lowerCaseLetters.Distinct().Count() == lowerCaseLetters.Count;
}
}
Propósito: Archivos adicionales de proyecto, de compilación o de apoyo necesarios para que los tests se puedan ejecutar.
Presencia: Obligatorio si los archivos predeterminados no bastan para ejecutar los tests
Algunos lenguajes necesitan archivos adicionales para que los tests se ejecuten. Ejemplos de ello son los archivos de proyecto de C# y los archivos package.json de Node, sin los cuales no será posible ejecutar los tests.
Algunos archivos no son específicos de ejercicios concretos, sino que se aplican a todos los ejercicios. Consulta la documentación para obtener más información.
Hay una diferencia en cómo se presenta la documentación del ejercicio al estudiante cuando usa el editor del navegador en lugar de la CLI. Consulta este documento para obtener más información.
Cada ejercicio tiene un icono que lo acompaña.
De forma predeterminada, el icono mostrado es el cuyo nombre coincide con el slug del ejercicio.
Se puede sobrescribir especificando la propiedad icon en el archivo .meta/config.json del ejercicio.
Si estás implementando un ejercicio a partir de los metadatos de problem-specifications, probablemente ya exista un icono para ese ejercicio. Si no es así, abre una incidencia en el repositorio website-icons.