Ir al contenido principal

Python + Pygame (XXXII): Tutorial - Colisiones precisas (II)

En el post anterior puse un script para poder apreciar la diferencia de precisión existente entre las colisiones basadas en los rectángulos delimitadores de los sprites y aquellas basadas en las máscaras de sus formas, y en éste voy a poner un script de ejemplo de la utilización de la colisión por máscaras en un videojuego 2D, para lo que tomo otra vez como referencia uno de mis video juegos tipo arcade y género plataformas preferido, además de ser uno de los más populares de todos los tiempos: 'Donkey Kong'.

Para este script de ejemplo parto del que incluí en la última entrada del tutorial correspondiente a 'Salto de personajes'.

El script final, sobre el que, tras leer el post anterior,  no creo que haya que realizar explicaciones adicionales a los comentarios que en él figuran, es el siguiente:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# COLISIONES PRECISAS (MÁSCARAS):
#
# Colisiones entre sprites utilizando el método pygame.sprite.collide_mask().
#
# Autor: Mikel García Larragan.
# https://mikelgarcialarragan.blogspot.com/

import pygame
import os


class DonkeyKong(pygame.sprite.Sprite):
    # Donkey Kong estará definido por la clase DonkeyKong, que hereda de la
    # clase sprite.Sprite de Pygame. Clase base para objetos visibles del
    # juego.
    def __init__(self, x, y):
        super().__init__()
        self.x, self.y  = x, y
        # Dibujar a Donkey Kong en su posición inicial.
        self.image = pygame.image.load('recursos/imagenes/donkey_kong_1.png') \
                                                               .convert_alpha()

    def animar(self, imagen):
        # Método que permite que Donkey Kong tire barriles durante el juego y
        # gruña al finalizar éste.
        self.imagen = imagen
        self.image = pygame.image.load('recursos/imagenes/donkey_kong_'       +
                                     str(self.imagen) + '.png').convert_alpha()


    def update(self):
        # La función update() se ejecutará en cada frame, y permite actualizar
        # la posición de Donkey Kong.
        self.rect = self.image.get_rect(center=(self.x, self.y))


class Jumpman(pygame.sprite.Sprite):
    # Jumpman (Mario) estará definido por la clase Jumpman, que hereda de la
    # clase sprite.Sprite de Pygame. Clase base para objetos visibles del
    # juego.
    def __init__(self, x, y):
        super().__init__()
        self.x, self.y  = x, y
        self.image = pygame.image.load('recursos/imagenes/'                   +
                                       'jumpman_derecha_1.png').convert_alpha()
        self.mask = pygame.mask.from_surface(self.image)
        self.rect = self.image.get_rect(center=(self.x, self.y))

    def mover(self, movimiento, sentido, paso, vel_x, vel_y):
        # Método que permite que Jumpman se mueva (ande o salte) en el sentido
        # indicado.
        self.movimiento = movimiento
        self.sentido = sentido
        self.paso = paso
        self.x += vel_x
        self.y += vel_y
        if self.movimiento == 'ANDAR':
            self.image = pygame.image.load('recursos/imagenes/'               +
                                           'jumpman_' + self.sentido + '_'    +
                                                  str(self.paso) + '.png')    \
                                                          .convert_alpha()
        elif self.movimiento == 'SALTAR':
                self.image = pygame.image.load('recursos/imagenes/'   +
                                               'jumpman_saltar_'      +
                                                    self.sentido + '.png')    \
                                                          .convert_alpha()

    def finalizar_mover(self):
        # Método que permite completar el movimiento de Jumpman, tanto cuando
        # anda como cuando salta, mostrando la imagen correspondiente a Jumpman
        # parado.
        self.image = pygame.image.load('recursos/imagenes/'                   +
                                       'jumpman_' + self.sentido + '_1.png')  \
                                        .convert_alpha()

    def morir(self):
        # Método que permite mostrar la muerte de Jumpman cuando colisiona con
        # un barril, cae al piso inmediatamente inferior al que se encuentra
        # o salta fuera de la ventana.
        self.image = pygame.image.load('recursos/imagenes/'                   +
                                       'jumpman_morir.png').convert_alpha()

    def update(self):
        # El método update() se ejecutará en cada frame y permite actualizar la
        # posición de Jumpman.
        self.rect = self.image.get_rect(center=(self.x, self.y))


class Tramo(pygame.sprite.Sprite):
    # Los tramos del suelo por donde anda y salta Jumpman estarán definidos por
    # la clase Tramo, que hereda de la clase sprite.Sprite de Pygame. Clase
    # base para objetos visibles del juego.
    def __init__(self, x, y):
        super().__init__()
        self.x, self.y  = x, y
        self.image = pygame.image.load('recursos/imagenes/tramo.png')         \
                                                     .convert_alpha()
        self.rect = self.image.get_rect(center=(self.x, self.y))
        self.alto_tramo = self.image.get_height()

    def update(self):
        # El método update() se ejecutará en cada frame, y permite actualizar
        # los tramos.
        self.rect = self.image.get_rect(center=(self.x, self.y))


class Barril(pygame.sprite.Sprite):
    # Los barriles que arroja Donkey Kong estarán definidos por la clase
    # Barril, que hereda de la clase sprite.Sprite de Pygame. Clase base
    # para objetos visibles del juego.
    def __init__(self, piso, x, y):
        super().__init__()
        self.piso = piso
        self.imagen = 1
        self.x, self.y  = x, y
        self.vel_x, self.vel_y = 3, 1
        self.image = pygame.image.load('recursos/imagenes/barril_'            +
                                       str(self.imagen) + '.png')             \
                                       .convert_alpha()
        self.mask = pygame.mask.from_surface(self.image)
        self.rect = self.image.get_rect(center=(self.x, self.y))

    def caer(self, vel_x, vel_y):
        # Método que permite que los barriles vayan cayendo por las
        # platafornas.
        self.vel_x, self.vel_y = vel_x, vel_y
        self.imagen += 1
        if self.imagen > 4:
            self.imagen = 1
        self.image = pygame.image.load('recursos/imagenes/barril_'            +
                                       str(self.imagen) + '.png')             \
                                       .convert_alpha()
        self.mask = pygame.mask.from_surface(self.image)

    def update(self):
        # El método update() se ejecutará en cada frame, y permite actualizar
        # la posición de los barriles.
        self.rect.move_ip(self.vel_x, self.vel_y)


def donkey_kong():
    # Inicializar módulos internos de pygame.
    pygame.init()
    # Establecer tamaño de la ventana.
    # Crear una superficie de visualización: la ventana, y centrarla.
    os.environ['SDL_VIDEO_CENTERED']='1'
    ventana = pygame.display.set_mode((674, 430))
    # Título de la ventana.
    pygame.display.set_caption('Donkey Kong')
    # Cargar la imagen del fondo y cambiar el formato de píxel para crear una
    # copia que se dibujará más rápidamente en la pantalla.
    fondo = pygame.image.load('recursos/imagenes/fondo_2.png')
    fondo = fondo.convert()
    # Cargar archivos de fuente y de sonidos.
    font_emulogic_12 = pygame.font.Font(
                                'recursos/fuentes/emulogic.ttf', 12)
    font_emulogic_48 = pygame.font.Font(
                                'recursos/fuentes/emulogic.ttf', 48)
    sonido_andar = pygame.mixer.Sound(
                                   'recursos/sonidos/andar.wav')
    sonido_saltar = pygame.mixer.Sound(
                                   'recursos/sonidos/saltar.wav')
    sonido_morir = pygame.mixer.Sound(
                                   'recursos/sonidos/morir.wav')
    sonido_juego = pygame.mixer.Sound(
                                   'recursos/sonidos/juego.wav')
    sonido_game_over = pygame.mixer.Sound(
                                   'recursos/sonidos/game_over.wav')
    # Crear canales para sonidos simultáneos.
    canal1 = pygame.mixer.Channel(0)
    canal2 = pygame.mixer.Channel(1)
    # Grupo individual para Donkey Kong y dibujarlo.
    grupo_donkey_kong = pygame.sprite.GroupSingle()
    donkey_kong = DonkeyKong(125, 170)
    grupo_donkey_kong.add(donkey_kong)
    # Grupo de sprites. Agrupamos los tramos del suelo de los diferentes pisos
    # usando la clase sprite.Group de Pygame para hacer que dicha clase se
    # encargue de actualizarlos y dibujarlos, sin necesidad de hacerlo
    # manualmente.
    grupo_tramos_0 = pygame.sprite.Group()
    grupo_tramos_1 = pygame.sprite.Group()
    grupo_tramos_2 = pygame.sprite.Group()
    # Establecer el tiempo transcurrido (valor de un contador) desde que se
    # muestra una imagen de Donkey Kong tirando barriles  o gruñendo y el que
    # debe transcurrir hasta que se muestre la siguiente imagen.
    contador_inicio_imagen_donkey_kong = 0
    contador_fin_imagen_donkey_kong = 75
    # Imagen de Donkey Kong a mostrar cuando tira barriles.
    imagen_donkey_kong = 2
    # Variable boolena que indica si Donkey Kong ha tirado un barril.
    barril_tirado = False
    # Colocar los tramos del suelo del piso 0 en la pantalla.
    for num_tramo in range(14):
        tramo = Tramo(24 + 48 * num_tramo, 396)
        grupo_tramos_0.add(tramo)
    # Colocar los tramos del suelo del piso 1 en la pantalla.
    for num_tramo in range(13):
        tramo = Tramo(72 + 48 * num_tramo, 327 - num_tramo * 2)
        grupo_tramos_1.add(tramo)
    # Colocar los tramos del suelo del piso 2 en la pantalla.
    for num_tramo in range(13):
        if num_tramo < 9:
            tramo = Tramo(24 + 48 * num_tramo, 230)
        else:
            tramo = Tramo(24 + 48 * num_tramo, 232 + (num_tramo - 9) * 2)
        grupo_tramos_2.add(tramo)
    # Posición inicial de Jumpman.
    x, y = 120, 296
    # Grupo individual para Jumpman y dibujarlo.
    grupo_jumpman = pygame.sprite.GroupSingle()
    jumpman = Jumpman(x, y)
    grupo_jumpman.add(jumpman)
    # Variable booleana que indica si Jumpman está vivo o muerto.
    jumpman_vivo = True
    # Variables booleanas que indican si Jumpman se encuentra en el suelo o
    # está saltando, respectivamente.
    en_suelo = True
    en_salto = False
    # Sentido del movimiento de Jumpman, tanto cuando anda como cuando salta.
    sentido = 'DERECHA'
    # Velocidad de movimiento en ambos ejes.
    vel_x, vel_y = 3, 0
    # Variables correspondientes al salto.
    sentido_salto = 0
    altura_salto = 9
    gravedad = 1
    # Establecer el tiempo transcurrido (valor de un contador) desde el inicio
    # del movimiento de Jumpman, tanto cuando está andando como cuando salta, y
    # el que debe transcurrir hasta su finalización.
    contador_inicio_mover = 0
    contador_fin_mover = 10
    # Variable booleana que indica si se debe finalizar de mostrar el
    # movimiento de Jumpman (andar o saltar).
    finalizar_mover = False
    # Grupo para los barriles que arroja Donkey Kong.
    grupo_barriles = pygame.sprite.Group()
    # Variables booleanas que indican si se ha producido una colisión entre los
    # rectángulos delimitadores de los sprites de Jumpman y un barril, y de sus
    # máscaras (formas), respectivamente.
    colision_rect = colision_mask = False
    # Establecer el tiempo transcurrido (valor de un contador) desde que se
    # empieza a mostrar el mensaje de colisión de los rectángulos delimitadores
    # de los sprites de Jumpman y un barril, y el que debe transcurrir hasta
    # que se deje de mostrar dicho mensaje.
    contador_inicio_mostrar_mensaje = 0
    contador_fin_mostrar_mensaje = 75
    # Hacer que suene el sonido del juego.
    canal1.play(sonido_juego, -1)
    # Reloj para ejecutar el videojuego.
    reloj = pygame.time.Clock()
    # El juego se ejecutará a 60 frames por segundo.
    fps = 60
    while True:
        # Ejecutar el siguiente frame.
        reloj.tick(fps) 
        # Escuchar cada uno de los eventos de la lista de eventos de Pygame.
        for evento in pygame.event.get():
            # Finalizar el juego cuando se produzca el evento de terminación
            # del programa (cierre de la ventana).
            if evento.type == pygame.QUIT:
                pygame.quit()
                return
        if jumpman_vivo:
            # Comprobar si Jumpman colisiona con algún barril.
            barril_colisionado = pygame.sprite.spritecollide(jumpman,
                                                    grupo_barriles,
                                                    False,
                                                    pygame.sprite.collide_mask)
            if len(barril_colisionado) > 0:
                colision_mask = True
                canal2.play(sonido_morir)
                jumpman.y += grupo_barriles.sprites()[0].rect.center[1] -     \
                             jumpman.rect.center[1]
                jumpman.morir()
                jumpman_vivo = False
            else:
                # Obtener la lista de teclas pulsadas y gestión de las mismas.
                teclas = pygame.key.get_pressed()
                # Movimiento horizontal (tanto si Jumpman está en el suelo como
                # si está saltando).
                if en_suelo:
                    vel_x = 3
                    if teclas[pygame.K_LEFT]:
                        canal2.play(sonido_andar)
                        sentido = 'IZQUIERDA'
                        jumpman.mover('ANDAR', sentido, 2, -vel_x, 1)
                        finalizar_mover = True
                    elif teclas[pygame.K_RIGHT]:
                        canal2.play(sonido_andar)
                        sentido = 'DERECHA'
                        jumpman.mover('ANDAR', sentido, 2, vel_x, 0)
                        finalizar_mover = True
                elif en_salto:
                    jumpman.mover('SALTAR', sentido, 2,
                                  sentido_salto * 6, vel_y)
                # Salto.
                if teclas[pygame.K_SPACE] and en_suelo:
                    canal2.play(sonido_saltar)
                    vel_x = 0
                    vel_y = -altura_salto
                    jumpman.mover('SALTAR', sentido, 1, vel_x, -altura_salto)
                    en_suelo = False
                    en_salto = True
                    # Guardar el sentido en el que se inicia el salto.
                    if teclas[pygame.K_LEFT]:
                        sentido_salto = -1
                    elif teclas[pygame.K_RIGHT]:
                        sentido_salto = 1
                    else:
                        sentido_salto = 0
                # Aplicar gravedad.
                vel_y += gravedad
                # Comprobar si colisiona con algún tramo del piso en el que
                # está, tanto cuando anda como cuando salta.
                tramos_colision = pygame.sprite.groupcollide(grupo_jumpman,
                                                             grupo_tramos_1,
                                                             False, False)
                if len(tramos_colision) > 0:
                    vel_x = 0
                    # Colisión con el suelo.
                    if en_suelo:
                        jumpman.mover('ANDAR', sentido, 2, vel_x, -1)
                    elif en_salto: 
                        jumpman.mover('SALTAR', sentido, 1, vel_x,
                                      tramos_colision[jumpman][0].
                                      rect.top -
                                      jumpman.rect.bottom -
                                      tramo.alto_tramo // 2 - 1)
                    finalizar_mover = True
                    vel_y = 0
                    en_suelo = True
                    en_salto = False
                elif jumpman.rect.bottomright[0]<=grupo_tramos_1.sprites()[0].\
                                                  rect.topleft[0] or          \
                    jumpman.rect.bottomleft[0]>=grupo_tramos_1.sprites()[-1]. \
                                                  rect.topright[0]:
                    vel_x = 0
                    jumpman.mover('ANDAR', sentido, 1, vel_x, 3)
                    # Comprobar si colisiona con algún tramo del piso
                    # inmediatamente inferior al que está.
                    tramos_colision = pygame.sprite.groupcollide(grupo_jumpman,
                                                                grupo_tramos_0,
                                                                False, False)
                    if len(tramos_colision) > 0:
                        canal2.play(sonido_morir)
                        jumpman.morir()
                        jumpman_vivo = False
                    elif jumpman.rect.bottom > 475:
                        canal2.play(sonido_morir)
                        grupo_jumpman.remove(jumpman)
                        jumpman_vivo = False
                # Animar movimientos de Jumpman.
                if finalizar_mover:
                    if contador_inicio_mover > contador_fin_mover:
                        jumpman.finalizar_mover()
                        contador_inicio_mover = 0
                        finalizar_mover = False
                    else:
                        contador_inicio_mover += 1
                # Hacer que Donkey Kong tire barriles.
                if contador_inicio_imagen_donkey_kong >                           \
                    contador_fin_imagen_donkey_kong:
                    donkey_kong.animar(imagen_donkey_kong)
                    imagen_donkey_kong += 1
                    if imagen_donkey_kong > 4:
                        imagen_donkey_kong = 2
                        barril_tirado = True
                    contador_inicio_imagen_donkey_kong = 0
                else:
                    contador_inicio_imagen_donkey_kong += 1
                # Comprobar si Donkey Kong ha tirado un barril para crear la
                # instancia correspondiente.
                if barril_tirado:
                    barril = Barril(2, 250, 200)
                    grupo_barriles.add(barril)
                    barril_tirado = False
                # Animar barriles.
                # Comprobar si los barriles colisionan con algún tramo de un
                # piso.
                for barril_arrojado in grupo_barriles:
                    tramos_colision_2 = pygame.sprite.groupcollide(
                                                                grupo_barriles,
                                                                grupo_tramos_2,
                                                                False, False)
                    tramos_colision_1 = pygame.sprite.groupcollide(
                                                                grupo_barriles,
                                                                grupo_tramos_1,
                                                                False, False)
                    if barril_arrojado in tramos_colision_2:
                        barril_arrojado.caer(3, 0)
                    elif barril_arrojado in tramos_colision_1:
                        barril_arrojado.piso = 1
                        barril_arrojado.caer(-3, 0)
                    else:
                        if barril_arrojado.piso == 2:
                            if barril.rect.center[0] <= 625:
                                barril_arrojado.caer(3, 1)
                            else:
                                barril_arrojado.caer(1, 3)
                        elif barril_arrojado.piso == 1:
                            if barril_arrojado.rect.center[0] <= 0:
                                grupo_barriles.remove(barril_arrojado)
                            else:
                                barril_arrojado.caer(-3, 1)
            # Actualizar sprites.
            grupo_tramos_0.update()
            grupo_tramos_1.update()
            grupo_tramos_2.update()
            grupo_donkey_kong.update()
            grupo_barriles.update()
            grupo_jumpman.update()
            # Copiar la imagen de fondo de la ventana en el canvas que la
            # mostrará.
            ventana.blit(fondo, (0, 0))
            # Textos indicativos de si se ha producido la colisión de los
            # rectángulos delimitadores de ambos sprites y de si se ha producido la
            # colisión de sus máscaras.
            if pygame.sprite.spritecollide(jumpman, grupo_barriles, False):
                colision_rect = True
                texto_colision_rect = font_emulogic_12.render(
                                      'Colision rectangulos delimitadores.'  +
                                      'Jumpman NO MUERE.',
                                       1, (255, 0, 0), (0, 0, 0))
            else:
                texto_no_colision_rect = font_emulogic_12.render(
                                      'NO han colisionado los rectangulos '   +
                                      'delimitadores.',
                                       1, (34, 177, 76), (0, 0, 0))
            if colision_rect:
                if contador_inicio_mostrar_mensaje >                          \
                    contador_fin_mostrar_mensaje:
                    contador_inicio_mostrar_mensaje = 0
                    colision_rect = False
                else:
                    ventana.blit(texto_colision_rect, (35, 340))
                    contador_inicio_mostrar_mensaje += 1
            else:
                ventana.blit(texto_no_colision_rect, (35, 340))
            if colision_mask:
                texto_colision_mask = font_emulogic_12.render(
                                      'Colision mascaras de ambos sprites.'  +
                                      'Jumpman MUERE.',
                                       1, (255, 0, 0), (0, 0, 0))
            else:
                texto_colision_mask = font_emulogic_12.render(
                                      'NO han colisionado las mascaras de '   +
                                      'ambos sprites.',
                                       1, (34, 177, 76), (0, 0, 0))
            ventana.blit(texto_colision_mask, (35, 365))
            # Dibujar sprites.
            grupo_tramos_0.draw(ventana)
            grupo_tramos_1.draw(ventana)
            grupo_tramos_2.draw(ventana)
            grupo_donkey_kong.draw(ventana)
            grupo_barriles.draw(ventana)
            grupo_jumpman.draw(ventana)
            # Mostrar la ventana dibujada (cambiar buffers, buffer pantalla a
            # disponible para dibujar y viceversa.
            pygame.display.flip()
        else:
            pygame.time.wait(3000)
            canal1.play(sonido_game_over, -1)
            imagen_donkey_kong = 5
            while True:
                # Ejecutar el siguiente frame.
                reloj.tick(fps) 
                # Escuchar cada uno de los eventos de la lista de eventos de
                # Pygame.
                for evento in pygame.event.get():
                    # Finalizar el juego cuando se produzca el evento de
                    # terminación del programa (cierre de la ventana).
                    if evento.type == pygame.QUIT:
                        pygame.quit()
                        return
                if contador_inicio_imagen_donkey_kong >                       \
                    contador_fin_imagen_donkey_kong:
                    donkey_kong.animar(imagen_donkey_kong)
                    imagen_donkey_kong += 1
                    if imagen_donkey_kong > 6:
                        imagen_donkey_kong = 5
                    contador_inicio_imagen_donkey_kong = 0
                else:
                    contador_inicio_imagen_donkey_kong += 1
                # Actualizar sprites.
                grupo_donkey_kong.update()
                # Copiar la imagen de fondo de la ventana en el canvas que la
                # mostrará.
                ventana.blit(fondo, (0, 0))
                # Dibujar sprites.
                grupo_tramos_0.draw(ventana)
                grupo_tramos_1.draw(ventana)
                grupo_tramos_2.draw(ventana)
                grupo_donkey_kong.draw(ventana)
                grupo_jumpman.draw(ventana)
                # Visualizar texto 'Game Over'.
                texto_game_over = font_emulogic_48.render('Game Over', 1,
                                                        (255, 0, 0), (0, 0, 0))
                ventana.blit(texto_game_over, (115, 200))
                # Mostrar la ventana dibujada (cambiar buffers, buffer pantalla
                # a disponible para dibujar y viceversa.
                pygame.display.flip()
            
    pygame.quit()


if __name__ == '__main__':
    donkey_kong()
En la ejecución del script que se muestra a continuación podemos observar que en el primer salto no se produce ningún tipo de colisión entre el sprite de Jumpman y el del barril que salta, mientras que en el segundo sólo se produce la colisión de los rectángulos delimitadores de ambos sprites, es decir, no se produce la colisión de sus máscaras (formas), por lo que Jumpan sigue vivo. Finalmente, cuando se encuentra parado, sí se produce la colisión de sus máscaras (lógicamente y de forma previa, también la de sus rectángulos delimitadores), por lo que Jumpman muere.
 Quizás también te interese:

Comentarios

Entradas populares de este blog

Criptografía (I): cifrado Vigenère y criptoanálisis Kasiski

Hace unos días mi amigo Iñaki Regidor ( @Inaki_Regidor ), a quien dedico esta entrada :), compartió en las redes sociales un post titulado "Criptografía: el arte de esconder mensajes"  publicado en uno de los blogs de EiTB . En ese post se explican ciertos métodos clásicos para cifrar mensajes , entre ellos el cifrado de Vigenère , y , al final del mismo, se propone un reto consistente en descifrar un mensaje , lo que me ha animado a escribir este post sobre el método Kasiski  para atacar un cifrado polialfabético ( conociendo la clave descifrar el mensaje es muy fácil, pero lo que contaré en este post es la forma de hacerlo sin saberla ). El mensaje a descifrar es el siguiente: LNUDVMUYRMUDVLLPXAFZUEFAIOVWVMUOVMUEVMUEZCUDVSYWCIVCFGUCUNYCGALLGRCYTIJTRNNPJQOPJEMZITYLIAYYKRYEFDUDCAMAVRMZEAMBLEXPJCCQIEHPJTYXVNMLAEZTIMUOFRUFC Como ya he dicho el método de Vigenère es un sistema de sustitución polialfabético , lo que significa que, al contrario que en un sistema...

¿Qué significa el emblema de la profesión informática? (I)

Todas o muchas profesiones tienen un emblema que las representa simbólicamente y en el caso de la  informática: " es el establecido en la resolución de 11 de noviembre de 1977  para las titulaciones universitarias superiores de informática, y  está constituido por una figura representando en su parte central  un  núcleo toroidal de ferrita , atravesado por  hilos de lectura,  escritura e inhibición . El núcleo está rodeado por  dos ramas : una  de  laurel , como símbolo de recompensa, y la otra, de  olivo , como  símbolo de sabiduría. La  corona  será la  de la casa real  española,  y bajo el escudo se inscribirá el acrónimo de la organización. ". Veamos los diferentes elementos tomando como ejemplo el emblema del COIIE/EIIEO (Colegio Oficial de Ingenieros en Informática del País Vasco/ Euskadiko Informatikako Ingeniarien Elkargo Ofiziala ) . Pero no sólo el COIIE/EIIEO adopta el emblem...

Criptografía (XXIII): cifrado de Hill (I)

En este post me propongo explicar de forma comprensible lo que he entendido sobre el cifrado de Hill , propuesto por el matemático Lester S. Hill , en 1929, y que se basa en emplear una matriz como clave  para cifrar un texto en claro y su inversa para descifrar el criptograma correspondiente . Hay tres cosas que me gustan de la criptografía clásica, además de que considero que ésta es muy didáctica a la hora de comprender los sistemas criptográficos modernos: la primera de ellas es que me "obliga" a repasar conceptos de matemáticas aprendidos hace mucho tiempo y, desgraciadamente, olvidados también hace demasiado tiempo, y, por consiguiente, que, como dice  Dani , amigo y coautor de este blog, me "obliga" a hacer "gimnasia mental"; la segunda es que, en la mayoría de las ocasiones, pueden cifrarse y descifrase los mensajes, e incluso realizarse el criptoanálisis de los criptogramas, sin más que un simple lápiz y papel, es decir, para mi es como un pasat...