Hola, mundo
escribir imprime y añade un salto de línea.
Los 55 ejemplos de esta página no están escritos a mano:
son archivos .lince del repositorio que se ejecutan al generar
el manual, y lo que ves bajo cada uno es su salida real. Si el lenguaje
cambia de comportamiento, la página deja de cuadrar y la integración continua lo
detecta — así la documentación no puede quedarse mintiendo.
Nada coincide con esa búsqueda.
escribir imprime y añade un salto de línea.
Sin importar nada: escribir y leer, a_numero, a_texto y a_logico para pasar de un tipo a otro, rango para contar, y mapear, filtrar y reducir para trabajar con listas (y con generadores, como rango()). argumentos() da lo que se escribió detrás del programa en la terminal.
escribir(a_numero("3.5") * 2)
escribir(a_texto(42) + "!")
escribir("{a_logico(0)} {a_logico("hola")}")
para cada numero n en rango(1, 10, 3) { escribir(n) }
sea dobles = mapear([1, 2, 3], funcion(val numero x): numero { devolver x * 2 })
sea pares = filtrar(rango(10), funcion(val numero x): logico { devolver x % 2 == 0 })
sea suma = reducir([1, 2, 3, 4], 0, funcion(val numero a, val numero x): numero { devolver a + x })
escribir("{dobles} {pares} {suma}")7 42! falso verdadero 1 4 7 [2, 4, 6] [0, 2, 4, 6, 8] 10
sea crea algo que puede cambiar; fijo, algo que no.
sea nombre = "Ana"
fijo PI = 3.14159
nombre = "Blanca"
escribir(nombre)
escribir(PI)Blanca 3.14159
x += 5 es x = x + 5 (también -=, *=, /= y %=), y x++ suma uno (x-- resta uno). Valen para variables, elementos de listas y diccionarios, y campos (mi.vidas--).
sea puntos = 10
puntos += 5
puntos *= 2
escribir(puntos)
sea nombre = "Lin"
nombre += "ce"
escribir(nombre)
sea vidas = {"Ana": 3, "Luis": 3}
vidas["Luis"] -= 1
escribir(vidas)
sea marcador = [3, 3]
marcador[1]--
marcador[0]++
escribir(marcador)30
Lince
{"Ana": 3, "Luis": 2}
[4, 2]Definir dos veces en el mismo ámbito es un error, no un descarte silencioso. Para cambiar el valor, asigna.
sea contador = 1
contador = 2
escribir(contador)
intentar {
sea contador = 3
} capturar (error e) {
escribir(e.mensaje)
}2
Esto no es redefinir: es otro ámbito. El de fuera queda intacto.
sea visible = "fuera"
funcion dentro(): texto {
sea visible = "dentro"
devolver visible
}
escribir(dentro())
escribir(visible)dentro fuera
En parámetros y retorno de función son obligatorios. En sea son opcionales y sólo para lista y diccionario.
sea lista notas = [9, 7, 10]
sea diccionario ficha = {"nombre": "Ana"}
funcion presentar(val texto quien, val numero anios): texto {
devolver quien + " tiene " + anios + " años"
}
escribir(presentar(ficha["nombre"], notas.longitud()))Ana tiene 3 años
Con corchetes, de una lista (tantos nombres como elementos); con llaves, de un diccionario por clave. Sin sea, asigna.
sea [ancho, alto] = [320, 180]
escribir(ancho * alto)
sea enemigo = {"vida": 50, "nombre": "orco", "fuerza": 7}
sea {nombre, vida} = enemigo
escribir("{nombre} con {vida} de vida")
sea a = 1
sea b = 2
[a, b] = [b, a]
escribir("{a} {b}")57600 orco con 50 de vida 2 1
si, sino si, sino. Los operadores lógicos son y, o, no.
sea nota = 7
si nota >= 9 {
escribir("sobresaliente")
} sino si nota >= 5 {
escribir("aprobado")
} sino {
escribir("suspenso")
}
si nota > 5 y no (nota == 10) {
escribir("entre 6 y 9")
}aprobado entre 6 y 9
y y o son operadores solo entre dos valores. En cualquier otro sitio son nombres normales, así que x e y sirven para las coordenadas, como en cualquier juego.
sea x = 3
sea y = 8
si x > 0 y y > 0 {
y = y - 1
escribir("arriba a la derecha, en ({x}, {y})")
}arriba a la derecha, en (3, 7)
Una expresión en cada rama y sino obligatorio. Solo se evalúa la rama que toca.
sea velocidad = -4
sea lado = si velocidad < 0 { "izquierda" } sino { "derecha" }
escribir(lado)
funcion nota(val numero n): texto {
devolver si n >= 9 { "sobresaliente" } sino si n >= 5 { "aprobado" } sino { "suspenso" }
}
escribir(nota(7))
sea puntos = 1
escribir("{puntos} {si puntos == 1 { "punto" } sino { "puntos" }}")izquierda aprobado 1 punto
para clásico, mientras, hacer/mientras y para cada.
para (i = 0; i < 3; i++) {
escribir("para " + i)
}
sea n = 0
mientras n < 2 {
escribir("mientras " + n)
n = n + 1
}
sea m = 0
hacer {
escribir("hacer " + m)
m = m + 1
} mientras (m < 2)
para cada numero x en [10, 20] {
escribir("cada " + x)
}para 0 para 1 para 2 mientras 0 mientras 1 hacer 0 hacer 1 cada 10 cada 20
romper sale del bucle; continuar pasa a la vuelta siguiente. Con bucles uno dentro de otro, afectan al de dentro.
sea enemigos = [{"vida": 0}, {"vida": 5}, {"vida": 8}, {"vida": 2}]
para cada diccionario e en enemigos {
si e["vida"] == 0 { continuar } # los muertos no cuentan
escribir("vivo con " + e["vida"])
si e["vida"] > 6 {
escribir("¡uno fuerte! dejo de mirar")
romper
}
}
para (i = 0; i < 20; i += 5) {
escribir(i)
}vivo con 5 vivo con 8 ¡uno fuerte! dejo de mirar 0 5 10 15
otro es el caso por defecto.
sea animal = "lince"
elegir animal {
caso "gato" { escribir("miau") }
caso "lince" { escribir("es un felino ibérico") }
otro { escribir("no sé qué hace") }
}es un felino ibérico
Los parámetros llevan val (por valor) o ref (por referencia), tipo y nombre.
funcion area(val numero base, val numero altura): numero {
devolver base * altura / 2
}
escribir(area(10, 4))20
Los parámetros con valor por defecto van al final.
funcion saludo(val texto nombre, val texto trato = "Hola"): texto {
devolver trato + ", " + nombre
}
escribir(saludo("Ana"))
escribir(saludo("Ana", "Buenas"))Hola, Ana Buenas, Ana
Una función sin nombre es un valor como cualquier otro.
sea doble = funcion(val numero x): numero { devolver x * 2 }
escribir(doble(21))
sea nums = [1, 2, 3, 4]
escribir(mapear(nums, doble))
escribir(filtrar(nums, funcion(val numero x): logico { devolver x % 2 == 0 }))
escribir(reducir(nums, 0, funcion(val numero a, val numero x): numero { devolver a + x }))42 [2, 4, 6, 8] [2, 4] 10
Una función es un valor más: se guarda en una lista, en un diccionario o en un campo, y se llama directamente desde ahí. También se puede llamar a lo que devuelve otra llamada. El ( va en la misma línea que lo que se llama.
sea golpes = [
funcion(val numero f): texto { devolver "puñetazo de " + f },
funcion(val numero f): texto { devolver "patada de " + f }
]
escribir(golpes[1](8))
sea acciones = {"saltar": funcion(): texto { devolver "¡hop!" }}
escribir(acciones["saltar"]())
funcion sumador(val numero a): funcion {
devolver funcion(val numero b): numero { devolver a + b }
}
escribir(sumador(2)(3))patada de 8 ¡hop! 5
Una función recuerda el ámbito donde se creó, así que puede llevar estado.
funcion contador_desde(val numero inicio): funcion {
sea n = inicio
devolver funcion(): numero {
n = n + 1
devolver n
}
}
sea siguiente = contador_desde(10)
escribir(siguiente())
escribir(siguiente())
escribir(siguiente())11 12 13
agregar, eliminar e insertar cambian la lista; longitud, posicion y contiene sólo la leen.
sea notas = [9, 7, 10]
notas.agregar(6)
escribir(notas)
escribir(notas.longitud())
escribir(notas.posicion(10))
escribir(notas.contiene(7))[9, 7, 10, 6] 4 2 verdadero
ordenar, invertir, copiar y + (dos listas seguidas) no tocan la original.
sea original = [3, 1, 2]
escribir(original.ordenar())
escribir(original.invertir())
escribir(original + [4, 5])
escribir(original)[1, 2, 3] [2, 1, 3] [3, 1, 2, 4, 5] [3, 1, 2]
La función comparadora devuelve negativo, cero o positivo. La ordenación es estable.
sea nums = [3, 1, 4, 1, 5]
escribir(nums.ordenar())
escribir(nums.ordenar(funcion(val numero a, val numero b): numero {
devolver b - a
}))[1, 1, 3, 4, 5] [5, 4, 3, 1, 1]
Las claves son texto. para cada sobre un diccionario recorre las claves.
sea persona = {"nombre": "Ana", "edad": 22}
persona["ciudad"] = "Córdoba"
escribir(persona["nombre"])
escribir(persona.longitud())
para cada texto clave en persona {
escribir(clave + " = " + persona[clave])
}Ana 3 nombre = Ana edad = 22 ciudad = Córdoba
La longitud cuenta caracteres, no bytes: las tildes y la eñe cuentan como uno.
importar "texto"
sea frase = "año de la cigüeña"
escribir(frase.longitud())
escribir(frase.mayusculas())
escribir(texto.dividir("a,b,c", ","))
escribir(texto.repetir("ab", 3))17 AÑO DE LA CIGÜEÑA ["a", "b", "c"] ababab
Entre llaves va cualquier expresión. Para una llave tal cual, \{; unas llaves vacías {} se quedan como están.
sea nombre = "Ana"
sea vidas = 3
escribir("{nombre} tiene {vidas} vidas")
escribir("y {vidas * 100} puntos, {nombre.longitud()} letras")
escribir("lista: {[1, 2, 3]}")
escribir("\{\"vidas\": {vidas}}")Ana tiene 3 vidas
y 300 puntos, 3 letras
lista: [1, 2, 3]
{"vidas": 3}mi es la instancia actual. El constructor se llama crear.
clase Rectangulo {
funcion crear(val numero ancho, val numero alto): nulo {
mi.ancho = ancho
mi.alto = alto
}
funcion area(): numero {
devolver mi.ancho * mi.alto
}
}
sea r = Rectangulo(4, 3)
escribir(r.area())12
extiende hereda; padre(...) llama al constructor de arriba.
clase Figura {
funcion crear(val texto nombre): nulo { mi.nombre = nombre }
funcion describir(): texto { devolver "soy un " + mi.nombre }
}
clase Cuadrado extiende Figura {
funcion crear(val numero lado): nulo {
padre("cuadrado")
mi.lado = lado
}
funcion area(): numero { devolver mi.lado * mi.lado }
}
sea c = Cuadrado(5)
escribir(c.describir())
escribir(c.area())soy un cuadrado 25
Una interfaz lista los métodos que una clase promete tener. Si a la clase le falta alguno, implementa da error al declararla.
interfaz Forma {
funcion area(): numero
funcion describir(): texto
}
clase Rectangulo implementa Forma {
funcion crear(val numero ancho, val numero alto): nulo {
mi.ancho = ancho
mi.alto = alto
}
funcion area(): numero {
devolver mi.ancho * mi.alto
}
funcion describir(): texto {
devolver "Rectángulo " + mi.ancho + "x" + mi.alto
}
}
clase Cuadrado implementa Forma {
funcion crear(val numero lado): nulo {
mi.lado = lado
}
funcion area(): numero {
devolver mi.lado * mi.lado
}
funcion describir(): texto {
devolver "Cuadrado de lado " + mi.lado
}
}
sea lista formas = [Rectangulo(2, 3), Cuadrado(5)]
para cada elemento f en formas {
escribir(f.describir() + " → " + f.area())
}Rectángulo 2x3 → 6 Cuadrado de lado 5 → 25
Una enumeracion da nombre a un conjunto fijo de valores: los estados de un personaje, las direcciones... Se comparan con ==, encajan en elegir y se recorren con para cada. Cada uno tiene nombre, indice (su posición) y valor: el que se le dé con =, o su posición. Si a un elegir sin otro le faltan valores, Lince avisa al empezar.
enumeracion Estado { Quieto Andando Saltando }
enumeracion Direccion {
Arriba = [0, -1]
Abajo = [0, 1]
Izquierda = [-1, 0]
Derecha = [1, 0]
}
funcion animacion(val Estado e): texto {
elegir e {
caso Estado.Quieto { devolver "respirar" }
caso Estado.Andando { devolver "andar" }
caso Estado.Saltando { devolver "saltar" }
}
devolver ""
}
sea estado = Estado.Andando
escribir(estado)
escribir(animacion(estado))
escribir(estado == Estado.Andando)
para cada Direccion d en Direccion {
escribir(d.nombre + " mueve " + d.valor)
}
escribir(Direccion.Izquierda.indice)Estado.Andando andar verdadero Arriba mueve [0, -1] Abajo mueve [0, 1] Izquierda mueve [-1, 0] Derecha mueve [1, 0] 2
Lo privado sólo se ve desde dentro de la clase; lo protegido, también desde sus subclases. Saltárselo lanza un ErrorAcceso, que se captura como cualquier error.
clase Cuenta {
privado sea saldo = 0
funcion ingresar(val numero cantidad): nulo {
mi.saldo = mi.saldo + cantidad
}
funcion consultar(): numero {
devolver mi.saldo
}
}
sea c = Cuenta()
c.ingresar(50)
escribir(c.consultar())
intentar {
escribir(c.saldo)
} capturar (ErrorAcceso e) {
escribir("No se puede: " + e.mensaje)
}50 No se puede: El campo 'saldo' de 'Cuenta' es privado: no se puede leer desde aquí.
estatico hace que un campo o método pertenezca a la clase y no a cada objeto. Se usan con el nombre de la clase. Un método estático no tiene mi.
clase Pedido {
estatico sea creados = 0
estatico fijo IVA = 21
funcion crear(val numero base): nulo {
mi.base = base
Pedido.creados = Pedido.creados + 1
}
estatico funcion con_iva(val numero base): numero {
devolver base + base * Pedido.IVA / 100
}
}
Pedido(10)
Pedido(20)
escribir(Pedido.creados)
escribir(Pedido.con_iva(100))2 121
Una clase abstracta no se instancia y puede exigir métodos abstracto a sus subclases. sobrescribe avisa si el padre no tiene ese método, en vez de crear uno nuevo por una errata.
abstracta clase Figura {
abstracto funcion area(): numero
funcion describir(): texto {
devolver "área " + mi.area()
}
}
clase Cuadrado extiende Figura {
funcion crear(val numero lado): nulo {
mi.lado = lado
}
sobrescribe funcion area(): numero {
devolver mi.lado * mi.lado
}
}
escribir(Cuadrado(3).describir())
intentar {
Figura()
} capturar (ErrorTipo e) {
escribir(e.mensaje)
}área 9 'Figura' es una clase abstracta y no se puede instanciar.
obtener y fijar se usan como un campo pero ejecutan código, así que pueden validar. Los métodos sumar, igual, menor... dan sentido a los operadores, y a_texto decide cómo se escribe el objeto.
clase Vector {
privado sea _x = 0
obtener x(): numero { devolver mi._x }
fijar x(val numero v): nulo {
si v < 0 { lanzar Error("x no puede ser negativa") }
mi._x = v
}
funcion sumar(val Vector b): Vector {
sea r = Vector()
r.x = mi.x + b.x
devolver r
}
funcion menor(val Vector b): logico { devolver mi.x < b.x }
funcion igual(val Vector b): logico { devolver mi.x == b.x }
funcion a_texto(): texto { devolver "Vector(" + mi.x + ")" }
}
sea a = Vector()
a.x = 2
sea b = Vector()
b.x = 5
escribir(a + b)
escribir(a < b)
escribir(a == b)
intentar {
a.x = -1
} capturar (Error e) {
escribir(e.mensaje)
}Vector(7) verdadero falso x no puede ser negativa
Una interfaz puede dar el cuerpo de un método: las clases que la implementan lo reciben sin repetirlo. x es Tipo comprueba la clase, la interfaz o el tipo básico de un valor.
interfaz Saludable {
funcion nombre(): texto
funcion saludar(): texto {
devolver "Hola, soy " + mi.nombre()
}
}
clase Persona implementa Saludable {
funcion nombre(): texto { devolver "Ana" }
}
clase Robot { }
sea p = Persona()
escribir(p.saludar())
escribir(p es Saludable)
escribir(Robot() es Saludable)
escribir(p es Persona)
escribir(5 es numero)Hola, soy Ana verdadero falso verdadero verdadero
generador en vez de funcion, y producir en vez de devolver.
generador pares(val numero hasta): numero {
para (i = 0; i <= hasta; i++) {
si i % 2 == 0 { producir i }
}
}
para cada numero p en pares(8) {
escribir(p)
}0 2 4 6 8
Cada valor se calcula cuando para cada lo pide, así que un generador puede no acabar: se sale con romper o devolver, y entonces se para (con su finalmente). Un generador se recorre una vez.
generador naturales(): numero {
sea n = 1
mientras verdadero {
producir n
n++
}
}
para cada numero n en naturales() {
si n * n > 50 {
escribir("el primero con el cuadrado mayor que 50 es " + n)
romper
}
}el primero con el cuadrado mayor que 50 es 8
Guardado en una variable, un generador recuerda dónde se quedó: el siguiente para cada continúa tras el romper. Los valores se calculan cuando se piden, así que rango() sirve aunque sea enorme.
generador turnos(): texto {
mientras verdadero {
producir "Ana"
producir "Luis"
producir "Marta"
}
}
sea quien = turnos()
para cada texto t en quien {
escribir("ronda 1: " + t)
si t == "Luis" { romper }
}
para cada texto t en quien {
escribir("ronda 2: " + t)
si t == "Ana" { romper }
}
para cada numero n en rango(1000000000) {
si n == 3 { romper }
escribir(n)
}ronda 1: Ana ronda 1: Luis ronda 2: Marta ronda 2: Ana 0 1 2
Una tarea se escribe como una función y empieza a correr al llamarla. esperar() la deja aparcada en esa línea hasta el fotograma siguiente; esperar(segundos), hasta que pase ese tiempo, y esperar(otra), hasta que otra tarea acabe (y da lo que devolvió). Mientras, todo lo demás sigue. En un juego avanzan solas en cada juego.presentar(); aquí, sin juego, avanzan mientras el programa espera.
tarea parpadear(val texto quien, val numero veces) {
para (i = 0; i < veces; i++) {
escribir(quien + ": brilla")
esperar()
}
escribir(quien + ": desaparece")
}
tarea jefe(): texto {
escribir("jefe: carga el golpe")
esperar(0.2)
escribir("jefe: ¡golpe!")
devolver "fin del ataque"
}
parpadear("moneda", 2)
parpadear("estrella", 3)
escribir(esperar(jefe()))
sea t = parpadear("vela", 100)
esperar()
t.parar() # se puede parar a medias
escribir(t.terminada())moneda: brilla estrella: brilla jefe: carga el golpe moneda: brilla estrella: brilla moneda: desaparece estrella: brilla estrella: desaparece jefe: ¡golpe! fin del ataque vela: brilla verdadero
capturar (error e) atrapa cualquier tipo; con un tipo concreto, sólo ese.
intentar {
sea lista nums = [1, 2, 3]
escribir(nums[99])
} capturar (ErrorRango e) {
escribir("fuera de rango: " + e.mensaje)
} capturar (error e) {
escribir("otro error")
} finalmente {
escribir("esto se ejecuta siempre")
}fuera de rango: Índice 99 fuera de rango. La lista tiene 3 elementos. esto se ejecuta siempre
Tipos predefinidos: Error, ErrorTipo, ErrorRango, ErrorNulo, ErrorMatematico, ErrorArgumento.
funcion raiz_entera(val numero n): numero {
si n < 0 {
lanzar ErrorArgumento("no hay raíz real de un número negativo")
}
devolver n
}
intentar {
escribir(raiz_entera(-1))
} capturar (ErrorArgumento e) {
escribir("[" + e.tipo + "] " + e.mensaje)
}[ErrorArgumento] no hay raíz real de un número negativo
Un error no se tapa con sus propias consecuencias: se informa de la causa, no del fallo que vino detrás.
intentar {
escribir(noExiste())
} capturar (error e) {
escribir("[" + e.tipo + "] " + e.mensaje)
}
intentar {
sea cinco = 5
escribir(cinco(1))
} capturar (ErrorTipo e) {
escribir("[" + e.tipo + "] " + e.mensaje)
}[Error] La variable 'noExiste' no está definida. [ErrorTipo] 'cinco' no es una función, así que no se puede llamar.
Un método con los argumentos mal, un índice fuera de rango, un campo que no existe… llegan como errores con su tipo y se pueden capturar. Sin capturar, el mensaje dice la línea.
sea lista notas = [9, 7]
intentar {
notas.agregar()
} capturar (ErrorArgumento e) {
escribir("[" + e.tipo + "] " + e.mensaje)
}
intentar {
notas[5] = 1
} capturar (ErrorRango e) {
escribir("[" + e.tipo + "] " + e.mensaje)
}
clase Caja {
funcion crear(val numero v): nulo { mi.v = v }
}
intentar {
sea c = Caja(1)
escribir(c.contenido)
} capturar (error e) {
escribir("[" + e.tipo + "] " + e.mensaje)
}[ErrorArgumento] 'agregar' necesita exactamente 1 argumento. [ErrorRango] Índice 5 fuera de rango. La lista tiene 2 elementos. [Error] El objeto no tiene el campo 'contenido'.
Hay ocho: matematica, texto, archivos, tiempo, sistema, json, pruebas y juego.
importar "matematica"
importar "json"
escribir(matematica.raiz(144))
escribir(json.texto({"vivo": verdadero}))12
{"vivo": true}La ruta se resuelve junto al archivo que importa, no desde donde lanzas el programa. Importar dos veces el mismo archivo no hace nada la segunda.
importar "./lib_geometria"
escribir(area_circulo(1.0))3.14159
Con como, el archivo corre en su propio ámbito y sólo se alcanza por el alias. Así dos librerías pueden tener funciones del mismo nombre.
importar "./lib_metros" como metros
importar "./lib_pies" como pies
escribir(metros.convertir(100))
escribir(pies.convertir(100))
escribir(metros.UNIDAD)100 328.084 m
Las clases de la librería se instancian por el alias: figuras.Cuadrado(3).
importar "./lib_figuras" como figuras
sea c = figuras.Cuadrado(3)
escribir(c.area())9
Redondeos, raíces, potencias, trigonometría (en radianes), máximos y mínimos, números al azar y las constantes PI, E y TAU. grados y radianes pasan de unos a otros (el módulo juego mide los ángulos en grados), y para juegos hay distancia, angulo, limitar, interpolar y más. aleatorio() da un número entre 0 y 1; aleatorio(1, 6), un entero entre los dos (un dado).
importar "matematica"
escribir("{matematica.piso(3.9)} {matematica.techo(3.1)} {matematica.redondear(2.5)}")
escribir("{matematica.raiz(144)} {matematica.potencia(2, 10)} {matematica.abs(-7)}")
escribir("{matematica.maximo(3, 9)} {matematica.minimo(3, 9)}")
escribir(matematica.redondear(matematica.seno(matematica.PI / 2)))
escribir("{matematica.factorial(5)} {matematica.combinaciones(5, 2)}")
escribir("{matematica.grados(matematica.PI)} {matematica.distancia(0, 0, 3, 4)} {matematica.limitar(15, 0, 10)}")
sea dado = matematica.aleatorio(1, 6)
escribir(dado >= 1 y dado <= 6)3 4 3 12 1024 7 9 3 1 120 10 180 5 10 verdadero
Lo que se hace con textos y no es un método: partirlos por un separador, unir una lista, darles la vuelta y buscar dónde aparece algo (−1 si no está).
importar "texto"
sea partes = texto.dividir("rojo,verde,azul", ",")
escribir(partes)
escribir(texto.unir(partes, " y "))
escribir(texto.invertir("lince"))
escribir("{texto.posicion("perspicaz", "pica")} {texto.posicion("lince", "x")}")["rojo", "verde", "azul"] rojo y verde y azul ecnil 4 -1
archivos lee y escribe en disco; sistema ejecuta órdenes del sistema y lee el entorno.
importar "archivos"
importar "sistema"
sea ruta = "/tmp/lince_manual_ejemplo.txt"
archivos.escribir(ruta, "hola")
archivos.agregar(ruta, " mundo")
escribir(archivos.leer(ruta))
escribir(archivos.existe(ruta))
archivos.eliminar(ruta)
escribir(archivos.existe(ruta))
escribir(sistema.ejecutar("echo desde el sistema"))hola mundo verdadero falso desde el sistema
tiempo da la hora y permite esperar (en segundos). En un juego se usa poco: el tiempo de cada fotograma lo da juego.dt().
importar "tiempo"
sea inicio = tiempo.ahora()
tiempo.esperar(0.02)
escribir(tiempo.ahora() - inicio >= 0)verdadero
json.parsear convierte un texto JSON en listas y diccionarios de Lince (y da un error si no es JSON válido); json.texto hace lo contrario, en una línea o, con verdadero, en varias. Escrito dentro de un texto, cada { lleva delante \ para que no se tome por un valor metido en el texto. Lo normal es leerlo de un archivo: json.parsear(archivos.leer("nivel.json")).
importar "json"
sea datos = json.parsear("\{\"nombre\": \"Ñandú\", \"puntos\": [10, 25.5], \"activo\": true}")
escribir("{datos["nombre"]} {datos["puntos"][1]} {datos["activo"]}")
escribir(json.texto({"vidas": 3, "llaves": ["roja"]}))
escribir(json.texto({"vidas": 3, "llaves": ["roja"]}, verdadero))
intentar {
json.parsear("\{\"roto\": ")
} capturar (error e) {
escribir(e.mensaje)
}Ñandú 25.5 verdadero
{"vidas": 3, "llaves": ["roja"]}
{
"vidas": 3,
"llaves": [
"roja"
]
}
json.parsear(): el texto no es JSON válidobytes es para datos binarios: leer y escribir archivos byte a byte, y enteros de 1, 2 o 4 bytes en una posición (leer_u16, escribir_i32...). Se usan como una lista de números de 0 a 255. bits hace las operaciones bit a bit con nombres: ambos (AND), alguno (OR), solo_uno (XOR), izquierda y derecha (desplazar), hex y binario.
importar "bytes"
importar "bits"
sea b = bytes.crear(6)
b.escribir_u16(0, 640)
b.escribir_u32(2, 4096)
escribir(b)
escribir("{b.leer_u16(0)} {b.leer_u32(2)} {b.longitud()}")
fijo SALTA = 0b0001
fijo DISPARA = 0b0010
sea estado = bits.alguno(SALTA, DISPARA)
escribir("{bits.binario(estado, 4)} {bits.ambos(estado, DISPARA) != 0}")
escribir("{bits.hex(255)} {bits.izquierda(1, 4)} {bits.de_hex("ff")}")bytes[80 02 00 10 00 00] 640 4096 6 0011 verdadero ff 16 255
Pruebas unitarias para tus programas: afirmar comprueba una condición, igual compara valores (también listas y diccionarios), lanza comprueba que una función da error y resumen imprime el total y termina con código 1 si algo falló, ideal para la integración continua.
importar "pruebas"
funcion doble(val numero n): numero {
devolver n * 2
}
pruebas.suite("doble")
pruebas.afirmar("doble de 4 es 8", doble(4) == 8)
pruebas.igual("una lista de dobles", [doble(1), doble(2)], [2, 4])
pruebas.lanza("dividir por cero da error", funcion(): nulo { sea x = 1 / 0 })
pruebas.resumen() ▶ doble
✅ doble de 4 es 8
✅ una lista de dobles
✅ dividir por cero da error
3 pruebas: 3 correctas, 0 fallidasUna fecha es una marca de tiempo: segundos desde 1970, como tiempo.ahora(). crear, formatear, partes y analizar trabajan en hora local; sus versiones _utc no dependen de la zona horaria. analizar devuelve nulo si el texto no encaja con el formato.
importar "tiempo"
sea t = tiempo.crear_utc(2024, 2, 29, 13, 5, 9)
escribir(tiempo.formatear_utc(t, "%d/%m/%Y %H:%M"))
escribir(tiempo.formatear_utc(t + 86400, "%Y-%m-%d"))
sea p = tiempo.partes_utc(t)
escribir(p["anio"])
escribir(p["dia_anio"])
escribir(tiempo.analizar_utc("2024-02-29 13:05:09", "%Y-%m-%d %H:%M:%S") == t)
escribir(tiempo.analizar_utc("no es una fecha", "%Y-%m-%d"))29/02/2024 13:05 2024-03-01 2024 60 verdadero nulo
El módulo para hacer juegos: ventana, dibujo, sprites y animaciones, teclado, ratón, mandos y pantalla táctil, sonido, mapas, física, menús... Tiene su propia página, con un ejemplo y su captura para cada cosa: el módulo juego. Estas funciones de ayuda no necesitan abrir ventana.
importar "juego"
# ¿se tocan el jugador y el enemigo? (x, y, ancho, alto de cada uno)
escribir(juego.colision(10, 10, 32, 32, 30, 30, 32, 32))
escribir(juego.colision(10, 10, 32, 32, 100, 100, 32, 32))
# ancho en píxeles de un texto, para centrarlo en la pantalla
sea ancho_pantalla = 800
escribir((ancho_pantalla - juego.ancho_texto("GAME OVER", 4)) / 2)verdadero falso 294
lince programa.lince lo ejecuta (un juego, con recarga en caliente: al guardar cambios sigue con el código nuevo). lince comprobar solo mira que esté bien escrito. lince compilar hace un ejecutable con el programa dentro, y lo que importa, que funciona sin instalar Lince. lince nuevo crea un juego pequeño y completo para empezar a cambiarlo. Para compartir un juego, y para el móvil, mira el módulo juego.
lince programa.lince # ejecutarlo
lince comprobar programa.lince # solo la sintaxis
lince compilar programa.lince -o prog # un ejecutable con todo dentro
lince nuevo mi_juego # una carpeta con un juego para empezar
lince versionlince depurar programa.lince lo ejecuta parándose en cada línea: s entra en la siguiente (también dentro de las funciones), n pasa a la siguiente sin entrar, c sigue hasta un punto de parada (b archivo.lince:12), p expresión enseña un valor, v las variables, bt la pila de llamadas y q sale.
lince depurar programa.lince
→ programa.lince:1 importar "juego"
(lince-dbg) b programa.lince:12
(lince-dbg) c
(lince-dbg) p jugador["vida"]
(lince-dbg) v
(lince-dbg) nlince sin nada abre el REPL: se escribe una línea y se ejecuta al momento, recordando lo anterior. Sirve para probar una función o ver qué da una expresión. :ayuda dice sus órdenes.
$ lince
🐆 Lince v0.9.0 — Escribe :ayuda para ver los comandos
>> sea vidas = 3
>> vidas * 10
=> 30lince instalar descarga una librería de Lince (un repositorio git) para usarla con importar "paquete:nombre". Para el editor hay una extensión de VS Code con colores, plantillas, errores y avisos al escribir, autocompletado e ir a la definición; por debajo usa lince lsp, que cualquier editor que hable LSP puede usar.
lince instalar https://github.com/usuario/paquete
lince listar
lince desinstalar paquete
code --install-extension lince-language-X.Y.Z.vsix # viene con cada versión