Una algoritme és un programa que pot executar diferents blocs de codi en funció de si es compleixen, o no es compleixen, unes condicions el número de vegades que tu vulguis.

Introducció

Tal com has vista a Computació, un programa pot executar qualsevol tipus de formula matemàtica.

Però apart d'això, amb el que coneixes fins ara, no es pot fer gaire cosa més.

Tots els algoritmes es basen en una condició que només pot tenir dos valors: cert o fals.

En Typescript tens els tipus boolean que només pot tenir dos valors: true o false

Selecció

Condició

Una variable de tipus boolean ens permet executar un tros de codi si es compleix un condició.

Això es fa amb l'expressió if.

La sentencia if (...) avalua la condició dins els parentesis, i si el resultat és cert (true), executa un bloc de codi.

Crea el fitxer main.ts:

let isDone: boolean = true

if (isDone) {
    console.log("Ben fet!")
}

console.log("Adeu!")

Si executes el codi pots veure que com que isDone és true, s'executa la sentència console.log("Ben fet!"):

$ bun.exe .\main.ts
Ben fet!
Adeu!

En canvi, si modifiques el codi i dius que isDone és false:

let isDone: boolean = false

if (isDone) {
    console.log("Ben fet!")
}
console.log("Adeu!")

La sentència console.log("Ben fet!") no s'executa:

$ bun.exe .\main.ts
Adeu!

A continuació tens el diagrama d'execució:

flowchart 
    S(("S")) --> A
    A[isDone = false] --> B{IF isDone}
    B -- true --> C["console.log(#quot;Ben fet!#quot;)"]
    B -- false --> D
    C --> D["console.log(#quot;Adeu#quot;)"]
    D --> Z(("F"))

Comparació

Els operadors de comparació comparen dos valors i retornen un valor de tipus boolean: true o false.

Operador Exemple Explicació
== a == b a és igual a b
!= a != b a no és igual a b
> a > b a és més gran que b
< a > b a és menys gran que b
>= a >= b a és més gran o igual que b
<= a <= b a és menys gran o igual que b

Per exemple:

console.log(2 > 1)  // true 
console.log(2 == 1) // false
console.log(2 != 1) // true

Si intentes comparar dos tipus diferents, Typescript et diu que t'estas equivocant:

let result: boolean = "eee" > 4

Error. Operator '>' cannot be applied to types 'string' and 'number'

El resultat d'una comparació és pot assignar a una variable, igual que qualsevol valor:

let result: boolean = 5 > 4 // assignar el resultat de la comparació
console.log(result); // true

Si intentes comparar dos variables amb tipus diferent, Typescript et diu que és un error:

let a: number
let b: string
console.log( a == b)

Error. This comparison appears to be unintentional because the types 'number' and 'string' have no overlap.

Si compares un valor amb un variable que té valor null, el resultat és false:

let dog : string | null = null
console.log(dog == "Idefix")

else

Molt cops no només has d'executar codi si es compleix una condició, també quan no és compleix aquesta condició (encara que només sigui per dir a l'usuari que la condició no es compleix).

Per això a un if se li pot afegir un else.

Per exemple, aquí tens un programa que permet a l'usuari comprar un drac volador si money és major de 100 monedes d'or 🐉

let money = 230

if (money > 100) {
    alert("Tens un 🐉")
} else {
    alert("El preu del 🐉 és de 100 🪙")
}

console.log("Adeu 👋")

Si executes el codi, pots comprar un drac volador:

> bun.exe .\main.ts
Tens un 🐉 [Enter] 
Adeu 👋

A continuació tens el diagrama d'execució del codi:

flowchart 
    S(("S")) --> A
    A[money = 230] --> B{"IF money > 100"}
    B -- true --> C[#quot;Tens un 🐉!#quot;]
    B -- false --> D[#quot;El preu pel 🐉 és de 100 🪙#quot;]
    D --> E[#quot;Adeu 👋#quot;]
    C --> E
    E --> Z(("F"))

A continuació modifica el codi per tal que demani a l'usuari quantes monedes ofereix:

let money: number = Number(prompt("Quantes monedes ofereixes 🪙?", "0"))
if (money > 100) {
    alert("Tens un 🐉")
} else {
    alert("El preu del 🐉 és de 100 🪙")
}

console.log("Adeu 👋")

else if

A veces queremos probar más de una condición. La clausula else if nos permite hacer esto.

Por ejemplo:

let year = Number(prompt('¿En qué año fue publicada la especificación ECMAScript-2015?', "0"))

if (year < 2015) {
    alert('Muy poco...');
} else if (year > 2015) {
    alert('Muy Tarde');
} else {
    alert('¡Exactamente!');
}

En el código de arriba, TypeScript:

  • Primero revisa si year < 2015.
  • Si esto es falso, continúa a la siguiente condición year > 2015.
  • Si esta también es falsa, mostrará la última alert.

Podría haber más bloques else if.

Operador ternario ?

A veces necesitamos que el valor que asignemos a una variable dependa de alguna condición.

Por ejemplo:

let age = Number(prompt('¿Qué edad tienes?', "0"))

let accessAllowed: string
if (age > 18) {
  accessAllowed = "Por supuesto!"
} else {
  accessAllowed = "Ni en sueños!"
}

alert(accessAllowed)

El "operador condicional" nos permite ejecutar esto en una forma más corta y simple.

El operador está representado por el signo de cierre de interrogación ?.

La Sintaxis es:

let result = condition ? value1 : value2;

Se evalúa condition: si es verdadera entonces devuelve value1 , de lo contrario value2.

Por ejemplo:

let age = Number(prompt('¿Qué edad tienes?', "0"))

let accessAllowed = (age > 18) ? "Por supuesto!" : "Ni en sueños!"
alert(accessAllowed)

Múltiples ?

Una secuencia de operadores de signos de interrogación ? puede devolver un valor que depende de más de una condición.

Por ejemplo:

let age = Number(prompt('¿edad?', "18"))

let message =
    (age < 3) ? '¡Hola, bebé!' :
        (age < 18) ? '¡Hola!' :
            (age < 100) ? '¡Felicidades!' :
                '¡Qué edad tan inusual!'

alert(message)

Puede ser difícil al principio comprender lo que está sucediendo.

Pero después de una mirada más cercana, podemos ver que es solo una secuencia ordinaria de condiciones:

  • El primer signo de pregunta revisa si age < 3.
  • Si es cierto, devuelve '¡Hola, bebé!'. De lo contrario, continúa a la expresión que está después de los dos puntos :, la cual revisa si age < 18.
  • Si es cierto, devuelve '¡Hola!'. De lo contrario, continúa con la expresión que está después de los dos puntos siguientes :, la cual revisa si age < 100.
  • Si es cierto, devuelve '¡Felicidades!'. De lo contrario, continúa a la expresión que está después de los dos puntos :, la cual devuelve '¡Qué edad tan inusual!'.

Aquí lo podemos ver utilizando if..else:

let age = Number(prompt('¿edad?', "18"))

let message: string
if (age < 3) {
    message = '¡Hola, bebé!'
} else if (age < 18) {
    message = '¡Hola!'
} else if (age < 100) {
    message = '¡Felicidades!'
} else {
    message = '¡Qué edad tan inusual!'
}

alert(message)

Activitat

1.- Escriu un script que et pregunta l'edat, i et diu que pots votar si tens més de 17 anys:

let edat: number | null = Number(prompt("Quina edat tens?"))

if (edat > 17) {
    alert("Pots votar!")
}

2.- Modifica l'script perque a més de dir-te que encara no tens edat per votar, et digui quants anys et falten per poder votar.

3.- Que passa si l'usuari et diu que té -555 anys?

4.- Usando el constructor if..else, escribe un código que obtenga a través de un prompt un número y entonces muestre en un alert:

  • 1, si el valor es mayor que cero,
  • -1, si es menor que cero,
  • 0, si es igual a cero.

let value = Number(prompt('Escribe un número', "0"))

if (value > 0) {
    alert(1);
} else if (value < 0) {
    alert(-1);
} else {
    alert(0);
}

5.- Reescriba esta condición if usando el operador ternario '?':

let a = 5
let b = 8 

let result: string

if (a + b < 4) {
  result = 'Debajo'
} else {
  result = 'Encima'
}

let a = 5
let b = 8

let result = (a + b < 4) ? 'Debajo' : 'Encima'

6.- Reescriba el if..else utilizando operadores ternarios múltiples ?.

let login :string | null = null

let message;

if (login == 'Empleado') {
  message = 'Hola'
} else if (login == 'Director') {
  message = 'Felicidades'
} else if (login == null) {
  message = 'Sin sesión'
} else {
  message = ''
}

console.log(message)

let login: string | null = null

let message =
    (login == 'Empleado') ? 'Hola' :
        (login == 'Director') ? 'Felicidades' :
            (login == null) ? 'Sin sesión' : ''

console.log(message)

Operadors lògics

|| OR

El operador OR se representa con dos símbolos de linea vertical:

let result: boolean = a || b;

Si cualquiera de sus argumentos es true, retorna true, de lo contrario retorna false.

Hay cuatro combinaciones lógicas posibles:

console.log(true || true)   // true 
console.log(false || true)  // true
console.log(true || false)  // true
console.log(false || false) // false

Como podemos ver, el resultado es siempre true excepto cuando ambos operandos son false.

La mayoría de las veces, OR || es usado en una declaración if para probar si alguna de las condiciones dadas es true.

Por ejemplo:

let hour = 9

if (hour < 10 || hour > 18) {
    alert('La oficina esta cerrada')
}

Podemos pasar mas condiciones:

let hour = 12
let isWeekend = true

if (hour < 10 || hour > 18 || isWeekend) {
    alert("La oficina esta cerrada.") // Es fin de semana
}

Dado múltiples valores aplicados al operador OR:

let result: boolean = value1 || value2 || value3

El operador OR || realiza lo siguiente:

  • Evalúa los operandos de izquierda a derecha.
  • Para cada operando, si el resultado es true, se detiene y retorna true.
  • Si todos los operandos eran false, retorna false.

&& AND

El operador AND es representado con dos ampersands &&:

let result: boolean = a && b

AND retorna true si ambos operandos son valores verdaderos y false en cualquier otro caso.

console.log(true && true)   // true
console.log(false && true)  // false
console.log(true && false)  // false
console.log(false && false) // false

Un ejemplo con if:

let hour = 12
let minute = 30

if (hour == 12 && minute == 30) {
    alert("La hora es 12:30")
}

Dado múltiples valores aplicados al operador AND:

let result: boolean = value1 && value2 && value3;

El operador AND && realiza lo siguiente:

  • Evalúa los operandos de izquierda a derecha.
  • Para cada operando, si el resultado es false, se detiene y retorna false.
  • Si todos los operandos fueron valores verdaderos, devuelve true

La precedencia del operador AND && es mayor que la de OR ||.

Así que el código a && b || c && d es básicamente el mismo que si la expresiones && estuvieran entre paréntesis: (a && b) || (c && d).

! (NOT)

El operador booleano NOT se representa con un signo de exclamación !.

La sintaxis es bastante simple:

let result: boolean = !value

El operador acepta un solo argumento y realiza lo siguiente: retorna el valor contrario.

Por ejemplo:

console.log(!true)    // false
console.log(!(5 > 0)) //false

La precedencia de NOT ! es la mayor de todos los operadores lógicos, así que siempre se ejecuta primero, antes que && o ||.

Activitat

1.- Escribe una condición if para comprobar que age está entre 40 y 60 inclusive.

“Inclusive” significa que age puede llegar a ser uno de los extremos, 40 o 60.

let age = 50

if (age >= 40 && age <= 60)
    alert("You are middle-aged")

2.- Escribe una condición if para comprobar que age NO está entre 40 y 60 inclusive.

Crea dos variantes: la primera usando NOT !, y la segunda sin usarlo.

let age = 90

if (!(age >= 40 && age <= 60))
    alert("You aren't middle age")

if (age > 60 || age < 40)
    alert("You aren't middle age")

3.- Escriu un codi que primer pregunti el nom de l'usuari, i si aquest és admin, pregunti per la contrasenya, i si aquesta és password, doni la benvinguda a l'ususari.

let userName = prompt("Who are you?")

if (userName != "admin")
    alert("I don't know you")
else {
    let pass = prompt("Password?")
    if (pass != "password")
        alert("Bad password")
    else
        alert("Welcome!")
}

Repetició

Usualmente necesitamos repetir acciones.

Por ejemplo, mostrar los elementos de una lista uno tras otro o simplemente ejecutar el mismo código para cada número del 1 al 10.

Los Bucles son una forma de repetir el mismo código varias veces.

While

El bucle while (mientras) tiene la siguiente sintaxis:

while (condition) {
  // código
  // llamado "cuerpo del bucle"
}

Mientras la condición condition sea verdadera, el código del cuerpo del bucle será ejecutado.

Por ejemplo, el bucle debajo imprime i mientras se cumpla i < 3:

let i: number = 0
while (i < 3) { // muestra 0, luego 1, luego 2
    console.log(i)
    i += 1
}
flowchart 
    S(("S")) --> A
    A[i = 0] --> B{"WHILE i < 3"}
    B -- true --> C["console.log(i); i += 1"]
    C --> B
    B -- false --> E(("F"))
 
$ bun main.ts
0
1
2

Cada ejecución del cuerpo del bucle se llama iteración. El bucle en el ejemplo de arriba realiza 3 iteraciones.

Si faltara i += 1 en el ejemplo de arriba, el bucle sería repetido (en teoría) eternamente. En la práctica, el navegador tiene maneras de detener tales bucles desmedidos; y en el lado del servidor, podemos eliminar el proceso.

let i: number = 0
while (i < 3) { 
    console.log(i)
}

El bucle “do…while”

La comprobación de la condición puede ser movida debajo del cuerpo del bucle usando la sintaxis do..while:

do {
  // cuerpo del bucle
} while (condition)

El bucle primero ejecuta el cuerpo, luego comprueba la condición, y, mientras sea un valor verdadero, la ejecuta una y otra vez.

Por ejemplo:

let guess: string | null
do {
    guess = prompt("Guess")
} while (guess != "toto")

A continuació tens un exemple d'execució:

$ bun test.ts 
Guess fofo
Guess 
Guess toto

Esta sintaxis solo debe ser usada cuando quieres que el cuerpo del bucle sea ejecutado al menos una vez sin importar que la condición sea verdadera.

Rompiendo el bucle

Normalmente, se sale de un bucle cuando la condición se vuelve falsa.

Pero podemos forzar una salida en cualquier momento usando la directiva especial break.

Per exemple, en aquest bucle mai s'imprimeix res a la consola:

let i: number = 0
while (i < 10) {
    i += 1
    break
    console.log(i)
}
console.log(`i == ${i}`)

I només s'executa 1 cop!

$ bun test.ts 
i == 1

A continuació tens un exemple en que es demana a l'usuari que adivini un número:

const guess = 5
let tries = 3

while (tries > 0) {

    let n : number | null = Number(prompt("Número"))
    
    if (n == guess) {
        console.log("Correcte!")
        break
    }

    i =-1
}

Pots veure que el bucle acaba abans dels 3 intents perquè l'usuari ha adivinat el número.

$ bun test.ts 
Número 3
Número 5
Correcte!

La combinación “bucle infinito + break según sea necesario” es ideal en situaciones donde la condición del bucle debe ser comprobada no al inicio o al final de el bucle, sino a la mitad o incluso en varias partes del cuerpo.

Continuar a la siguiente iteración

La directiva continue detiene la iteración actual y fuerza al bucle a comenzar una nueva (si la condición lo permite).

Per exemple, en aquest bucle mai s'imprimeix res a la consola:

let i: number = 0
while (i < 10) {
    i += 1
    continue
    console.log(i)
}
console.log(`i == ${i}`)

Però s'executa 10 vegades!

$ bun test.ts 
i == 10

A continuació tens un bucle que va sumant números mentres l'usuari no entri cap valor:

let sum: number = 0
while (true) {

    let input: string | null = prompt("Número")

    if (input == null)
        break

    sum += Number(input)
    console.log(sum)
}

Pots veure que el programa va sumant a menys que l'usuari apreti "enter" sense cap valor:

$ bun test.ts 
Número 34
34
Número 56
90
Número 

El problema és que si l'usuari introdueix un string que no es pot transforma en number ...

$ bun test.ts 
Número tres
NaN
Número 45
NaN
Número

Tot és un NaN a partir de llavors.

Modifica el codi per verificar si l'entrada és NaN, i si es cert, continuar amb la propera iteració:

let sum: number = 0
while (true) {

    let input: string | null = prompt("Número")
    
    if (input == null)
        break
    
    let n = Number(input)
    if (Number.isNaN(n))
        continue

    sum += Number(input)
    console.log(sum)
}

Pots verificar que tot el que no sigui un número s'ignora:

$ bun test.ts
Número tres
Número 5
5
Número 

Activitats

1.- Crea un programa que pregunti a l'usuari adivinar un número del 1 al 100, i li digui si ha acertat, o e número és més gran o més petit.