# perdiendo.org/museodemetralla

entraron en mi cabeza (201) | libros (20) | me lo llevo puesto (7) | pelis (2) | Renta básica (9) | series (6) | escasez (2) | frikeando (94) | arduino (1) | autoreferencial (11) | bici (1) | esperanto (4) | eve online (3) | git (2) | GNU/linux (4) | markdown (7) | nexus7 (2) | python (7) | raspberry pi (3) | vim (1) | wordpress (1) | zatchtronics (3) | hago (755) | canciones (156) | borradores (7) | cover (42) | el extremo inútil de la escoba (2) | elec (1) | GRACO (2) | guitarlele (11) | ruiditos (11) | Solenoide (1) | fotos (37) | nanowrimo (3) | novela (26) | criaturas del pantano (5) | el año que no follamos (12) | huim (5) | rehab (4) | poemas (353) | Anclajes (15) | andando (3) | B.A.R (7) | Canción de cuna para un borracho (38) | Cercos vacíos (37) | Cien puentes en la cabeza (7) | Conejo azul (6) | Contenido del juego (5) | De tiendas (3) | del pantano (3) | Destrozos (2) | Epilogo (4) | Fuegos de artificio (5) | Imposible rescate (15) | Jugando a rojo (7) | Libro del desencuentro (2) | Lo que sé de Marte (11) | Los cuentos (21) | Montaje del juego (5) | Orden de salida (4) | palitos (31) | Piernas abiertas (7) | Poemas medianos (12) | Privado de sueño (7) | rasguemas (5) | Tanto para nada (17) | Todo a 100 (2) | Uno (4) | relatos (96) | anatemas (9) | orbital (2) | prompts (8) | vindicaciones (103) | perdiendo (1.694) | atranques (1) |

el ahorcado

Es divertido, mucho. Pero después de reventarme contra ello es de esas cosas que sé que puedo entender si la reviso, pero no sé si sería capaz de crearlo por mí mismo (dudo mucho que fuera capaz).

# el famosísimo internacionalmente juego del ahorcado versión mimismo

import random # importamos el módulo para elegir posteriormente entre las palabras de la variable "palabras"

'''
Cadena multi-línea: comillas triples en una variable permiten meter varias líneas sin tener que utilizar \n

Lista: contiene varios valores a los que se puede acudir por número de izq a der empezando desde el 0,
en la de abajo IMÁGENES_AHORCADO cada elemento de la lista es una cadena multi-línea

Constantes: para variables constantes como IMÁGENES_AHORCADO la convención es que vayan escritas en mayúscula
(una "variable constante" es un contrasentido como un piano, yo diría "constante" sin más)

'''

IMÁGENES_AHORCADO = [''' 

  +---+
  |   |
      |
      |
      |
      |
=========''', '''

  +---+
  |   |
  O   |
      |
      |
      |
=========''', '''

  +---+
  |   |
  O   |
  |   |
      |
      |
=========''', '''

  +---+
  |   |
  O   |
 /|   |
      |
      |
=========''', '''

  +---+
  |   |
  O   |
 /|\  |
      |
      |
=========''', '''

  +---+
  |   |
  O   |
 /|\  |
 /    |
      |
=========''', '''

  +---+
  |   |
  O   |
 /|\  |
 / \  |
      |
=========''']

palabras = 'hormiga babuino tejon murcielago oso castor camello gato almeja cobra pantera coyote cuervo ciervo perro burro pato aguila huron zorro rana cabra ganso halcon leon lagarto llama topo mono alce raton mula salamandra nutria buho panda loro paloma piton conejo carnero rata cuervo rinoceronte salmon foca tiburon oveja mofeta perezoso serpiente araña cigüeña cisne tigre sapo trucha pavo tortuga comadreja ballena lobo wombat cebra'.split()

# el método .split() devuelve una lista en la que cada palabra en la cadena es un elemento aparte, separa en cada hueco en blanco. 
# "palabras" pasa a ser una lista igual que si hubiéramos escr
# con ListaDePalabras defines un parámetro, dices que al lanzar la función obtenerPalabraAlAzar le incluirás una lista entre (). ito palabras = ['hormiga', 'babuino'] etcetc.

# recordatorio personal: definir funciones no pone en marcha nada, simplemente las define para un futuro

# no es que estés creando otra lista, sino que le indicas que trabajará con una lista de palabras que proporcionas, en este caso 'palabras'
# eso mola porque la función utilizará listaDePalabras para manipularlas se llame como se llame la lista que le metas
# lo que me ha costado comprender esto, todo está relacionado con las variables globales y las variables locales
# si dentro de la función substituyes listaDePalabras por palabras todo seguiría funcionando igual, de hecho lo hace en la función siguiente
def obtenerPalabraAlAzar(listaDePalabras):
    índiceDePalabras = random.randint(0, len(listaDePalabras) - 1) # el número que se usará para elegir de la lista palabras[x]
# -1 porque el elemento 1 es el 0 en la asignación, así que la cuarta palabra en la lista estará en la posición 3
# elige entre 0 y la longitud de la lista -1
    return listaDePalabras[índiceDePalabras]
# devuelve listaDePalabras (que en este caso es palabras, el nombre de la lista) y [el índice]: palabras[x]

# en esta función las variables locales se llaman igual que las globales, aunque no son las mismas
def mostrarTablero(IMÁGENES_AHORCADO, letrasIncorrectas, letrasCorrectas, palabraSecreta):
    print(IMÁGENES_AHORCADO[len(letrasIncorrectas)]) # imprime de la lista de imágenes la que está en la posición de las letras incorrectas
    print() # imprimimos una línea en blanco

    print('Letras incorrectas:', end=' ') # imprime el texto y no salta a la línea de abajo
    for letra in letrasIncorrectas: # letra es una nueva variable for hace que "deletree" las letras que pertenecen a incorrectas y las guarda en cada ciclo en letra
        print(letra, end=' ') # la secuencia for imprime letra sin saltar a la linea de abajo
    print() # imprimimos una línea en blanco

    espaciosVacíos = '_' * len(palabraSecreta) # las líneas de la palabra, imprime tantos _ como su longitud

    for i in range(len(palabraSecreta)): # nueva variable i en la que se acumula toda la longitud de palabraSecreta, si tiene 7 letras se moverá entre el 0-6
        if palabraSecreta[i] in letrasCorrectas: # si la letra que toca está en letras correctas... (cualquier variable es tb una lista de letras, guardas 'hola' y palabraSecreta[0] será h)
            espaciosVacíos = espaciosVacíos[:i] + palabraSecreta[i] + espaciosVacíos[i+1:]
            ''' vamos a actualizar espaciosVacíos por las letras descubiertas con un corte de lista
                corte de lista [a:c] marca las palabras que se van a incluir con desde-hasta, y el hasta no incluye, en hola[1:3] sería ol, las pos 1 y 2
                1. espaciosVacíos[:i] metemos los valores de espacios vacíos hasta i (para no modificar los anteriores bucles de _ vacíos y letras descubiertas)
                el hasta del corte llega hasta justo la posición anterior a i
                2. palabraSecreta[i] metemos la letra que ha sido correcta en i
                3. espaciosVacíos[i+1:] metemos desde i en adelante lo que hubiera (_ vacíos y letras descubiertas)
                de espaciosVacíos nos interesan los _ y las letras descubiertas en bucles anteriores, y de palabraSecreta sólo la letra correcta
            '''

    for letra in espaciosVacíos: # generamos letra con todo lo que esté en spaciosVacíos
        print(letra, end=' ') # imprimimos las letras y los _ (letra es la variable que creamos cada ciclo) y no saltamos de línea
    print() # imprimimos una línea en blanco

# nueva función para recibir la nueva letra, le metemos letrasProbadas con las letras que hemos metido con anterioridad como parámetro
def obtenerIntento(letrasProbadas):
    while True: # jaja, siempre es true hasta que sales con return
        print('Adivina una letra.') # imprimimos Adivina...
        intento = input() # le pedimos que meta una letra y la guardamos en intento
        intento = intento.lower() # la ponemos en minúscula
        if len(intento) != 1: # si la longitud de intento es más de uno es que ha metido más de una letra y no mola
            print('Por favor, introduce una letra.') # le decimos lo que ha pasado
        elif intento in letrasProbadas: # tb si la letra ya la ha metido antes 
            print('Ya has probado esa letra, elige otra.') # le decimos que ya lo ha hecho
        elif intento not in 'abcdefghijklmnñopqrstuvwxyz': # si no está en el abecedario
            print('Por favor, ingresa una LETRA.') # se lo recordamos
        else: # en cualquier otro caso
            return intento # devolvemos el resultado metiéndolo en la variable global intento

# función para volver a jugar o salir
def jugarDeNuevo(): # definimos, no necesita parámetro
    print('¿Quieres jugar de nuevo (sí o no)') # imprimimos la pregunta
    return input().lower().startswith('s') # ponemos input en minúsculas, si empieza por s devuelve True (s no es lo mismo que S)

# y empieza el juego!
print('A H O R C A D O') # imprimimos el nombre
letrasIncorrectas = '' # creamos la variable letrasIncorrectas
letrasCorrectas = '' # creamos la variable #letrasCorrectas
# la única vez que se invoca "palabras" es para meterla dentro de la función obtenerPalabraAlAzar
# le estás diciendo a la función el nombre de la lista que tiene que utilizar
palabraSecreta = obtenerPalabraAlAzar(palabras) # creamos la palabra correcta
juegoTerminado = False # establecemos el status para salir del juego en False

while True: # repite el bucle indefinidamente hasta que algo le saca
    mostrarTablero(IMÁGENES_AHORCADO, letrasIncorrectas, letrasCorrectas, palabraSecreta) # invocas mostrarTablero con sus variables

    intento = obtenerIntento(letrasIncorrectas + letrasCorrectas) # creas intento invocando a la función obtenerIntento, con las letrasIncorrectas y las letrasCorrectas como variables que se meterán en la variable local letrasProbadas

    if intento in palabraSecreta: # aquí la función obtenerIntento ya ha devuelto la letra que ha metido el tipo, así que si está en la palabraSecreta...
        letrasCorrectas = letrasCorrectas + intento # la añadimos a letrasCorrectas manteniendo las anteriores, en intento sigue estando la letra que ha metido el tipo

        encontradoTodasLasLetras = True # marcamos el status de encontradoTodasLasLetras como verdadero, tendrá sentido en el siguiente if
        for i in range(len(palabraSecreta)): # bucle for para testar las letras
            if palabraSecreta[i] not in letrasCorrectas: # si una de las letras de palabraSecreta no está en letrasCorrectas
                encontradoTodasLasLetras = False # cambiamos el status de encontradoTodasLasLetras a False
                break # rompemos el for, así que pasará a else:
        if encontradoTodasLasLetras: # si encontradoTodasLasLetras es True
            print('¡Sí! ¡La palabra secreta es "' + palabraSecreta + '"! ¡Has ganado!') # imprimes el final
            juegoTerminado = True # y creas juego terminado y le das valor True
    else:
        letrasIncorrectas = letrasIncorrectas + intento # si la letra no estaba en la palabra secreta, la añadimos a letras incorrectas

        if len(letrasIncorrectas) == len(IMÁGENES_AHORCADO) - 1: # ojo, si la longitud de letrasIncorrectas es igual a IMÁGENES_AHORCADO - 1 (len empieza en 1, las listas en 0)
            mostrarTablero(IMÁGENES_AHORCADO, letrasIncorrectas, letrasCorrectas, palabraSecreta) # invocamos mostrarTablero con sus parámetros
            print('¡Te has quedado sin intentos!\nDespués de ' + str(len(letrasIncorrectas)) + ' intentos fallidos y ' + str(len(letrasCorrectas)) + ' aciertos, la palabra era "' + palabraSecreta + '"')
            # imprimimos msg + el número de letras incorrectas + msg + el número de letras correctas + msg + la palabra secreta que había que adivinar
            juegoTerminado = True # y establecemos juegoTerminado en True

    if juegoTerminado: # invocamos juegoTerminado, y si devuelve True 
        if jugarDeNuevo(): # si el tipo ha contestado cualquier cosa que empiece por s, incluido soplapollas
                           # atención a cómo juegoTerminado, que no es una función, no tiene (), mientras que jugarDeNuevo, que sí lo es, sí los tiene
            letrasIncorrectas = '' # ponemos a cero letrasIncorrectas
            letrasCorrectas = '' # ponemos a cero letrasCorrectas
            juegoTerminado = False # convertimos juegoTerminado a False
            palabraSecreta = obtenerPalabraAlAzar(palabras) # obtenemos una nueva palabraSecreta
        else: # si jugarDeNuevo devuelve false
            break # cerramos el programa

reino de dragones

Este ejercicio me ha gustado mucho. Descubrir que se puede hacer que se ejecute una función como expresión de una variable me ha volado la cabeza. Es tontísimo, pero también lo soy yo. Escribí el código y después estuve un rato intentando entender por qué estaba funcionando y me divertí un ratazo. Mientras siga divirtiéndome seguro que al final termino aprendiendo a hacer algo.

# mancantao

import random # importa el módulo random para números aleatorios
import time # importa el módulo time para los delays de explorarCueva

# El programa va a definir algunas funciones antes de empezar

def mostrarIntroducción(): # defines la función de la introducción, no mucho más que decir

# se podría hacer con un print partiéndolo con \n

'''
    print('Estás en una tierra llena de dragones. Frente a ti' '\n' 'hay dos cuevas. En una de ellas el dragón es generoso y' '\n' 'amigable y compartirá su tesoro contigo. El otro dragón' '\n' 'es codicioso y está hambriento y te devorará inmediatamente.')

'''
    print('Estás en una tierra llena de dragones. Frente a ti')
    print('hay dos cuevas. En una de ellas el dragón es generoso y')
    print('amigable y compartirá su tesoro contigo. El otro dragón')
    print('es codicioso y está hambriento y te devorará inmediatamente.')

def elegirCueva():
    # puedes meter lo que quieras, se va a sobreescribir en cuanto responda el paco, pero es más elegante crear una cadena vacía
    # y más interesante meter algo que nadie va a ver
    cueva = 'Gustavo Bueso es un fraude'
    # cachondo, si no es uno o dos repite el bucle hasta que el paco responda lo que debe, si es 1 o 2 sigue adelante
    while cueva != '1' and cueva != '2':
        print('¿A qué cueva quieres entrar? (1 o 2)')
        cueva = input()

    # hace que la función elegirCueva, al terminar, devuelva el valor de la variable cueva, así que el resultado de elegirCueva() sería 1 o 2
    return cueva

def explorarCueva(cuevaElegida):
    print('Te aproximas a la cueva...')
    time.sleep(2)
    print('Es oscura y espeluznante...')
    time.sleep(2)
    print('¡Un gran dragón aparece súbitamente frente a ti! Abre sus fauces y...')
    print()
    time.sleep(2)

    cuevaAmigable = random.randint(1,2) # asocia un número aleatorio entre 1 y 2 a cuevaAmigable

    if cuevaElegida == str(cuevaAmigable):
        print('¡Te regala su tesoro!')
    else:
        print('¡Te engulle de un bocado!')

# Y el programa empieza

jugarDeNuevo = 'si' # empieza dándole un valor si a jugarDeNuevo para poner en marcha el while
while jugarDeNuevo == 'si' or jugarDeNuevo == 's':

    mostrarIntroducción()

    númeroDeCueva = elegirCueva() # asocia númeroDeCueva a la ejecución de elegirCueva!!! eso mola un montón. El valor que devuelve se le asigna a númeroDeCueva

    explorarCueva(númeroDeCueva) # ejecuta explorarCueva con el valor de número de Cueva

    print('¿Quieres jugar de nuevo (si o no)')
    jugarDeNuevo = input()

fractalmente complejo cuanto más te acercas

Jekyll es lento para tanta mandanga. Se puede utilizar la opción

--incremental

para que no recree las mismas entradas una y otra vez, pero tarda millones de años en el feed (que podría deshabilitar) que defiendo por todos los medios que pueda. Por otro lado, en mi eterna carrera de amateur picaflor, en picocms he descubierto que puedes insertar archivos en el .twig (que me huelo que es más de twig que de picocms) con algo como:

 {% include 'thtml/tu-archivo.thtml' %}

Sólo tienes que insertar en la carpeta del tema en el que estés trabajando el .thtml correspondiente. Esa tontuna te permite, por ejemplo, hacer un pie de página que cambiar en un sólo archivo. Los archivos .twig en los que se inserta son una especie de estructura en la que después picocms coloca el contenido. Puedes necesitar varias estructuras para diferentes cosas, y tiene pinta de ser muy potente, pero imagina que tienes 30 o 40 diferentes y que cambia el año y tienes que modificarlas una a una. Encontrar en alguna parte esa simple solución le ha dado muchos más puntos al gestor de contenido.

Seguro que en cuanto entre alguien que entienda realmente de lo que estoy hablando se va a echar unas buenas risas con lo poco que entiendo yo.

El tema del blog… está complicado y no lo está (siguiendo con picocms). No está pensado para uno, pero se puede implementar con un .twig en el que incluyas algo como esto:

<div class="container">
        {{ content }}

        {% for page in pages|sort_by("time")|reverse %}
        {% if page.id starts with "blog/" and not page.hidden %}
        <div class="post">
            <p class="date">{{ page.date_formatted }}</p>
            <h3><a href="{{ page.url }}">{{ page.title }}</a></h3>
            <p class="excerpt">{{ page.description }}</p>
        </div>
    {% endif %}
{% endfor %}
</div>

Y después de un tiempo buscando encontré un plugin (pagination) que resuelve lo de dividir en páginas las chorrocientas entradas, pero no habría modo de navegar por año. Habría que darle a un número de página al azar (la 15, por ejemplo) e ir aproximándose. Por eso decidí hacer un archivo anual y, dentro de cada uno, otro mensual. Eso hace que tenga que generar 16 años * 12 meses = 192 plantillas .twig. No es por no hacerlo, con copypastes modificando una sola línea en cada uno es tedioso pero muy factible, pero no me parece una solución bonita. Me parece una cutrada.

Picocms es muy versátil pero tienes que saber unos mínimos, y yo no los sé. Al menos no de momento, y comprendo que estoy dando palos de ciego en muchas cuestiones.

Por otra parte me gusta el plugin de jekyll para importar del xml de wordpress. Te separa las entradas por un lado y el contenido multimedia por el otro. Ambos cms utilizan básicamente archivos markdown con un encabezado en yaml, así que se me ocurren modos de adaptar lo que jekyll necesita y recoge a cosas que picocms pueda interpretar. Puedo eliminar del XML de wordpress los campos que no me interesen, por ejemplo. O puedo eliminarlos luego de algún modo automátizado utilizando algún script de python. No sé.

Picocms no me termina de convencer porque necesitas el cms para interpretar los archivos. Jekyll puede ser lento, pero construye archivos html y css (bueno, SASS, un CSS vitaminado del que no había oído hablar hasta ayer, más lío) que no necesitan más interprete que el navegador.

Por otro lado por simple volúmen de contenido, por más tontaco que sea, aumentan las visitas, y la instancia de Amazon está cada día más colapsada. No voy a pagarles más de esos 60 pavos al año, que con eso me compro la raspi, la tarjeta sd, el cargador, un pendrive y la caja. Me ha gustado mucho aprender cómo tiene Amazon montado el garito, pero todo tiene un límite. Quizá mude wp a la raspi, que era lo que quería evitar, y ya veremos. Pero en la raspi ya está r4sp1, el extremo inutil de la escoba, palabra de bob, zilgu (esta, la pobre, no tendría ni que mencionarla, ya contaré su historia y el horror de que estuviera hecha en flash), un servidor de mumble, otro de XMPP, otro de transmission, una vpn, uno de netdata… y un montón de otras cosas que ya ni recuerdo haber metido ahí. ¿Reventara?, ¿paso todas las webs a la vieja raspi, y monto en la actual el blog y los servicios?

No sé, no tengo ni idea. Me explota la cabeza.