Si has llegado hasta aquí, ya sabes cómo manejar variables, colecciones, controlar el flujo de tu programa y crear funciones o lambdas para organizar tus acciones. ¡Enhorabuena! Tienes unas bases de programación fabulosas. Pero ahora toca dar el siguiente paso lógico y entrar de lleno en la Programación Orientada a Objetos (POO).
Imagina que en tu aplicación tienes que gestionar la información de decenas de usuarios: su nombre, su identificador, su correo y su edad. ¿Vas a usar variables sueltas por todo el código para cada cosita de cada usuario? Sería un absoluto caos y muy propenso a errores. Para eso están las clases y los objetos. En esta unidad, vamos a ver cómo Kotlin hace que crear y agrupar estructuras de datos sea un proceso muy limpio, y descubriremos la magia de las data classes (clases de datos), una de las características estrella del lenguaje que te ahorrará horas de escribir código.
¿Qué son las clases y cómo se declaran?
En Kotlin, la programación orientada a objetos es muy directa. Una clase te permite declarar un conjunto de características compartidas para un concepto. Piensa en la clase como si fuera el «molde» (por ejemplo, el concepto de Cliente) y en los objetos como las «galletas» reales que salen de ese molde (el cliente Juan, la clienta María).
Para declarar una clase, simplemente utilizamos la palabra reservada class:
class Cliente
Propiedades de una clase
Las características concretas de ese molde se llaman propiedades. Puedes declarar las propiedades de una clase directamente entre paréntesis () justo después del nombre de la misma. A esta parte se le conoce como el encabezado de la clase (class header).
class Contacto(val id: Int, var email: String)
También puedes definir propiedades adicionales dentro del cuerpo de la clase, abriendo unas llaves {}:
class Contacto(val id: Int, var email: String) {
val categoria: String = "trabajo"
}
La regla de oro: Te recomendamos encarecidamente que declares tus propiedades como de solo lectura (val) siempre que sea posible. Usa variables mutables (var) únicamente si tienes la absoluta certeza de que ese dato necesitará cambiar después de haber creado el objeto.
Al igual que ocurría con las funciones, las propiedades de una clase pueden tener valores por defecto:
class Contacto(val id: Int, var email: String = "[email protected]") {
val categoria: String = "trabajo"
}
El dato: Si pones parámetros en el encabezado sin escribir val o var delante, Kotlin los tratará como simples parámetros de configuración y no como propiedades reales de la clase; por lo tanto, no podrás acceder a ellos después. ¡Acuérdate de poner siempre val o var!
Nota extra: Kotlin te permite poner una coma al final de la última propiedad (conocido como trailing comma) para que te sea más fácil reordenar el código copiando y pegando líneas.
Crear instancias (objetos)
Para poder usar esa clase en la vida real, necesitas instanciarla (crear un objeto) a través de un constructor. En lenguajes más antiguos como Java tendrías que usar la palabra new a la fuerza, pero a Kotlin le gusta el código conciso, así que no hace falta.
Por defecto, el lenguaje te crea un constructor automáticamente exigiendo los parámetros que hayas puesto en el encabezado.
class Contacto(val id: Int, var email: String)
fun main() {
// Creamos la instancia y la guardamos en una variable
val contacto1 = Contacto(1, "[email protected]")
}
En este ejemplo:
Contacto es la clase (el molde).
contacto1 es la instancia (el objeto real en la memoria).
Acceder a las propiedades
Para leer o modificar una propiedad de un objeto que ya has creado, la sintaxis es facilísima: solo tienes que escribir el nombre de la instancia, seguido de un punto ., y el nombre de la propiedad.
fun main() {
val contacto = Contacto(1, "[email protected]")
// Imprimimos el valor de la propiedad
println(contacto.email)
// Salida: [email protected]
// Actualizamos el valor (es posible porque lo definimos como 'var')
contacto.email = "[email protected]"
// Imprimimos el nuevo valor
println(contacto.email)
// Salida: [email protected]
}
Si necesitas concatenar el valor de esa propiedad dentro de un texto, recuerda usar las plantillas de cadenas con el símbolo del dólar. Como estás accediendo a una propiedad y no a una variable simple, es obligatorio envolverlo todo entre llaves ${}:
println("Su correo electrónico de empresa es: ${contacto.email}")
Funciones miembro
Las clases no son simples «bolsas» para guardar datos estáticos. También pueden tener comportamiento propio. A las funciones que declaramos dentro del cuerpo de una clase se las denomina funciones miembro (o métodos).
Para llamar a estas funciones, volvemos a usar la sintaxis del punto .:
class Contacto(val id: Int, var email: String) {
// Esta es una función miembro
fun imprimirId() {
println("El identificador secreto es: $id")
}
}
fun main() {
val contacto = Contacto(1, "[email protected]")
// Llamamos a la función
contacto.imprimirId()
// Salida: El identificador secreto es: 1
}
El superpoder de Kotlin: data classes
Aquí es donde Kotlin brilla y demuestra por qué es un lenguaje tan popular. En el día a día, muchas veces vas a crear clases cuyo único propósito sea almacenar información de forma pasiva. Para estos casos concretos, Kotlin inventó las data classes (clases de datos).
Tienen exactamente la misma funcionalidad que las clases normales que acabamos de ver, pero el compilador de Kotlin les inyecta automáticamente por detrás un montón de funciones extra para que no tengas que escribir código repetitivo o boilerplate.
Para declararlas, solo tienes que poner la palabra data antes del class:
data class Usuario(val nombre: String, val id: Int)
Al hacer esto, ganas acceso automático a tres funciones vitales que analizamos en los siguientes puntos.
Imprimir como texto (toString)
Si imprimes una clase normal de Kotlin por la consola, te escupirá un nombre incomprensible con su referencia en memoria (algo tipo Usuario@2f92e0f4). Pero las data classes sobrescriben la función toString() de forma nativa para que la salida sea humana y legible.
fun main() {
val usuario = Usuario("Alex", 1)
println(usuario)
// Salida automática y bonita: Usuario(nombre=Alex, id=1)
}
Esto es indispensable cuando estás haciendo pruebas o guardando logs en tu servidor.
Comparar instancias (==)
Si tú comparas dos instancias distintas de una clase normal usando ==, Kotlin te dirá que son diferentes false, porque mirará si ocupan el mismo espacio físico en la memoria del ordenador.
Sin embargo, en las data classes, el operador == (que llama a la función equals()) es inteligente: compara los datos reales.
fun main() {
val user1 = Usuario("Alex", 1)
val user2 = Usuario("Alex", 1)
val user3 = Usuario("Max", 2)
println("user1 y user2: ${user1 == user2}") // true (¡Tienen los mismos datos!)
println("user1 y user3: ${user1 == user3}") // false
}
Copiar instancias (copy)
Imagina que quieres crear un objeto nuevo partiendo de uno existente, pero alterando únicamente uno de sus datos. Modificar el objeto original usando un var puede causar fallos encadenados si otra parte de tu código estaba usando a ese mismo usuario.
La función copy() te clona el objeto a la perfección, y como parámetros opcionales le puedes pasar el nuevo valor para las propiedades que quieras alterar:
fun main() {
val usuario = Usuario("Alex", 1)
// Clonación exacta
println(usuario.copy())
// Usuario(nombre=Alex, id=1)
// Clonación con el nombre alterado
println(usuario.copy(nombre = "Max"))
// Usuario(nombre=Max, id=1)
}
Ejercicios
Aquí tienes varios ejercicios de menos a más dificultad (los tres primeros son traducciones de la documentación oficial de Kotlin y los dos últimos son extras para asentar los conceptos). Abre tu Kotlin Playground y vamos a mancharnos las manos.
El empleado
Define una data class llamada Employee con dos propiedades: name (para el nombre en formato texto) y salary (para el salario en enteros). Asegúrate de que la propiedad del salario sea mutable, ¡o de lo contrario el empleado jamás podrá recibir un aumento a final de año!
El main a continuación te muestra cómo lo vamos a usar.
// Escribe tu código aquí
fun main() {
val emp = Employee("Mary", 20)
println(emp)
emp.salary += 10
println(emp)
}
Estructuras anidadas
A veces los objetos contienen a otros objetos. Declara las data classes adicionales que se necesitan para que el siguiente código compile sin errores. Fíjate bien en la llamada dentro de main() para adivinar qué propiedades y de qué tipo necesita cada clase.
data class Person(val name: Name, val address: Address, val ownsAPet: Boolean = true)
// Escribe tu código aquí:
// data class Name(...)
fun main() {
val person = Person(
Name("John", "Smith"),
Address("123 Fake Street", City("Springfield", "US")),
ownsAPet = false
)
println(person)
}
Generador aleatorio de empleados
Para probar tu código en el futuro, vas a necesitar un generador que cree empleados al azar. Define una clase normal RandomEmployeeGenerator.
El constructor de la clase debe recibir el minSalary y el maxSalary (ambos enteros y mutables).
Dentro del cuerpo de la clase, guarda una lista fija de nombres potenciales. Y, por último, crea una función miembro llamada generateEmployee() que devuelva una nueva instancia de tu data classEmployee usando un nombre aleatorio de tu lista y un salario aleatorio dentro de los márgenes dados.
Pista: Las listas de Kotlin tienen una extensión muy útil llamada .random() que te devuelve un ítem al azar. Usa Random.nextInt(from = minSalary, until = maxSalary) para generar el número.
import kotlin.random.Random
data class Employee(val name: String, var salary: Int)
// Escribe tu clase RandomEmployeeGenerator aquí
fun main() {
val empGen = RandomEmployeeGenerator(10, 30)
println(empGen.generateEmployee())
println(empGen.generateEmployee())
empGen.minSalary = 50
empGen.maxSalary = 100
println(empGen.generateEmployee())
}
El inventario de la tienda
Crea una clase (¡normal, no data class!) llamada Producto que reciba en su constructor un nombre de tipo String y un precio de tipo Double (ambos inmutables).
Añade una propiedad dentro del cuerpo de la clase llamada stock de tipo entero, inicializada en 0, que por supuesto sea mutable.
Crea una función miembro llamada añadirStock(cantidad: Int) que le sume esa cantidad al stock actual.
En tu función main, crea un producto, añádele 50 unidades de stock, e imprime un texto final diciendo: «Tenemos [stock] unidades de [nombre]».
Clonando clientes
Tienes una data class Cliente(val id: Int, val nombre: String, val email: String). Fíjate en que todo está blindado y es inmutable (val).
Crea una instancia para «Ana» con ID 1 y correo «[email protected]». De repente, Ana te avisa de que ha cambiado su correo corporativo a «[email protected]».
Como no puedes hacer ana.email = ... porque daría error, usa la función de las data classes que hemos aprendido para crear un nuevo objeto llamado anaActualizada basado en Ana, pero con su correo modificado. Imprime por consola a anaActualizada.
Soluciones a los ejercicios
No hagas trampas. Échale un vistazo a las soluciones únicamente cuando te hayas peleado un buen rato con tu editor de código y el compilador te haya gritado un par de veces.
El empleado
data class Employee(val name: String, var salary: Int)
fun main() {
val emp = Employee("Mary", 20)
println(emp)
emp.salary += 10
println(emp)
}
Estructuras anidadas
data class Person(val name: Name, val address: Address, val ownsAPet: Boolean = true)
data class Name(val first: String, val last: String)
data class Address(val street: String, val city: City)
data class City(val name: String, val countryCode: String)
fun main() {
val person = Person(
Name("John", "Smith"),
Address("123 Fake Street", City("Springfield", "US")),
ownsAPet = false
)
println(person)
}
Generador aleatorio de empleados
import kotlin.random.Random
data class Employee(val name: String, var salary: Int)
class RandomEmployeeGenerator(var minSalary: Int, var maxSalary: Int) {
// Definimos la lista en el cuerpo de la clase
val names = listOf("John", "Mary", "Ann", "Paul", "Jack", "Elizabeth")
// Función miembro que devuelve un Employee
fun generateEmployee() = Employee(
names.random(),
Random.nextInt(from = minSalary, until = maxSalary)
)
}
fun main() {
val empGen = RandomEmployeeGenerator(10, 30)
println(empGen.generateEmployee())
println(empGen.generateEmployee())
empGen.minSalary = 50
empGen.maxSalary = 100
println(empGen.generateEmployee())
}
El inventario de la tienda
class Producto(val nombre: String, val precio: Double) {
// Propiedad en el cuerpo inicializada a 0
var stock: Int = 0
fun añadirStock(cantidad: Int) {
stock += cantidad
}
}
fun main() {
val miProducto = Producto("Teclado Mecánico", 45.99)
miProducto.añadirStock(50)
println("Tenemos ${miProducto.stock} unidades de ${miProducto.nombre}")
}
Clonando clientes
data class Cliente(val id: Int, val nombre: String, val email: String)
fun main() {
// Creamos nuestra instancia original
val ana = Cliente(1, "Ana", "[email protected]")
// Clonamos el objeto modificando únicamente la propiedad email
val anaActualizada = ana.copy(email = "[email protected]")
// Comprobamos la magia
println(anaActualizada)
// Salida: Cliente(id=1, nombre=Ana, [email protected])
}
Hasta ahora, todos los programas que hemos escrito se ejecutaban en línea recta: el ordenador leía la línea 1, luego la 2, luego la 3… y terminaba. Pero en el mundo real, las aplicaciones necesitan tomar decisiones (si el usuario tiene saldo, haz la compra; si no, muestra un error) y repetir tareas (mostrar los 50 mensajes de un chat uno por uno).
Para esto sirve el Control de Flujo. En Kotlin, contamos con herramientas modernizadas y súper potentes para dirigir el tráfico de nuestro código. ¡Vamos a descubrirlas!
Tomando decisiones: el clásico if / else
La forma más básica de tomar una decisión en programación es usar la estructura if (si ocurre esto…) y else (si no, haz esto otro…).
La condición a evaluar siempre va entre paréntesis (), y el bloque de código que se ejecutará va entre llaves {}.
fun main() {
val edad = 18
if (edad >= 18) {
println("Puedes entrar a la discoteca.")
} else {
println("Lo siento, vuelve a casa.")
}
}
El súper-poder de Kotlin: el if como expresión
Si vienes de lenguajes como Java o JavaScript, conocerás el famoso operador ternario (condicion ? valor1 : valor2) para asignar variables en una sola línea. En Kotlin, el operador ternario no existe porque no hace falta.
En Kotlin, un if puede devolver un valor directamente. Si tu if y tu else solo tienen una línea, puedes quitar las llaves y hacerlo así de elegante:
fun main() {
val a = 10
val b = 20
// El resultado del if se guarda directamente en la variable 'mayor'
val mayor = if (a > b) a else b
println("El número mayor es $mayor") // Imprime: 20
}
El condicional when: el switch con esteroides
Cuando tienes que evaluar muchísimas opciones distintas, usar decenas de if / else if / else encadenados hace que el código sea ilegible.
Otros lenguajes usan la palabra switch. Kotlin usa when (cuando), y es una de las herramientas más queridas por los desarrolladores.
when como instrucción
Colocamos la variable que queremos evaluar entre paréntesis. Luego usamos una «flechita» -> para indicar qué hacer en cada caso. El else actúa como la opción por defecto si no se cumple ninguna de las anteriores.
fun main() {
val boton = "X"
when (boton) {
"A" -> println("Saltar")
"B" -> println("Atacar")
"X" -> println("Abrir Inventario")
"Y" -> println("Magia")
else -> println("Botón no reconocido")
}
}
Nota: Kotlin evalúa de arriba a abajo. En cuanto encuentra una coincidencia, ejecuta esa línea y sale del when automáticamente. (¡Adiós a la pesadilla de olvidar poner los break de otros lenguajes!)
when como expresión (devolviendo un valor)
Al igual que el if, podemos usar when para asignar un valor directamente a una variable:
val estadoSemaforo = "Rojo"
val accion = when (estadoSemaforo) {
"Verde" -> "Acelerar"
"Ambar" -> "Frenar poco a poco"
"Rojo" -> "Detenerse"
else -> "Llamar al mecánico" // Al devolver valor, el 'else' es OBLIGATORIO
}
println("Debes: $accion")
Rangos: preparando el terreno para los bucles
Antes de aprender a repetir tareas, necesitamos saber cómo crear Rangos (intervalos de valores) en Kotlin. Es facilísimo:
.. (Punto punto): Crea un rango que incluye el último número. 1..4 equivale a 1, 2, 3, 4.
..< (Punto punto menor): Crea un rango que excluye el último número. 1..<4 equivale a 1, 2, 3.
downTo: Cuenta hacia atrás. 4 downTo 1 equivale a 4, 3, 2, 1.
step: Cambia el tamaño del salto. 1..5 step 2 equivale a 1, 3, 5.
(¡También funciona con letras del abecedario! Ej: 'a'..'d')
Bucles: repitiendo tareas sin cansarse
El bucle for (para cada…)
Se usa cuando sabes exactamente cuántas veces quieres repetir algo, o cuando quieres recorrer una Colección (como las Listas que vimos en el artículo anterior).
fun main() {
// Repetir un código un número exacto de veces usando un rango
for (numero in 1..5) {
print(numero) // Imprime: 12345
}
println() // Salto de línea
// Recorrer una lista
val pasteles = listOf("Zanahoria", "Queso", "Chocolate")
for (pastel in pasteles) {
println("¡Qué rico, un pastel de $pastel!")
}
}
Los bucles while y do-while (mientras que…)
Se usan cuando no sabes cuántas veces se va a repetir algo, pero sabes que debe repetirse «mientras» se cumpla una condición.
while: Primero comprueba la condición. Si es falsa desde el principio, nunca se ejecuta.
do-while: Primero ejecuta el código una vez, y luego comprueba la condición. Te asegura que el bloque de código se va a ejecutar como mínimo una vez.
fun main() {
var porcionesComidas = 0
// Bucle while normal
while (porcionesComidas < 3) {
println("Me como una porción")
porcionesComidas++ // Esto suma 1 a la variable (es lo mismo que porcionesComidas = porcionesComidas + 1)
}
}
Crea un minijuego donde ganas si al lanzar dos dados sacas el mismo número. Si son iguales, imprime "¡Has ganado :)". Si no, "Has perdido :(".
(Nota: Para generar números aleatorios usaremos una librería nativa de Kotlin llamada Random).
import kotlin.random.Random
fun main() {
// Genera un número aleatorio entre 0 y 5.
val dado1 = Random.nextInt(6)
val dado2 = Random.nextInt(6)
println("Dado 1: $dado1 | Dado 2: $dado2")
// Escribe tu código (if/else) a partir de aquí:
}
Botones de consola
Usando un when que actúe como expresión (asignando su resultado o metiéndolo directo en un println), haz que el programa imprima la acción correspondiente al botón pulsado:
A -> «Sí»
B -> «No»
X -> «Menú»
Y -> «Nada»
Cualquier otro -> «No existe ese botón»
fun main() {
val boton = "A"
// Escribe tu when aquí dentro del println
println(
// ...
)
}
Comiendo Pizza
Tienes un código muy feo que cuenta porciones de pizza repitiendo líneas a mano. Conviértelo en un bucle while que cuente automáticamente hasta llegar a las 8 porciones.
fun main() {
var porciones = 0
// ¡Borra este desastre y usa un bucle while!
porciones++
println("Solo hay $porciones porción/es de pizza :(")
porciones++
println("Solo hay $porciones porción/es de pizza :(")
// ... así hasta 7 ...
// Al salir del bucle debe imprimir esto (y la variable debe valer 8):
println("¡Tenemos $porciones porciones! ¡Una pizza entera! :D")
}
El clásico reto FizzBuzz
Este es uno de los ejercicios más famosos en las entrevistas de programación junior.
Escribe un programa que imprima los números del 1 al 100, pero:
Si el número es divisible por 3, imprime la palabra "fizz" en lugar del número.
Si el número es divisible por 5, imprime "buzz".
Si el número es divisible por 3 Y por 5 (es decir, divisible por 15), imprime "fizzbuzz".
Pista: Usa un bucle for del 1 al 100. Dentro, usa un when sin argumento para evaluar condiciones usando el operador Módulo % (que te da el resto de una división. Si numero % 3 == 0, es que es divisible por 3).
fun main() {
// Escribe tu código aquí (for + when)
}
Soluciones a los ejercicios
No hagas trampas. Échale un vistazo a las soluciones únicamente cuando te hayas peleado un buen rato con el código.
Los dados
import kotlin.random.Random
fun main() {
val dado1 = Random.nextInt(6)
val dado2 = Random.nextInt(6)
println("Dado 1: $dado1 | Dado 2: $dado2")
// Comprobamos la igualdad con ==
if (dado1 == dado2) {
println("¡Has ganado :)")
} else {
println("Has perdido :(")
}
}
Botones de consola
fun main() {
val boton = "A"
println(
when (boton) {
"A" -> "Sí"
"B" -> "No"
"X" -> "Menú"
"Y" -> "Nada"
else -> "No existe ese botón"
}
)
}
La pizza
fun main() {
var porciones = 0
while (porciones < 7) {
porciones++
println("Solo hay $porciones porción/es de pizza :(")
}
porciones++ // Sumamos la octava porción al salir
println("¡Tenemos $porciones porciones! ¡Una pizza entera! :D")
}
El clásico reto FizzBuzz
fun main() {
for (numero in 1..100) {
println(
// Al usar when SIN variable, podemos evaluar condiciones booleanas libres
// ¡El orden importa! Hay que comprobar el 15 primero.
when {
numero % 15 == 0 -> "fizzbuzz"
numero % 3 == 0 -> "fizz"
numero % 5 == 0 -> "buzz"
else -> numero // Si no cumple ninguna, imprime el número normal
}
)
}
}
En las unidades anteriores aprendimos a guardar un dato individual en una variable (como un número o un texto). Pero, ¿qué pasa si estás creando una app y necesitas guardar los nombres de 100 usuarios? ¿Vas a crear 100 variables distintas? ¡Por supuesto que no!
Para eso existen las colecciones. Son estructuras que nos permiten agrupar múltiples datos bajo un mismo nombre para procesarlos más tarde.
En Kotlin, la regla de seguridad que vimos con val y var se mantiene: las colecciones pueden ser de solo lectura (inmutables) o mutables (modificables). Kotlin nos ofrece tres tipos principales. ¡Vamos a destriparlas!
Listas (Lists): El cajón ordenado
Una Lista (List) es exactamente lo que imaginas: una colección de elementos ordenados uno detrás de otro.
Tienen un orden estricto (el primero, el segundo, el tercero…).
Permiten duplicados (puedes tener el mismo elemento varias veces).
Crear listas
Para crear una lista de solo lectura usamos listOf(). Si queremos una lista a la que podamos añadir o quitar cosas en el futuro, usamos mutableListOf().
fun main() {
// Lista de solo lectura (Kotlin deduce que es de tipo String)
val formas = listOf("triángulo", "cuadrado", "círculo")
println(formas) // [triángulo, cuadrado, círculo]
// Lista mutable (Aquí le decimos explícitamente el tipo <String>)
val formasMutables: MutableList<String> = mutableListOf("triángulo", "cuadrado", "círculo")
}
Profundizando: El índice cero y los errores comunes
Como las listas están ordenadas, cada elemento tiene una posición o «índice». ¡Ojo! En programación, siempre empezamos a contar desde el cero.
Piensa en los ascensores en España: cuando entras al edificio desde la calle, estás en la Planta Baja (índice 0). Si subes un piso, llegas a la Planta 1 (el índice 1, que en realidad es el segundo nivel). El índice te dice cuántos saltos das desde el principio.
fun main() {
val formas = listOf("triángulo", "cuadrado", "círculo")
// Acceder por su posición (índice)
println("El primer elemento es: ${formas[0]}") // triángulo
// ¡CUIDADO! El terror de los novatos: IndexOutOfBoundsException
// println(formas[3]) -> ¡El programa explotará porque no hay un 4º elemento!
}
Kotlin también nos regala funciones súper útiles para no tener que lidiar siempre con los números:
fun main() {
val formas = listOf("triángulo", "cuadrado", "círculo")
println("El primer elemento: ${formas.first()}") // triángulo
println("El último elemento: ${formas.last()}") // círculo
println("Total de elementos: ${formas.count()}") // 3
// Comprobar si algo existe con la palabra 'in'
println("círculo" in formas) // true
}
Modificar listas mutables y el «truco del candado»
Si tu lista es MutableList, usas .add() para añadir y .remove() para borrar.
A veces tienes una lista mutable, pero se la vas a pasar a otra parte de tu código y no quieres que se modifique por accidente. Puedes «disfrazarla» de solo lectura:
val inventarioMutable: MutableList<String> = mutableListOf("Espada", "Poción")
val inventarioBloqueado: List<String> = inventarioMutable // ¡Candado puesto! Ahora no se puede modificar.
Conjuntos (Sets): El VIP de la exclusividad
Un conjunto (Set) es parecido a una lista, pero con dos diferencias vitales:
No tienen orden (no puedes pedir el elemento [0]).
NO permiten elementos duplicados. Son únicos y exclusivos.
Se crean con setOf() y mutableSetOf().
fun main() {
// Fíjate que ponemos "cereza" dos veces
val frutas = setOf("manzana", "plátano", "cereza", "cereza")
// Al imprimir, ¡la segunda cereza ha desaparecido mágicamente!
println(frutas) // [manzana, plátano, cereza]
println("Hay ${frutas.count()} frutas únicas") // 3
}
Profundizando: ¿Por qué usar Sets? ¡Por la velocidad!
Si quieres saber si el email «[email protected]» está en una Lista de 1 millón de usuarios, el ordenador mirará uno a uno. Es lentísimo.
Si usas un Set, Kotlin usa matemáticas internas (una función Hash) para saber exactamente dónde está guardado. Lo encuentra al instante. ¡Usa Sets cuando trabajes con muchos datos únicos!
Un Mapa (Map) almacena datos en pares Clave-Valor (Key-Value).
Piénsalo como la carta de un restaurante: el nombre del plato es la clave y su precio es el valor.
Las claves (keys) deben ser únicas.
Los valores (values) sí pueden repetirse.
Se crean con mapOf() y mutableMapOf(). Usamos la palabrita to para unir la pareja.
fun main() {
// Especificamos explícitamente: Claves String, Valores Int
val menuZumos: MutableMap<String, Int> = mutableMapOf("manzana" to 3, "kiwi" to 4)
// Leer un valor usando su clave entre corchetes
println("El zumo de manzana cuesta: ${menuZumos["manzana"]}€") // 3€
}
Profundizando: Nulos y sobreescritura
¿Qué pasa si buscas algo que no existe en el menú? Kotlin te devuelve null (nulo, vacío). Así evita que tu aplicación se cuelgue por un error.
println(menuZumos["piña"]) // Imprime: null
¿Y si añado una clave que ya existe? Se sobreescribe el valor antiguo. Es la forma oficial de actualizar datos:
menuZumos["manzana"] = 5 // ¡Inflación! Actualizamos el precio a 5€
menuZumos["coco"] = 6 // Como "coco" no existe, lo añade nuevo al mapa
menuZumos.remove("kiwi") // Eliminamos el kiwi
println(menuZumos.keys) // [manzana, coco]
println(menuZumos.values) // [5, 6]
Ejercicios
Abre el Kotlin Playground e intenta resolver estos ejercicios para asentar lo aprendido.
Sumando listas
Tienes una lista de números «verdes» y otra de «rojos». Imprime cuántos números hay en total sumando el tamaño de ambas listas.
fun main() {
val numerosVerdes = listOf(1, 4, 23)
val numerosRojos = listOf(17, 2)
// Escribe tu código aquí:
}
El protocolo de red
Tienes un Set con protocolos en mayúsculas. Un usuario pide «smtp» en minúsculas. Comprueba si está soportado (debe devolver un Boolean).
Pista: Usa .uppercase() en la petición para pasarla a mayúsculas antes de buscar en el Set con in.
fun main() {
val SOPORTADOS = setOf("HTTP", "HTTPS", "FTP")
val peticion = "smtp"
val estaSoportado = // Escribe tu código aquí
println("Soporte para $peticion: $estaSoportado")
}
Diccionario de números
Crea un Map que relacione los números del 1 al 3 con su nombre escrito («uno», «dos», «tres»). Imprime cómo se escribe el número 2 buscándolo en el mapa.
fun main() {
val numeroAPalabra = // Escribe tu código aquí
val n = 2
// Imprime el resultado
}
El inventario del héroe
Crea una lista mutable llamada inventario con: «Espada», «Escudo», «Poción».
Añade un «Arco». Elimina la «Poción». Finalmente, imprime el inventario y cuántos objetos tiene usando .count().
Soluciones a los ejercicios
¡No mires hasta haberlo intentado!
Sumando listas
fun main() {
val numerosVerdes = listOf(1, 4, 23)
val numerosRojos = listOf(17, 2)
val total = numerosVerdes.count() + numerosRojos.count()
println("Total: $total números")
}
El protocolo de red
fun main() {
val SOPORTADOS = setOf("HTTP", "HTTPS", "FTP")
val peticion = "smtp"
val estaSoportado = peticion.uppercase() in SOPORTADOS
println("Soporte para $peticion: $estaSoportado") // false
}
Diccionario de números
fun main() {
val numeroAPalabra = mapOf(1 to "uno", 2 to "dos", 3 to "tres")
val n = 2
println("El número $n se escribe como '${numeroAPalabra[n]}'")
}
El inventario del héroe
fun main() {
val inventario = mutableListOf("Espada", "Escudo", "Poción")
inventario.add("Arco")
inventario.remove("Poción")
println("Inventario: $inventario")
println("Tienes ${inventario.count()} objetos.")
}
En la unidad anterior vimos cómo hacer nuestro primer «Hola Mundo» y cómo usar variables (val y var). Pero nos dejamos un detalle importantísimo en el tintero: ¿qué tipo de información estamos guardando exactamente en esas variables?
En Kotlin, absolutamente todo tiene un tipo. Los tipos son fundamentales porque le dicen al compilador (el «cerebro» que lee tu código) qué puedes y qué no puedes hacer con una variable. Por ejemplo, puedes multiplicar dos números, pero no puedes multiplicar dos palabras, ¿verdad?
Ahora vamos a desgranar los tipos básicos de Kotlin, a aprender a operar con ellos y a descubrir cómo Kotlin nos facilita la vida con su «magia» deductiva.
La inferencia de tipos: Kotlin es muy listo
Si recuerdas la unidad anterior, declarábamos variables así:
var clientes = 10
En ningún momento le dijimos a Kotlin: «Oye, que sepas que clientes es un número entero». Sin embargo, Kotlin lo supo al instante. Esta capacidad se llama Inferencia de Tipos (Type Inference).
Como a la variable clientes le asignamos un 10, Kotlin deduce inmediatamente que su tipo es numérico, concretamente un Int (entero). Gracias a esto, el compilador sabe que puedes realizar operaciones matemáticas con esta variable.
Mira este ejemplo de asignaciones compuestas (una forma abreviada de hacer matemáticas):
fun main() {
var clientes = 10
// Vienen 3 clientes más (clientes = clientes + 3)
clientes += 3 // Ahora hay 13
// Se van 5 clientes
clientes -= 5 // Ahora hay 8
// El negocio explota y multiplicamos los clientes por 2
clientes *= 2 // Ahora hay 16
// Dividimos a los clientes en 4 grupos
clientes /= 4 // Ahora hay 4 en cada grupo
println(clientes)
// Resultado: 4
}
Los tipos básicos de Kotlin: La lista completa
Aunque Kotlin infiere los tipos, a veces querrás (o necesitarás) ser explícito. Para declarar un tipo manualmente, se usan los dos puntos : después del nombre de la variable.
A continuación mostramos los tipos fundamentales.
Números enteros (sin decimales)
Int: Es el estándar para números sin decimales. (Ej: val año: Int = 2024)
Long: Se usa para números ridículamente grandes. Si un número es demasiado grande para un Int, Kotlin lo convertirá en Long automáticamente. También puedes forzarlo añadiendo una L mayúscula al final. (Ej: val estrellas: Long = 9876543210L)
Byte y Short: Se usan en casos muy específicos para ahorrar memoria con números pequeños. Raramente los usarás al empezar.
Nota: Kotlin también tiene versiones «Unsigned» (sin signo, es decir, solo positivos) como UInt o ULong marcados con una u (Ej: val puntos: UInt = 100u).
Números con decimales (coma flotante)
Double: Es el estándar de Kotlin para números con decimales. Tiene una precisión doble, es decir, admite muchísimos decimales. (Ej: val precio: Double = 19.99)
Float: Ocupa menos memoria pero es menos preciso. Para indicarle a Kotlin que quieres un Float y no un Double, debes añadir una f o F al final del número. (Ej: val temperatura: Float = 24.5f)
Booleanos (verdadero o falso)
Boolean: Solo puede tener dos valores: true (verdadero) o false (falso). Es la base de la lógica en programación (Ej: val estaEncendido: Boolean = true).
Caracteres y cadenas de texto
Char: Representa un único carácter (una sola letra, número o símbolo). Se escribe entre comillas simples' '. (Ej: val inicial: Char = 'J')
String: Representa una cadena de texto (muchos caracteres juntos). Se escribe entre comillas dobles" ". (Ej: val mensaje: String = "¡Hola, mundo!")
Declarar ahora, inicializar después
A veces sabes qué tipo de dato vas a guardar, pero aún no tienes el valor exacto. Kotlin te permite declarar una variable y asignarle su valor más tarde.
Eso sí, en estos casos es obligatorio especificar el tipo explícitamente, porque Kotlin no tiene un valor inicial del que deducirlo:
fun main() {
// Declaramos la variable especificando el tipo explícitamente, pero sin darle valor
val d: Int
// Más adelante en el código, la inicializamos
d = 3
println(d) // Imprime: 3
}
La seguridad de Kotlin frente a errores
¿Qué pasa si intentas imprimir la variable dantes de darle un valor? En otros lenguajes tu programa explotaría (el temido NullPointerException o imprimiría basura de la memoria). Kotlin no te deja hacerlo. El código directamente se pondrá en rojo y no compilará, mostrándote el error: «Variable ‘d’ must be initialized». ¡Un salvavidas enorme!
Ejercicios
Abre tu editor o el Kotlin Playground y pon a prueba lo que acabas de aprender.
El tipado explícito
Kotlin puede inferir los tipos, pero en este ejercicio queremos que seas tú quien los escriba. Modifica el siguiente código para añadir explícitamente (: Tipo) el tipo de dato correcto a cada variable:
fun main() {
val a = 1000
val b = "mensaje de registro"
val c = 3.14
val d = 100_000_000_000_000 // Fíjate, los guiones bajos sirven para leer mejor los números grandes
val e = false
val f = '\n' // Esto es un carácter especial que representa un "salto de línea"
}
El cofre del tesoro
Crea un programa que simule el oro de un jugador en un videojuego usando una variable mutable (var) llamada monedas:
El jugador empieza con 50 monedas.
Encuentra un cofre mágico y su oro se multiplica por 3. (Usa asignación compuesta *=).
Compra una espada que cuesta 80 monedas. (Usa -=).
Imprime el resultado final: "Tras la aventura, te quedan X monedas".
Detecta el error
El siguiente código tiene un problema y Kotlin se quejará si intentas ejecutarlo. Corrígelo para que funcione y se imprima la edad correctamente.
fun main() {
val edadUsuario: Int
println("La edad del usuario es $edadUsuario")
edadUsuario = 25
}
Cuidado con las divisiones
Si divides dos variables Int (ej: 10 / 3), Kotlin devuelve un número entero (3) y se come los decimales.
Crea dos variables llamadas dividendo (valor 10) y divisor (valor 3). Haz que sean de tipo Double explícitamente para que, al imprimirlas usando una plantilla de cadena, el resultado sea con decimales (3.3333333333333335).
Soluciones a los ejercicios
¡No mires hasta que no te hayas peleado un rato con el código!
El tipado explícito
fun main() {
val a: Int = 1000
val b: String = "mensaje de registro"
val c: Double = 3.14 // Al tener decimales y no tener 'f', es Double
val d: Long = 100_000_000_000_000 // Es demasiado grande para ser Int
val e: Boolean = false // Verdadero o falso
val f: Char = '\n' // Comillas simples indican que es un solo Char
}
El cofre del tesoro
fun main() {
var monedas = 50
monedas *= 3
monedas -= 80
println("Tras la aventura, te quedan $monedas monedas")
// Imprimirá 70
}
Detecta el error
fun main() {
val edadUsuario: Int
edadUsuario = 25 // ¡Había que inicializarla ANTES de leerla!
println("La edad del usuario es $edadUsuario")
}
Cuidado con las divisiones
fun main() {
// Para forzar que un número entero se trate como decimal, ponemos .0
val dividendo: Double = 10.0
val divisor: Double = 3.0
println("El resultado exacto es ${dividendo / divisor}")
}
Si estás empezando en el mundo del desarrollo (ya sea para Android o backend), Kotlin es uno de los lenguajes más modernos, limpios y seguros que puedes aprender hoy en día.
En esta unidad, vamos a dar los primeros pasos. Entenderemos cómo funciona la estructura básica de un programa, cómo almacenar información usando variables y cómo imprimir mensajes por pantalla de forma elegante. Al final, tendrás ejercicios prácticos para asentar lo aprendido.
El clásico «Hola mundo»
Por tradición, el primer programa que todo desarrollador escribe al aprender un lenguaje nuevo es el que imprime las palabras «¡Hola, mundo!» en la pantalla.
En Kotlin, se hace así de fácil:
fun main() {
println("¡Hola, mundo!")
// ¡Hola, mundo!
}
Analizando el código línea a línea:
fun: Es la palabra reservada (abreviatura de function) que usamos en Kotlin para declarar una función. Una función no es más que un bloque de código que realiza una tarea específica.
main(): No es una función cualquiera. Es el punto de entrada (entry point) de tu programa. Siempre que ejecutes una aplicación en Kotlin, el ordenador buscará esta función y empezará a ejecutar las instrucciones que haya dentro de ella.
{ } (Las llaves): Todo lo que esté dentro de las llaves es el «cuerpo» de la función, es decir, las instrucciones que se van a ejecutar.
println(): Es una función nativa de Kotlin que coge lo que le pongas entre paréntesis (los «argumentos») y lo imprime por la salida estándar (la consola de tu pantalla). Al terminar de imprimir, añade un salto de línea (por eso termina en ln, de line). Si usas print() (sin el ln), el texto se imprimirá, pero el siguiente mensaje aparecerá pegado justo a la derecha, en la misma línea.
El dato: ¿Te has dado cuenta de algo? ¡No hay punto y coma (;) al final de la línea! En lenguajes más antiguos como Java o C++, olvidar el punto y coma era un dolor de cabeza. Kotlin es un lenguaje moderno y no los necesita.
Variables: Guardando información en memoria
Cualquier programa informático necesita almacenar datos (nombres de usuario, puntuaciones de un juego, precios…). Para eso utilizamos las variables.
En Kotlin, tenemos dos formas principales de crear variables, y esto es muy importante:
Variables de solo lectura (inmutables) con val (de value).
Variables mutables con var (de variable).
Para asignarle un valor a una variable, simplemente usamos el operador de asignación =. Fíjate en este ejemplo:
fun main() {
val palomitas = 5 // Tenemos 5 cajas de palomitas
val perritos = 7 // Tenemos 7 perritos calientes
var clientes = 10 // Hay 10 clientes en la cola
// De repente, un par de clientes se cansan de esperar y se van de la cola
clientes = 8
println(clientes)
// Resultado en pantalla: 8
}
val vs var: ¿Cuál debería usar?
Como clientes se declaró con var, pudimos reasignarle un nuevo valor (8) más adelante en el programa. Sin embargo, si intentáramos hacer palomitas = 6, el compilador de Kotlin nos daría un error, porque palomitas es un val y no puede cambiar una vez se le ha dado un valor inicial.
La regla de oro en Kotlin: Utiliza siempre val por defecto. Usa var única y exclusivamente cuando sepas seguro que ese valor va a tener que cambiar en el futuro (como un contador, o la vida de un personaje en un juego). Esto hace que tu código sea mucho más seguro, predecible y libre de errores accidentales (los temidos bugs).
Plantillas de cadenas (String Templates): Texto inteligente
En programación, es súper común querer imprimir un texto que contenga el valor de nuestras variables. En otros lenguajes tendrías que «sumar» o concatenar trozos de texto con el símbolo +, lo cual queda feo y es fácil equivocarse.
Kotlin lo soluciona de forma magistral con las String Templates (plantillas de cadenas).
Una cadena de texto (String) se escribe siempre entre comillas dobles " ". Para inyectar el valor de una variable dentro de ese texto, solo tienes que poner el símbolo del dólar $ seguido del nombre de la variable.
Y si lo que quieres es hacer una operación matemática u otro código más complejo dentro del texto, lo metes entre llaves ${ }. Mira por ejemplo el siguiente código:
fun main() {
val clientes = 10
// Imprimiendo una variable directamente
println("Actualmente hay $clientes clientes esperando.")
// Salida: Actualmente hay 10 clientes esperando.
// Haciendo una operación matemática dentro del texto
println("Si llega uno más, habrá ${clientes + 1} clientes en total.")
// Salida: Si llega uno más, habrá 11 clientes en total.
}
La magia oculta: La inferencia de tipos
Si prestas atención, en ningún momento le hemos dicho a Kotlin que clientes es un número. Kotlin es muy listo: al ver que le asignamos un 10, él automáticamente infiere (deduce) que el tipo de dato es un número entero (Int).
Ejercicios
La programación solo se aprende tecleando. Aquí tienes varios ejercicios de menos a más dificultad. Intenta resolverlos por tu cuenta en un editor o en el Kotlin Playground antes de mirar las soluciones más abajo.
Presentando a Mary
Completa el siguiente código para que el programa imprima por consola el mensaje exacto: "Mary tiene 20 años". Debes usar obligatoriamente las variables dadas y las plantillas de cadenas ($).
fun main() {
val nombre = "Mary"
val edad = 20
// Escribe tu código debajo de esta línea:
}
Batería del móvil
Crea un pequeño programa que simule la batería de tu móvil.
Declara una variable llamada bateria que empiece al 100%. (Piensa si debe ser val o var).
Imprime el texto: "La batería inicial es del 100%".
Simula que juegas a un videojuego y la batería baja a 75. Actualiza el valor de la variable.
Vuelve a imprimir el texto: "Tras jugar, la batería es del 75%".
Calculadora de la compra inteligente
Declara dos variables inmutables: precioZapatillas con un valor de 50, y cantidadCajas con un valor de 2.
Utilizando un único println() y las llaves de expresión ${}, imprime el siguiente mensaje calculando el total sobre la marcha:
"Has comprado 2 pares de zapatillas. El precio total es de 100 euros."
¿print o println?
Imagina que quieres que la consola muestre exactamente esto en dos líneas:
Hola Mundo
¡Amo Kotlin!
Escribe el código usando tres instrucciones de impresión para conseguir esa salida exacta. Haz que la palabra «Hola» y «Mundo» se impriman en instrucciones separadas pero se queden en la misma línea.
Soluciones a los ejercicios
¡No hagas trampas! Solo mira esto si ya has intentado resolverlos.
Presentando a Mary
fun main() {
val nombre = "Mary"
val edad = 20
println("$nombre tiene $edad años")
}
Batería del móvil
fun main() {
// Usamos 'var' porque la batería va a cambiar a lo largo del tiempo
var bateria = 100
println("La batería inicial es del $bateria%")
bateria = 75
println("Tras jugar, la batería es del $bateria%")
}
Calculadora de la compra inteligente
fun main() {
val precioZapatillas = 50
val cantidadCajas = 2
// Usamos ${} para multiplicar variables dentro del mismo texto
println("Has comprado $cantidadCajas pares de zapatillas. El precio total es de ${precioZapatillas * cantidadCajas} euros.")
}
¿print o println?
fun main() {
print("Hola ") // Usa print, por lo que la siguiente palabra se pega a esta. (Fíjate en el espacio al final)
println("Mundo") // Se pega al 'Hola ', y luego hace un salto de línea por el 'ln'
println("¡Amo Kotlin!") // Se imprime en la nueva línea
}
HTML dispone de numerosos elementos para dar formato al texto que no abordamos en las unidades anteriores. Aunque las etiquetas que se describen en esta unidad son menos conocidas o de uso más específico, conocerlas resulta de gran utilidad para enriquecer nuestros documentos. Aprenderás a realizar el marcado semántico correcto de abreviaturas, citas y referencias, fragmentos de código informático, ecuaciones matemáticas y datos de contacto.
Abreviaturas
El elemento de abreviatura de HTML (<abbr>) representa una abreviatura o un acrónimo. A través del atributo opcional title, podemos proporcionar el significado desarrollado del término o una descripción legible para el usuario.
Por lo general, los navegadores presentan este texto mediante una etiqueta emergente (tooltip) que aparece automáticamente cuando se pasa el cursor del ratón sobre el elemento. Es importante tener en cuenta que, si se incluye el atributo title, este debe contener única y exclusivamente la descripción completa, sin añadir texto adicional.
A continuación, veamos algunos ejemplos prácticos en los que resulta adecuado el uso de abreviaturas o acrónimos:
Usamos HTML para estructurar nuestros documentos web.
Puedes utilizar CSS para dar estilo a tu HTML.
La NASA realiza un trabajo fascinante, sin duda.
El chiste de Ashok me hizo LOL muchísimo.
Veamos ahora qué código HTML debemos escribir para conseguir ese resultado:
<p>Usamos <abbr title="Lenguaje de Marcado de Hipertexto">HTML</abbr> para estructurar nuestros documentos web.</p>
<p>Puedes utilizar <abbr title="Hojas de Estilo en Cascada">CSS</abbr> para dar estilo a tu <abbr title="Lenguaje de Marcado de Hipertexto">HTML</abbr>.</p>
<p>La <abbr title="Administración Nacional de Aeronáutica y el Espacio">NASA</abbr> realiza un trabajo fascinante, sin duda.</p>
<p>El chiste de Ashok me hizo <abbr title="Reír a carcajadas">LOL</abbr> muchísimo.</p>
El objetivo principal de este elemento es aportar valor semántico y facilitar información adicional. Aunque todos los navegadores lo muestran como un elemento en línea (inline) de forma predeterminada, su estilo visual por defecto no es consistente y varía según el navegador (si bien esto siempre puede unificarse añadiendo reglas CSS).
Las diferencias de estilo más comunes son las siguientes:
Sin estilo visual: Algunos navegadores, como Internet Explorer, no le aplican ninguna apariencia distintiva, mostrándolo exactamente igual que si fuera un elemento <span>.
Subrayado: Navegadores como Opera o Firefox suelen añadir un subrayado de puntos al texto de la abreviatura para diferenciarlo.
Versalitas: Unos pocos navegadores van un paso más allá y, además del subrayado punteado, transforman el texto a versalitas (small caps).
Ejercicio propuesto: Ejemplo de uso de abreviaturas
Crea una página web utilizando el código del ejemplo anterior, y añade varios párrafos nuevos que contengan algunas abreviaturas y verifica el resultado en tu navegador. Recuerda incluir el resto de etiquetas básicas de HTML necesarias para la estructura del documento y no olvides validar tu código.
Ejercicio propuesto: Abreviaturas para chatear
El mundo del correo electrónico, los mensajes de texto y la mensajería instantánea han dado lugar a toda una serie de acrónimos y abreviaturas que permiten a los usuarios redactar sus mensajes con mayor rapidez. En este ejercicio deberás crear un par de listas. La primera incluirá la relación de abreviaturas que se enumeran a continuación (puedes añadir otras que conozcas). La segunda lista deberá contener al menos veinte frases que ilustren cómo se utilizan dichas abreviaturas en una conversación de chat.
Además, utiliza encabezados <h1> y <h2> para añadir títulos a las listas y proporcionar así un texto descriptivo previo.
Por ejemplo, la primera lista podría mostrar las abreviaturas de la siguiente manera:
bn – Bien
bss – Besos
finde – Fin de semana
hl – Hola
kdms – Quedamos
npi – Ni puñetera idea
ns / nc – No sabe / No contesta
pf / xfa – Por favor
pq / xq – Por qué
q tal – Qué tal
rt – Retuit (compartido / de acuerdo)
salu2 – Saludos
tb – También
tqm – Te quiero mucho
tpc – Tampoco
vdd – Verdad
xo – Pero
+o- – Más o menos
La segunda lista deberá incluir al menos veinte frases en las que se empleen dichas abreviaturas. Por ejemplo:
Espero que te encuentres bn, hace tiempo que no hablamos.
Me tengo que ir corriendo, hablamos luego. ¡bss!
¿Tenéis algún plan interesante para este finde?
hl, ¿te ha llegado ya el paquete que te envié?
Si os parece bien, kdms a las 20:00 en la plaza mayor.
No me preguntes cómo arreglarlo porque no tengo npi.
Le he preguntado si vendrá a la cena de empresa, pero de momento ns / nc.
…
Puedes utilizar el siguiente código como ejemplo para saber qué etiquetas debes utilizar para obtener ambas listas:
<h1>Algunas abreviaturas que uso para chatear</h1>
<h2>Las abreviaturas</h2>
<ul>
<li>bn - Bien</li>
<li>bss - Besos</li>
<li>finde - Fin de semana</li>
<li>hl - Hola</li>
<li>kdms - Quedamos</li>
<li>npi - Ni puñetera idea</li>
<li>ns / nc - No sabe / No contesta</li>
<li>...</li>
</ul>
<h2>Algunos ejemplos</h2>
<ul>
<li>Espero que te encuentres <abbr title="Bien">bn</abbr>, hace tiempo que no hablamos.</li>
<li>Me tengo que ir corriendo, hablamos luego. ¡<abbr title="Besos">bss</abbr>!</li>
<li>¿Tenéis algún plan interesante para este <abbr title="Fin de semana">finde</abbr>?</li>
<li><abbr title="Hola">hl</abbr>, ¿te ha llegado ya el paquete que te envié?</li>
<li>Si os parece bien, <abbr title="Quedamos">kdms</abbr> a las 20:00 en la plaza mayor.</li>
<li>No me preguntes cómo arreglarlo porque no tengo <abbr title="Ni puñetera idea">npi</abbr>.</li>
<li>Le he preguntado si vendrá a la cena de empresa, pero de momento <abbr title="No sabe / No contesta">ns / nc</abbr>.</li>
<li>...</li>
</ul>
Citas
El elemento <q>
El elemento HTML <q> indica que el texto que encierra es una cita corta en línea (inline). La gran mayoría de los navegadores modernos interpretan este elemento envolviendo automáticamente el texto entre comillas.
Asimismo, puedes utilizar el atributo cite para especificar una URL que señale el documento de origen o la fuente de la información citada, aunque es importante tener en cuenta que, por defecto, el navegador no muestra esta URL al usuario de forma visible.
A continuación mostramos un par de ejemplos analizando primero el resultado visual (en la mayoría de los casos la única diferencia es que las comillas aparecen automáticamente para acotar la cita):
Cuando Dave le pide a HAL que abra las compuertas de la cápsula, HAL responde: "Lo siento, Dave. Me temo que no puedo hacerlo".
Según el sitio web de Mozilla,
"Firefox 1.0 se lanzó en 2004 y se convirtió en un gran éxito".
Y ahora el código fuente correspondiente:
<p>
Cuando Dave le pide a HAL que abra las compuertas de la cápsula, HAL responde: <q cite="https://www.imdb.com/es-es/title/tt0062622/">"Lo siento, Dave. Me temo que no puedo hacerlo"</q>.
</p>
<p>
Según el sitio web de Mozilla,
<q cite="https://www.mozilla.org/en-US/about/history/details/">"Firefox 1.0 se lanzó en 2004 y se convirtió en un gran éxito"</q>.
</p>
Importante: El elemento <q> está diseñado para citas breves que no requieren saltos de párrafo. Para citas extensas, utiliza el elemento <blockquote>.
Ejercicio propuesto: Citas en línea
Crea una página web utilizando el código del ejemplo anterior, y luego añade varios párrafos que contenga citas de tu elección y verifica el resultado en el navegador. Recuerda incluir el resto de etiquetas básicas de HTML para estructurar el documento y no olvides validar tu código.
El elemento HTML <blockquote> (o elemento de cita en bloque) indica que el texto que encierra constituye una cita extensa. Por lo general, los navegadores representan este elemento visualmente aplicando una sangría o indentación al texto.
Es posible especificar la URL de la fuente de la cita mediante el atributo cite, pero para indicar la referencia de la fuente en formato de texto visible se emplea el elemento completo <cite>. Por ejemplo:
Vuestro trabajo va a llenar gran parte de vuestra vida, y la única forma de estar realmente satisfecho es hacer lo que creéis que es un gran trabajo. Y la única forma de hacer un gran trabajo es amar lo que hacéis. Si aún no lo habéis encontrado, seguid buscando. No os conforméis. Como con todo lo que tiene que ver con el corazón, lo sabréis cuando lo encontréis.
Steve Jobs
<blockquote cite="https://www.brainyquote.com/quotes/steve_jobs_416859">
Vuestro trabajo va a llenar gran parte de vuestra vida, y la única forma de estar realmente satisfecho es hacer lo que creéis que es un gran trabajo. Y la única forma de hacer un gran trabajo es amar lo que hacéis. Si aún no lo habéis encontrado, seguid buscando. No os conforméis. Como con todo lo que tiene que ver con el corazón, lo sabréis cuando lo encontréis.
<a href="https://www.brainyquote.com/quotes/steve_jobs_416859"><cite>Steve Jobs</cite></a>
</blockquote>
Ejercicio propuesto: Citas célebres
Crea una página web que recopile al menos veinte de las citas más famosas de la historia. Puedes encontrar muchas de ellas en sitios como «https://www.proverbia.net«, «https://www.mundifrases.com/«, o también puedes utilizar cualquier otra fuente que prefieras.
Debes utilizar el elemento <blockquote> para envolver la cita completa, y el elemento <cite> dentro de cada cita para indicar el nombre del autor, tal como se muestra en el ejemplo anterior y en los siguientes:
La mayor gloria de vivir no radica en no caer nunca, sino en levantarnos cada vez que caemos.
Nelson Mandela
La manera de empezar es dejar de hablar y comenzar a actuar.
Walt Disney
Vuestro tiempo es limitado, así que no lo malgastéis viviendo la vida de otro.
No os dejéis atrapar por el dogma, que es vivir según los resultados del pensamiento de otros.
No dejéis que el ruido de las opiniones de los demás ahogue vuestra propia voz interior.
Y lo más importante, tened el coraje de seguir a vuestro corazón y vuestra intuición.
Steve Jobs
Si la vida fuera predecible, dejaría de ser vida y no tendría sabor.
Eleanor Roosevelt
Si miras lo que tienes en la vida, siempre tendrás más.
Si miras lo que no tienes en la vida, nunca tendrás suficiente.
Oprah Winfrey
…
Combinando los elementos <q>, <blockquote> y <cite>
El elemento de cita HTML (<cite>) se utiliza para referenciar el título de una obra creativa citada (como un libro, un artículo, un ensayo, una película, etc.). Según las convenciones de metadatos más apropiadas para el contexto, esta referencia puede presentarse de forma abreviada. Veamos un ejemplo práctico en el que resulta útil combinar estos tres elementos para crear una mejor estructura semántica:
Hola y bienvenidos a mi página de motivación. Como dice el sitio
Citas de Confucio
:
No importa lo lento que vayas mientras no te detengas.
También me encanta el concepto del pensamiento positivo y la necesidad de
«mantener tus pensamientos positivos»
(como se menciona en
Citas Positivas
).
Y ahora echemos un vistazo al código fuente que debemos escribir para obtener ese resultado:
<p>
Hola y bienvenidos a mi página de motivación. Como dice el sitio
<a href="https://proverbia.net/autor/frases-de-confucio">
<cite>Citas de Confucio</cite>
</a>:
</p>
<blockquote cite="https://www.proverbia.net/citasautor/confucio">
No importa lo lento que vayas mientras no te detengas.
</blockquote>
<p>
También me encanta el concepto del pensamiento positivo y la necesidad de
<q cite="https://www.mundifrases.com/tema/pensamiento-positivo/">
mantener tus pensamientos positivos
</q>
(como se menciona en
<a href="https://psicologiaymente.com/reflexiones/frases-positivas">
<cite>Citas Positivas</cite>
</a>).
</p>
Ejercicio propuesto: Ejemplo de citas completas
Crea una página web utilizando primero el código del ejemplo anterior y verifica el resultado en tu navegador. A continuación añade otro bloque similar combinando las tres etiquetas mencionadas, y vuelve a comprobar el resultado en el navegador.
No olvides incluir el resto de las etiquetas básicas de HTML (incluyendo títulos <h1> y <h2>) y valida tu código para asegurar que es correcto.
Representación de código informático
HTML pone a nuestra disposición una serie de elementos específicos para el marcado de código informático:
<code>: Se utiliza para marcar fragmentos genéricos de código informático.
<pre>: Se usa para preservar los espacios en blanco (generalmente empleado para bloques de código). Si utilizas sangría o espacios en blanco adicionales dentro del texto, los navegadores los ignorarán por defecto y no se verán reflejados en la página renderizada. No obstante, como ya explicamos en una unidad anterior, si envuelves el texto entre etiquetas <pre></pre>, los espacios en blanco se mostrarán idénticos a como aparecen en tu editor de texto.
<var>: Sirve para marcar específicamente nombres de variables.
<kbd>: Se utiliza para marcar la entrada de teclado (u otros tipos de entrada de datos) introducida en el ordenador.
<samp>: Se emplea para marcar la salida (output) de un programa informático.
El elemento <code>
El elemento HTML <code> muestra su contenido con un estilo visual diseñado para indicar que el texto es un fragmento breve de código informático. Por defecto, los navegadores muestran el texto de este elemento utilizando la fuente monoespaciada predeterminada del sistema.
Veamos un par de ejemplos:
El método push() añade uno o más elementos al final de un array y devuelve la nueva longitud del mismo.
La función selectAll() resalta todo el texto en el campo de entrada para que el usuario pueda, por ejemplo, copiar o eliminar el texto.
Y este sería el código HTML del ejemplo anterior:
<p>
El método <code>push()</code> añade uno o más elementos al final de un array y devuelve la nueva longitud del mismo.
</p>
<p>
La función <code>selectAll()</code> resalta todo el texto en el campo de entrada para que el usuario pueda, por ejemplo, copiar o eliminar el texto.
</p>
Ejercicio propuesto: Código en línea
Crea una página web con el código del ejemplo anterior, luego añade algunos ejemplos más, y verifica los resultados en tu navegador.
No olvides incluir el resto de las etiquetas básicas de HTML y validar tu código.
Los elementos <pre> + <code>
El elemento <code> por sí solo representa únicamente una instrucción o una única línea de código. Para representar múltiples líneas de código (un bloque), debemos envolver el elemento <code> dentro de un elemento <pre>. De esta forma, respetaremos los espacios y saltos de línea. Por ejemplo:
if (a > b) {
console.log('¡Hola!'); // Ejemplo de código en el lenguaje JavaScript
}
Código HTML del ejemplo:
<pre><code>
if (a > b) {
console.log('¡Hola!'); // Ejemplo de código en el lenguaje JavaScript
}
</code></pre>
Ejercicio propuesto: Bloque de código
Crea una página web con el código del ejemplo anterior, añade algunos bloque adicionales con cualquier fragmento de código de cualquier lenguaje y comprueba los resultados en tu navegador.
No olvides incluir el resto de las etiquetas básicas de HTML y validar tu código
El elemento <var>
El elemento de variable HTML (<var>) representa el nombre de una variable dentro de una expresión matemática o en un contexto de programación. Por lo general, se presenta visualmente utilizando una versión en cursiva de la tipografía actual, aunque este comportamiento depende de cada navegador.
Por ejemplo:
Una ecuación simple: x = y + 2
El volumen de una caja es l × w × h, donde l
representa la longitud, w la anchura y h la
altura de la caja.
Las variables minSpeed y maxSpeed controlan la velocidad mínima y máxima
del aparato en revoluciones por minuto (RPM).
Código HTML del ejemplo:
<p>
Una ecuación simple: <var>x</var> = <var>y</var> + 2
</p>
<p>
El volumen de una caja es <var>l</var> × <var>w</var> × <var>h</var>, donde <var>l</var>
representa la longitud, <var>w</var> la anchura y <var>h</var> la
altura de la caja.
</p>
<p>
Las variables <var>minSpeed</var> y <var>maxSpeed</var> controlan la velocidad mínima y máxima
del aparato en revoluciones por minuto (RPM).
</p>
Ejercicio propuesto: Ecuaciones y variables
Crea una página web con el código del ejemplo anterior, y añade un par de párrafos adicionales con cualquier ecuación que desees y comprueba los resultados en tu navegador.
No olvides incluir el resto de las etiquetas básicas de HTML y validar tu código
El elemento <kbd>
El elemento HTML de entrada de teclado (<kbd>) representa un fragmento de texto en línea que denota una entrada del usuario, ya sea a través de un teclado convencional, comandos de voz o cualquier otro dispositivo de entrada de texto.
Por convención, el navegador renderiza el contenido de un elemento <kbd> utilizando su fuente monoespaciada predeterminada para que destaque visualmente. Veamos algunos ejemplos:
Por favor, pulsa Ctrl + Mayús + R para recargar una página de MDN.
Usa el comando help micomando para ver la documentación del comando «micomando».
Puedes crear un nuevo documento utilizando el atajo de teclado Ctrl + N.
<p>
Por favor, pulsa <kbd>Ctrl</kbd> + <kbd>Mayús</kbd> + <kbd>R</kbd> para recargar una página de MDN.
</p>
<p>
Usa el comando <kbd>help micomando</kbd> para ver la documentación del comando "micomando".
</p>
<p>
Puedes crear un nuevo documento utilizando el atajo de teclado <kbd>Ctrl</kbd> + <kbd>N</kbd>.
</p>
Ejercicio propuesto: Atajos de teclado
Crea una página web con el código del ejemplo anterior, añade un par de párrafos con cualquier atajo de teclado que conozcas y comprueba los resultados en tu navegador.
No olvides incluir el resto de las etiquetas básicas de HTML y validar tu código.
El elemento <samp>
El elemento de muestra HTML (<samp>) se utiliza para encerrar texto en línea que representa la salida (output) de muestra o el resultado devuelto por un programa informático. Su contenido se muestra habitualmente utilizando la fuente monoespaciada predeterminada del navegador (como Courier o Lucida Console) para diferenciarlo del texto normal.
Veamos un par de ejemplos:
Estaba intentando arrancar mi ordenador, pero me salió este mensaje tan irónico:
Teclado no encontrado Pulse F1 para continuar
Cuando el proceso finalice, la utilidad mostrará el texto Escaneo completado. Se han encontrado N resultados. Entonces podrás proceder al siguiente paso.
Código HTML del ejemplo:
<p>Estaba intentando arrancar mi ordenador, pero me salió este mensaje tan irónico:</p>
<p>
<samp>Teclado no encontrado <br>Pulse F1 para continuar</samp>
</p>
<p>...</p>
<p>
Cuando el proceso finalice, la utilidad mostrará el texto <samp>Escaneo completado. Se han encontrado <em>N</em> resultados.</samp> Entonces podrás proceder al siguiente paso.
</p>
Ejercicio propuesto: Salida de muestra
Crea una página web con el código del ejemplo anterior, junto con un par de párrafos más, y comprueba los resultados en tu navegador.
No olvides incluir el resto de las etiquetas básicas de HTML y validar tu código para asegurar que es correcto
Un ejemplo completo
Veamos ahora un ejemplo completo que combina todos estos elementos (<code>, <pre>, <var>, <kbd>, <samp>) para ver cómo interactúan entre sí.
A continuación mostramos el resultado visual:
var para = document.querySelector('p');
para.onclick = function() {
alert('¡Ay, deja de pincharme!');
}
No deberías utilizar elementos de presentación como <font> y <center>.
En el ejemplo de JavaScript anterior, para representa un elemento de párrafo.
Selecciona todo el texto con Ctrl/Cmd + A.
$ ping mozilla.orgPING mozilla.org (63.245.215.20): 56 data bytes
64 bytes from 63.245.215.20: icmp_seq=0 ttl=40 time=158.233 ms
Y aquí el código fuente correspondiente:
<pre><code>var para = document.querySelector('p');
para.onclick = function() {
alert('¡Ay, deja de pincharme!');
}</code></pre>
<p>No deberías utilizar elementos de presentación como <code><font></code> y <code><center></code>.</p>
<p>En el ejemplo de JavaScript anterior, <var>para</var> representa un elemento de párrafo.</p>
<p>Selecciona todo el texto con <kbd>Ctrl</kbd>/<kbd>Cmd</kbd> + <kbd>A</kbd>.</p>
<pre>$ <kbd>ping mozilla.org</kbd>
<samp>PING mozilla.org (63.245.215.20): 56 data bytes
64 bytes from 63.245.215.20: icmp_seq=0 ttl=40 time=158.233 ms</samp></pre>
Ejercicio propuesto: Código, atajos y salida
Crea una página web con el código del ejemplo anterior, junto con algún bloque <pre>...</pre> adicional, y comprueba los resultados en tu navegador.
No olvides incluir el resto de las etiquetas básicas de HTML y validar tu código .
Ejercicio propuesto: Comandos de Linux
Crea una página web que muestre una tabla con algunos de los comandos de Linux más importantes y su descripción de uso, siguiendo aproximadamente el modelo de la tabla que se muestra a continuación.
Debes cumplir los siguientes requisitos semánticos: 1. Utiliza la etiqueta <code> para los comandos en la columna de la izquierda. 2. Utiliza la etiqueta <kbd> para los ejemplos de entrada del usuario (user’s input) dentro de las descripciones. 3. Recuerda que la tabla debe tener encabezados (<th>) y un título o leyenda (<caption>).
Comandos de Linux
Comandos
Descripción
passwd
Cambia tu contraseña de usuario:
1. Escribe tu antigua contraseña
2. Introduce la nueva contraseña
3. Confirma la nueva contraseña
~
Directorio personal del usuario (Home)
(atajo para: /home/usuario)
ls
Lista las carpetas y archivos del directorio actual
mkdir
Crea un nuevo directorio dentro del actual: mkdir nuevodir
cd
Cambia de directorio: cd test (ir a un directorio llamado ‘test’) cd .. (ir al directorio padre/superior) cd ~ (ir al directorio personal)
rm
Elimina el archivo o directorio especificado: rm nombrearchivo (elimina un solo archivo) rm *.txt (elimina TODOS los archivos .txt del directorio actual) rm -r nombredir (elimina el directorio y sus archivos)
¡Por favor, ten cuidado al usar la opción -f!
rmdir
Elimina el directorio VACÍO especificado rmdir nombredir
pwd
Imprime la ruta absoluta actual
man
Muestra la página de manual del comando especificado: man ls (muestra la ayuda de ls)
vi x.sh
VI es un editor de texto. Si x.sh no existe, vi crea un nuevo archivo llamado
x.sh y lo abre;
de lo contrario, simplemente abre el archivo existente.
less archivotexto
less es un paginador de texto. Abre (solo lectura) el archivo archivotexto. Puedes usar las flechas arriba y abajo para desplazarte por el texto; comparte muchos comandos con VI.
chmod
Cambia los permisos POSIX de un archivo o directorio. Permite proteger archivos contra accesos no deseados: r : permiso de lectura w : permiso de escritura x : permiso de ejecución
chmod +x archivo.sh (permite la ejecución) chmod -w archivo.sh (deniega la escritura)
chown
Cambia el propietario de un archivo o directorio: chown usuario archivo.sh
top
Muestra los procesos en ejecución actualmente
cat
Imprime el contenido de un archivo en pantalla
grep
Filtra el archivo de texto especificado y muestra las líneas que contienen el patrón: grep patron archivo.sh
También puedes usar tuberías (pipes) con la salida de otro comando: cat archivo.sh | grep home cat archivo.sh | grep "home page"
Marcado de datos de contacto
HTML proporciona un elemento específico para marcar semánticamente la información de contacto: <address>. Este elemento es muy versátil y puede utilizarse en diversos contextos; por ejemplo, para facilitar los datos de contacto de una empresa en el encabezado o pie de página de un sitio web, o para indicar quién es el autor de un artículo o una publicación concreta.
Su funcionamiento es sencillo: basta con envolver los detalles de contacto dentro de esta etiqueta. Veamos un ejemplo básico:
<address>
<p>Fernando Ruiz, IES San Vicente, España</p>
</address>
No obstante, el contenido del elemento <address> puede albergar un marcado mucho más complejo. De hecho, la información suministrada puede adoptar la forma que mejor se ajuste al contexto, incluyendo cualquier dato necesario: dirección física, URL, correo electrónico, número de teléfono, redes sociales, coordenadas geográficas, etc. .
Regla importante: Debes tener en cuenta que siempre hay que incluir, como mínimo, el nombre de la persona, grupo u organización a la que hacen referencia dichos datos de contacto.
También es correcto utilizar este elemento para referenciar información de contacto que se encuentra en otra página o enlace, como en el siguiente caso:
<address>
Puedes contactar con el autor en <a href="http://www.midominio.com/contacto">www.midominio.com</a>.<br>
Si encuentras algún error, por favor <a href="mailto:[email protected]">contacta con el webmaster</a>.<br>
También puedes visitarnos en:<br>
Fundación Mozilla<br>
331 E Evelyn Ave<br>
Mountain View, CA 94041<br>
EE. UU.
</address>
Ejercicio propuesto: Información de contacto
Crea una página web utilizando el código de los ejemplos anteriores y verifica el resultado en tu navegador.
No olvides incluir el resto de las etiquetas básicas de HTML y validar tu código para asegurar que la estructura es correcta .
El elemento <figure>
El elemento HTML <figure> (Figura con leyenda opcional) representa contenido independiente (self-contained content), el cual puede ir acompañado de un título o leyenda opcional especificado mediante el elemento <figcaption>.
La figura, su leyenda y su contenido se referencian semánticamente como una única unidad.
Figuras con imágenes
Este es el uso más común: asociar imágenes con sus pies de foto. Por ejemplo:
Crea una página web utilizando el código del ejemplo anterior, añade un par de figuras (<figure>) nuevas con imágenes y elige una leyenda adecuada (<figcaption>) para cada una. Finalmente, comprueba los resultados en tu navegador. No olvides incluir el resto de las etiquetas básicas de HTML y validar tu código.
Puedes utilizar cualquier imagen que te guste; por ejemplo, las del servicio «https://picsum.photos/images«, tal como hicimos en ejercicios de la unidad anterior.
Figuras con poemas
El elemento <figure> no sirve solo para imágenes; también es excelente para enmarcar poemas o fragmentos literarios, como por ejemplo:
Caminante, son tus huellas
el camino y nada más;
Caminante, no hay camino,
se hace camino al andar.
Al andar se hace el camino,
y al volver la vista atrás
se ve la senda que nunca
se ha de volver a pisar.
Proverbios y cantares, de Antonio Machado
Código HTML del ejemplo:
<figure>
<p>
Caminante, son tus huellas<br>
el camino y nada más;<br>
Caminante, no hay camino,<br>
se hace camino al andar.<br>
Al andar se hace el camino,<br>
y al volver la vista atrás<br>
se ve la senda que nunca<br>
se ha de volver a pisar.
</p>
<figcaption>
<cite>Proverbios y cantares</cite>, de Antonio Machado
</figcaption>
</figure>
Ejercicio propuesto: Poemas
Crea una página web con el código del ejemplo anterior (el de Machado), añade una nueva figura con otro poema que te guste (quizás de Lorca, Bécquer o Neruda) y comprueba los resultados en tu navegador.
No olvides incluir el resto de las etiquetas básicas de HTML y validar tu código .
Figuras con código
El elemento <figure> es ideal para mostrar fragmentos de código que tienen un título descriptivo o que funcionan como ejemplos independientes.
Crea una página web con el código del ejemplo anterior, junto con otro más, y comprueba los resultados en tu navegador.
No olvides incluir el resto de las etiquetas básicas de HTML y validar tu código .
Figuras con citas
Como vimos anteriormente, podemos usar <blockquote> por sí solo, pero si envolvemos la cita dentro de un elemento <figure>, podemos usar <figcaption> para indicar el autor o la fuente con mayor implicación semánticamente. Por ejemplo:
Edsger Dijkstra:
Si depurar es el proceso de eliminar errores de software,
entonces programar debe ser el proceso de introducirlos.
Código HTML del ejemplo:
<figure>
<figcaption><cite>Edsger Dijkstra:</cite></figcaption>
<blockquote>
Si depurar es el proceso de eliminar errores de software,
entonces programar debe ser el proceso de introducirlos.
</blockquote>
</figure>
Ejercicio propuesto: Citas famosas (versión con figuras)
Crea una página web con el código del ejemplo anterior y añade algunas citas famosas más utilizando este mismo formato (<figure> + <figcaption> + <blockquote>) para mostrar al menos diez citas.
Finalmente, comprueba los resultados en tu navegador. No olvides incluir el resto de las etiquetas básicas de HTML y validar tu código.
En esta unidad crearemos una aplicación con una galería interactiva de botones de audio, diseñada para reproducir sonidos de Halloween y Navidad. La interfaz está organizada en dos tablas temáticas: una para Halloween y otra para Navidad, cada una con imágenes representativas que, al hacer clic, activan la reproducción de un sonido específico.
Imágenes y sonidos
A continuación se muestran posibles imágenes y audios que puedes usar. Además, puedes hacer clic en estos enlaces para descargarte un zip con todas las imágenes y todos los sonidos.
Halloween
Navidad
Fichero «index.html»
El archivo index.html define la estructura básica de la aplicación, que es una galería de botones de audio con imágenes interactivas. A continuación explicamos cada parte del archivo.
Cabecera (<head>)
El código que se encuentra en esta primera sección del archivo se encarga de lo siguiente:
Define el título de la página («Instant buttons»).
Incluye enlaces a fuentes personalizadas de Google Fonts:
Creepster: utilizada para el tema de Halloween.
Mountains of Christmas: utilizada para el tema de Navidad.
Vincula la hoja de estilos style.css, donde están los estilos para el fondo, las fuentes, y los efectos visuales de las imágenes.
Dentro del cuerpo, se encuentran dos tablas temáticas: una de Halloween y otra de Navidad.
Tabla de Halloween
Utiliza la clase halloween para aplicar estilos específicos desde style.css, como el color rojo y la fuente Creepster.
Cada celda (<td>) contiene una imagen y tiene un evento onclick que ejecuta la función play con dos parámetros: el nombre del archivo de sonido y el volumen de reproducción.
Los archivos de imagen se encuentran en una carpeta llamada img y están nombrados de forma consecutiva para cada botón (por ejemplo, halloween1.webp, halloween2.webp, etc.).
Sigue la misma estructura que la tabla de Halloween, pero está estilizada con la clase christmas, que aplica un color azul y la fuente Mountains of Christmas.
Las imágenes de Navidad también están organizadas en una cuadrícula de tres filas y tres columnas, cada una con un archivo de audio distinto.
Antes de cerrar el elemento <body> de nuestra página web, deberemos incluir un elemento <audio> que utilizaremos para reproducir los sonidos, y también deberemos enlazar el fichero con el código JavaScript:
Elemento <audio>: Este elemento, con el id="player", se usa para reproducir los archivos de sonido. Al hacer clic en cada imagen, la función JavaScript play modifica su fuente (src) y volumen, y luego reproduce el audio seleccionado.
JavaScript: Al final del archivo se carga el script script.js, que contiene la función play para controlar la reproducción de audio cuando se hace clic en una imagen.
En resumen…
El archivo index.html estructura la página, definiendo tablas temáticas interactivas para reproducir sonidos festivos de Halloween y Navidad mediante el uso de JavaScript y estilos en CSS para mejorar la experiencia visual y sonora.
El archivo script.js es un código JavaScript sencillo que controla la reproducción de sonidos al hacer clic en las imágenes de la galería. A continuación, explicamos la función principal de este archivo.
Fichero «script.js»
Nuestra aplicación de instant buttons utiliza sólo una sencilla función javascript para reproducir los audios con ajuste de volumen incluido. A continuación se muestra todo el código necesario agrupado en la función play:
function play(soundName, soundVolume) {
// Obtener el elemento de audio
const player = document.getElementById("player");
// Cambiar el archivo de audio a reproducir
player.src = `audio/${soundName}.mp3`;
// Cambiar el volumen del audio
player.volume = soundVolume;
// Reproducir el audio
player.play();
}
Explicación detallada de la función play
Esta función play recibe dos parámetros, soundName y soundVolume, y se ejecuta cada vez que se hace clic en una de las imágenes en el archivo index.html. La función realiza los siguientes pasos:
Obtener el elemento de audio:
const player = document.getElementById("player");
Utiliza document.getElementById("player") para obtener el elemento de audio <audio id="player"> en el archivo HTML. Este elemento de audio es el que realmente reproduce los sonidos.
Cambiar el archivo de audio:
player.src = `audio/${soundName}.mp3`;
Modifica la propiedad src del elemento player para cambiar el archivo de audio que se va a reproducir. La función construye la ruta del archivo de audio usando el nombre del archivo pasado como parámetro soundName (por ejemplo, halloween1, christmas2, etc.). Así, si soundName es halloween1, la función buscará y cargará el archivo audio/halloween1.mp3.
Ajustar el volumen:
player.volume = soundVolume;
Cambia el volumen de reproducción del audio estableciendo la propiedad volume del elemento player. Este valor se toma del parámetro soundVolume, que es un número entre 0 (silencio) y 1 (volumen máximo). Por ejemplo, algunos sonidos tienen un volumen de 0.7 y otros de 1.0 en función de la experiencia que se quiera dar al usuario.
Reproducir el sonido:
player.play();
Finalmente, llama al método play() del elemento player para iniciar la reproducción del archivo de audio con el archivo y volumen especificados.
En resumen…
La función play es un controlador de reproducción de sonido que:
Cambia el archivo de audio a reproducir.
Ajusta el volumen de la reproducción.
Inicia la reproducción del archivo de audio.
Esta función permite que, al hacer clic en las imágenes de la galería, cada imagen reproduzca un sonido específico asociado a la festividad (Halloween o Navidad) con el volumen predefinido en la función onclick del HTML.
Fichero «style.css»
El archivo style.css contiene los estilos visuales de la aplicación, desde el fondo animado hasta los efectos visuales para cada imagen y tabla temática. A continuación, explicamos cada sección del código CSS.
Gradiente de colores: El fondo de la página es un gradiente lineal que pasa por varios tonos oscuros y fríos (negro, azul oscuro, azul brillante y morado). Esto crea un ambiente visual similar a una aurora boreal.
Tamaño del fondo: background-size: 200% 100%; hace que el gradiente se duplique en ancho, lo que permite que el fondo se mueva de lado a lado.
Animación: animation: aurora 2.5s infinite alternate; activa una animación de ida y vuelta cada 2.5 segundos, creando el efecto de movimiento en el fondo.
Animación aurora: Define una transición que mueve el gradiente de izquierda a derecha en el 100% del ancho, y luego vuelve al inicio, lo que da el efecto de aurora en movimiento.
Ancho de las imágenes: width: 100% asegura que las imágenes ocupen todo el ancho de la celda. max-width: 250px limita el tamaño máximo de las imágenes en pantallas grandes.
Transición suave: transition: 0.5s ease aplica una transición suave al hacer clic en las imágenes.
Efecto al hacer clic (:active): Cuando una imagen es presionada, se agranda un 50% (transform: scale(1.5)), se oscurece ligeramente (brightness(0.75)) y aumenta el contraste (contrast(1.25)), además de aplicar una sombra negra para resaltar el efecto de interacción.
Estilos para las tablas de Halloween y Navidad
Cada tabla tiene estilos específicos que incluyen una fuente, color y sombra para dar un ambiente acorde a la festividad.
Fuente: Utiliza Mountains of Christmas, que tiene un estilo festivo.
Color: El color del texto es azul (color: blue;).
Sombra de texto: Usa sombras suaves en azul claro y blanco (text-shadow: 2px 2px 5px #00aaff, -2px -2px 5px #ffffff;) para dar un efecto festivo de brillo.
Estilos generales para las tablas
table {
margin: auto;
}
Centrado de las tablas: La propiedad margin: auto; centra las tablas horizontalmente en la página.
En resumen…
Este archivo CSS define la estética de la aplicación:
Un fondo animado tipo aurora boreal.
Efectos interactivos para las imágenes de los botones.
Estilos específicos para cada tabla (Halloween y Navidad) con colores y fuentes temáticas.
Estos estilos ayudan a crear una experiencia visual inmersiva y coherente con cada festividad.
Ejercicios propuestos
Cambiar la orientación de la animación de fondo
Prueba a cambiar la orientación de fondo para que el efecto de aurora boreal se produzca con un movimiento de arriba hacia abajo y viceversa. Para ello basta con que modifiques el ángulo del gradiente a 180 grados, el tamaño del fondo al doble de alto, y el porcentaje de la animación en el eje Y de 0% a 100%:
/* Fondo con gradiente animado vertical tipo aurora */
body {
/* Cambiamos el ángulo del gradiente a 180 grados para que vaya de arriba hacia abajo */
background: linear-gradient(180deg, #1a1a1a, #003c5a, #0086c9, #9001d7);
/* Ajustamos el tamaño del fondo para que solo se duplique en altura */
background-size: 100% 200%;
/* Mantiene la misma animación */
animation: aurora 2.5s infinite alternate;
}
/* Animación de gradiente tipo aurora en vertical */
@keyframes aurora {
/* Fijamos la posición horizontal en 50% y animamos solo la posición vertical */
0% { background-position: 50% 0%; }
100% { background-position: 50% 100%; }
}
Animación de fondo radial
Prueba a cambiar la orientación de fondo para que el efecto de aurora boreal sea de tipo radial con movimiento diagonal. Para ello basta con que definas el gradiente con radial-gradient(circle, ...), y luego dupliques el tamaño del fondo al doble de ancho y de alto, y en último lugar cambies los porcentajes de la animación en ambos ejes de 0% a 100%:
/* Fondo con gradiente animado tipo aurora */
body {
/* Cambiamos a un gradiente radial para un efecto más llamativo */
background: radial-gradient(circle, #1a1a1a, #003c5a, #0086c9, #9001d7);
/* Ajustamos el tamaño del gradiente para que cubra más área */
background-size: 200% 200%;
/* Mantiene la misma animación */
animation: aurora 2.5s infinite alternate;
}
/* Animación de gradiente tipo aurora */
@keyframes aurora {
/* Modificamos la posición inicial y final para adaptarla al gradiente radial */
0% { background-position: 0% 0%; }
100% { background-position: 100% 100%; }
}
Diferentes colores de fondo
Prueba a cambiar los colores de la animación de fondo. Para ello solo debes cambiar los colores de la propiedad background dentro del selector body. Por ejemplo:
/* Fondo con gradiente animado tipo aurora de Halloween */
body {
/* Usamos colores típicos de Halloween en el gradiente radial */
background: radial-gradient(circle, black, purple, orange, darkred);
...
}
...
Utiliza tus propias imágenes y graba tus propios audios
Prueba a usar otras imágenes y otros audios. Puedes encontrar imágenes y audios gratuitos en los siguientes enlaces:
También puedes grabar tus audios e incluirlos directamente en la aplicación. Puedes utilizar tu propio móvil o alguna página web online similar a la siguiente:
Prueba a compilar la aplicación para móvil, y así podrás pulsar sobre las imágenes como si fueran botones. Puedes seguir las instrucciones detalladas aquí.
Ten en cuenta que el tamaño máximo para la aplicación en formato móvil es de 10MB, por lo que no podrás utilizar imágenes y audios demasiado grandes. Recomendamos el formato webp para imágenes y mp3 para audio. Puedes cambiar el formato o bajar la calidad de los ficheros con alguna herramienta online. Por ejemplo:
Añadir efecto de vibración al pulsar sobre cada imagen
Puedes añadir efecto de vibración muy fácilmente añadiendo la siguiente línea dentro de la función play del fichero script.js:
function play(soundName, soundVolume) {
...
// Si la vibración está disponible (en el móvil por ejemplo), vibrar durante 100 ms
if (navigator.vibrate) navigator.vibrate(100);
}
El resultado
En este enlace puedes probar esta versión de la aplicación instant buttons.
En esta parte del proyecto, vamos a añadir al juego la posibilidad de comprar Fábricas que produzcan más galletas para nosotros cada segundo sin tener que hacer clic.
Imagen para activar la mejora
Al pulsar sobre esta imagen activarás la mejora de las fábricas. Puedes elegir cualquier imagen para tu juego, teniendo en cuenta simplemente que deberás colocarla dentro de la carpeta img. A continuación te proporcionamos una imagen de ejemplo:
Modificaciones del fichero «index.html»
Vamos a añadir un div adicional a nuestro código html para poder activar la mejora. De esta forma, el jugador podrá comprar fábricas pulsando sobre la imagen. Por cada fábrica que adquiera el jugador, se generarán más galletas automáticamente cada segundo:
Añadimos la mejora de fabricas al objeto juego, con un precio inicial de 500 galletas. Cada fábrica comprada generará 20 galletas por segundo:
// Objeto que almacena toda la información relativa al progreso y configuración del juego
let juego = {
galletas: 0, // Cantidad total de galletas conseguidas
mejoras: {
...
fabricas: { cantidad: 0, precio: 500, descripcion: "Fábricas que producen 20 galletas por segundo" } // Mejora de Fábricas
}
}
Modificaciones del fichero «script.js»
Para conseguir que las fábricas produzcan galletas sin que tengamos que hacer clic, deberemos incrementar la cantidad de galletas de forma automática cada segundo. Para ello ya disponemos de la función «producirAutomaticamente()», que creamos en una unidad anterior, dentro del fichero «script.js». Añadiendo una sola línea a esta función podremos conseguir que por cada fábrica que hayamos comprado, consigamos 20 galletas más de forma automática cada segundo:
...
// Función para producir galletas automáticamente
// Se ejecuta cada segundo y suma galletas según las mejoras compradas
function producirAutomaticamente() {
...
juego.galletas += juego.mejoras.fabricas.cantidad * 20; // Suma las galletas por Fábricas
guardarProgreso(); // Guarda el progreso automáticamente
}
En esta parte del proyecto vamos a añadir al juego la posibilidad de comprar Granjas. De esta forma podremos conseguir más galletas cada segundo sin tener que hacer clic.
Imagen para activar la mejora
Al pulsar sobre esta imagen activarás la mejora de las granjas. Puedes elegir cualquier imagen para tu juego, teniendo en cuenta simplemente que deberás colocarla dentro de la carpeta img. A continuación te proporcionamos una imagen de ejemplo:
Modificaciones del fichero «index.html»
Vamos a añadir un div adicional a nuestro código html para poder activar la mejora. De esta forma, el jugador podrá comprar granjas pulsando sobre la imagen. Por cada granja que adquiera el jugador, se generarán más galletas automáticamente:
Añadimos la mejora de granjas al objeto juego, con un precio inicial de 400 galletas por cada granja que compremos. Cada una de ellas generará 10 galletas por segundo:
// Objeto que almacena toda la información relativa al progreso y configuración del juego
let juego = {
galletas: 0, // Cantidad total de galletas conseguidas
mejoras: {
...
granjas: { cantidad: 0, precio: 400, descripcion: "Granjas que producen 10 galletas por segundo" }, // Mejora de Granjas
}
}
Modificaciones del fichero «script.js»
Para conseguir que las granjas produzcan galletas sin que tengamos que hacer clic, deberemos incrementar la cantidad de galletas de forma automática cada segundo. Para ello ya disponemos de la función «producirAutomaticamente()», que creamos en una unidad anterior, dentro del fichero «script.js». Añadiendo una sola línea a esta función podremos conseguir que por cada granja que hayamos comprado, consigamos 10 galletas más de forma automática cada segundo:
...
// Función para producir galletas automáticamente
// Se ejecuta cada segundo y suma galletas según las mejoras compradas
function producirAutomaticamente() {
...
juego.galletas += juego.mejoras.granjas.cantidad * 10; // Suma las galletas por Granjas
guardarProgreso(); // Guarda el progreso automáticamente
}