-
Notifications
You must be signed in to change notification settings - Fork 0
Home
Log de experimento sobre los píxeles en modo texto, usando los caracteres unicode de Braile
A través de redes sociales me enteré de este pull-request que se hizo al kernel de linux: https://github.com/torvalds/linux/pull/1290
Echando un vistazo a los ficheros, vi estos asombrosos dibujos ASCII... en modo texto!!
⠀⠀⠀ ⠀⠀⠀⠀⢠⠴⠫⠩⠳⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⣠⠖⠏⠅⠅⠅⠅⠅⠝⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⢀⡴⠏⠅⠅⠅⠅⠅⠅⠅⠅⠅⠅⠝⢦⡀⠀⠀⠀⠀⠀⠀
⠀⠀⣸⠩⠨⠨⠨⠨⠨⠨⠨⠨⠨⠨⠨⠨⠨⠨⠳⡄⠀⠀⠀⠀
⠀⢀⡯⠨⠨⠨⠈⡈⠨⡈⡈⡈⣈⡈⠈⡈⡈⡈⡈⡇⠀⠀⠀⠀
⠀⢸⡨⡪⡪⠊⠴⠿⡌⠪⡨⡂⣿⡿⠖⠈⠪⡪⡨⡻⣦⡀⠀⠀⠀
⣠⡯⡪⡊⡰⠿⠹⠿⢿⣦⣈⣂⣿⡿⠿⠿⠷⠈⡪⡪⡨⣳⠀⠀⠀
⡯⡪⡨⡂⢰⡇⠘⠃⢰⡟⣿⣿⢳⡆⠘⠃⢸⡆⠨⡪⡪⣺⠀⠀⠀
⣯⡪⡪⡂⣜⠧⠀⠀⠜⣡⣶⣶⡘⠧⠀⠀⠴⠃⢐⢕⢅⢵⠃⠀⠀
⠘⢮⡨⡢⠈⡻⣧⣻⣿⣯⣙⣋⣽⣿⣿⡏⠠⠪⡨⣪⡾⠁⠀⠀⠀
⠀⠀⠉⠉⡯⡪⡂⠈⡙⡛⠛⠛⠛⡛⡋⡀⠨⡪⣺⠁⠀⠀⠀⠀⠀
⠀⣀⣀⣠⡯⡈⠀⣊⡪⠈⠒⠗⠊⢈⣈⣂⠈⡊⡯⠤⣄⠀⠀⠀⠀
⢸⣱⣿⣷⡌⢰⣿⣿⣿⣄⠀⠀⢰⣿⣿⣿⣧⢊⣾⣿⣿⠀⠀⠀⠀
⠸⣝⣿⣟⣃⢸⣿⣿⣿⣿⠀⠀⣿⣿⣿⣿⣿⣨⠿⠿⠟⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠹⢿⣿⣿⡿⠓⠒⠒⠿⣿⣿⡿⠋⠀⠀⠀⠀⠀⠀
⠸⢾⣿⣿⣿⣧⠰⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⢮⢃⣾⣿⣿⠀⠀
⠀⠀⣺⣿⣿⣿⠄⢃⡀⠀⠀⠀⢀⣀⡀⠀⠀⢀⠀⠠⠀⡀⠸⢃⣾⣿⠋⠉⠀⠀
⡀⢉⠿⠛⠉⣰⣼⣶⠍⡠⡾⢠⣷⣿⣿⣥⠀⠸⣖⡈⣦⣍⠲⣌⠻⢿⣷⢢⢀⣀
⣴⠀⢂⣤⣿⣿⠿⠁⡐⠞⠃⠨⣿⣽⣿⣻⡇⣾⡿⢇⠘⢽⣷⡈⢚⡆⠉⡚⣸⣿
⡋⠠⡀⠻⠟⠫⠁⠠⠜⠁⠂⠘⠱⢿⣿⣿⡇⢹⡟⠝⠘⠂⠙⠍⠀⠡⠀⠀⠻⠿
⢁⢟⣧⡀⠀⠂⢀⣠⣶⣶⣧⠰⣿⣿⣿⣿⡇⣸⣿⣷⢰⣷⣶⣦⡀⠀⢡⡶⠀⠿
⢬⣾⣿⣷⡎⣰⣿⣿⣿⣿⣿⣆⢳⣼⣿⣿⡇⢻⣿⠇⣼⣿⣿⣿⣿⣦⡀⠮⢁⠰
⣿⣿⣿⣿⠁⣿⣿⡿⠟⠛⠛⠿⣦⠹⣿⣿⢡⡘⢋⣴⡿⠿⠛⠻⠿⣿⡇⠘⡭⡀
⣟⣽⣿⣿⠸⠛⢁⣤⠠⠄⠀⠀⢨⣿⣦⣥⣾⣿⣿⣥⡄⠠⠀⠀⠀⣈⢑⠀⣿⠃
⢿⣿⣿⣿⢸⣦⣹⣿⣆⠰⠾⣦⣿⣿⣿⣿⣿⣿⣿⣿⣿⣄⠰⠿⣳⣧⣿⠀⢸⣶
⠊⢿⣿⣿⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⢸⣿
⠐⠘⣿⣿⡈⣿⣿⣿⣿⣏⣛⠿⣿⣿⣿⣿⣿⣿⣿⣿⡿⢿⣋⣽⣿⣿⣿⠁⢸⡾
⠀⠀⠙⣿⣇⢹⣿⣿⣿⣿⣿⣿⣿⣶⣾⣿⣿⣶⣶⣿⣿⣿⣿⣿⣿⣿⠏⠀⣎⡟
⣀⠠⣲⠀⠙⠂⠻⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠟⠋⠁⠀⠠⠊⠀
⣿⡇⣿⠀⠀⠀⠀⠀⠀⠈⠉⠉⢉⡹⣿⣿⡟⣉⠉⠉⠀⠀⠀⠀⠀⠀⠀⠀⢰⣥
⢀⢨⢪⢪⢪⠪⠪⠊⠌⡐⢐⢀⠂⠔⡀⡂⢂⠂⡂⡐⡐⠠⠁⠅⠣⠱⡑⡕⢔⢄
⢕⢕⠅⠇⠊⠄⠡⠨⠐⡐⢐⠐⣈⢄⠂⠀⠂⢐⣐⠐⠠⠡⠁⠅⠌⡐⡈⠌⠢⡣
⠕⠡⠈⠄⠅⠌⠨⠠⢁⢂⠂⢄⡾⣇⢠⣿⣳⡄⣟⣧⠈⠄⠅⠅⡁⡂⠔⡈⡐⠠
⠨⠠⠡⠡⠨⠈⠄⠅⡂⢂⠂⢺⢯⣏⠘⠗⠟⢈⣷⡻⠆⠡⢈⠂⡂⢂⠡⢐⠠⢁
⡠⠡⠨⠠⠡⠨⠈⠔⠠⠡⠨⠀⠻⠽⠳⠖⠖⣟⠾⠝⠀⡁⠂⡂⢂⢁⠂⡂⠌⠄
⡪⡢⡡⠈⠄⢁⠈⡀⠂⡀⠂⡈⠀⠄⠂⡀⠂⡀⠠⠀⠂⡀⠂⠠⠀⠄⠂⡀⠅⢬
⡪⣊⠆⠐⡀⡢⡐⡐⢔⢐⠅⡢⠁⠄⡁⠄⠂⡐⢀⠁⡂⠐⢈⠠⠁⠄⠁⠄⠠⢸
⡪⡪⢂⣐⣀⠂⠊⡈⠢⠑⠌⠢⠂⢁⠀⢂⠁⠄⠂⠐⠠⢈⠠⠐⠀⠅⠨⢀⠡⡴
⡪⢊⢼⣫⢾⣸⢣⢲⢲⢱⠈⡢⠪⠠⠨⠠⡐⠠⠡⡈⠢⢐⠐⡜⢈⠨⠂⠢⡀⢝
⢊⢰⢿⢸⠇⡏⣮⢿⣽⡡⡁⡆⠡⠡⢑⠠⠂⠡⢑⠐⠡⢁⠂⡑⠅⡂⡂⠡⡂⢨
⠌⣞⡯⠸⡁⡂⣽⣛⡾⠯⡢⠸⣪⠨⠠⡈⠌⠪⡀⠌⢌⠐⠄⠨⡂⢠⠨⠂⢶⠐
⢇⢇⠣⢁⠂⠄⠷⠻⠻⠻⡯⣧⣝⢽⣪⡶⣵⡥⡿⠼⠢⠱⠥⠨⡐⡜⠖⡩⠀⢨
⠕⡕⡨⠐⠨⢀⢱⣽⢍⠔⣮⡳⣟⣿⢯⡿⣯⢯⠔⠜⣽⣽⣖⠐⠄⡂⢇⠂⠅⡰
⢗⠌⠄⠅⡨⠐⢬⡻⣾⣼⣾⣿⣟⣿⣻⣟⣿⣧⣷⣳⣿⣿⡯⡈⡂⠆⡑⠨⢈⢎
⢡⢃⠨⠐⠠⠈⠄⠯⣷⣻⡾⣷⡿⣯⣿⢿⣽⣾⢯⣟⣾⣳⡏⠢⢐⢀⢂⢰⢑⠕
⢑⠡⡂⢍⠪⢢⡥⣦⢝⡷⣟⣿⣻⣿⣽⣿⣻⣾⣿⣽⡾⣷⠣⣑⠵⠊⠔⡡⠡⡑
⢂⡣⡊⢆⢃⢐⠅⠙⢿⡿⣿⣻⣯⣗⣖⣽⣽⣷⡿⣷⡿⢋⠂⠔⠀⠅⡂⠪⠨⡂
⢑⢌⠌⢆⢑⢅⡊⠄⠂⢉⠛⠿⣽⢿⣯⡿⣷⢟⠫⠁⠂⡐⢈⠠⡈⡐⠠⠈⢌⠢
⡑⡔⡱⢑⢑⠔⡄⠇⡅⡡⡀⡂⢆⢫⢫⢩⡢⡕⡅⢈⢐⠀⢐⠀⠂⠄⠅⡊⠠⣁
En el pull-request hay muchos más. Examinándolos con más detalle vi que estaban hecho a partir de los bloques de braile del código unicode: https://www.compart.com/en/unicode/block/U+2800
Esto me ha dado la idea de hacer una pantalla en modo texto, con esos píxeles. Y poder así dibujar líneas y hacer animaciones en modo texto pero con más resolución. Ofrece todo un mundo de posibilidades
El objetivo de este proyecto, y de este log, es estudiar estos bloques y hacer experimentos para implementar una pantalla gráfica con estos píxeles, pero en modo texto
Los dibujos del kernel los he metido como cadenas en este ejemplo, y se imprimen en el terminal, usando la biblioteca curses
- Fichero: Ej-01-cute.py
#!/usr/bin/env python3
# ──────────────────────────────────────────────────────
# ── Impresion de dibujos en modo texto
# ──────────────────────────────────────────────────────
import curses
import time
# ──────────────────────────────────────────────────────
# ── Dibujar y esperar
# ──────────────────────────────────────────────────────
def show(dibujo):
stdscr.clear()
stdscr.addstr(dibujo)
stdscr.refresh()
time.sleep(WAIT)
# ─── Tiempo de espera en segundos
WAIT = 1
# ────── Constantes para determinar la visibilidad del cursor
ON = 2
OFF = 0
# ────── Inicializacion
stdscr = curses.initscr()
# ── Ocultar el cursor
curses.curs_set(OFF)
# ── Definicion de los dibujos
dibujo1 = """\
⠀⠀⠀⠀⢠⠴⠫⠩⠳⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⣠⠖⠏⠅⠅⠅⠅⠅⠝⢦⡀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⢀⡴⠏⠅⠅⠅⠅⠅⠅⠅⠅⠅⠅⠝⢦⡀⠀⠀⠀⠀⠀⠀
⠀⠀⣸⠩⠨⠨⠨⠨⠨⠨⠨⠨⠨⠨⠨⠨⠨⠨⠳⡄⠀⠀⠀⠀
⠀⢀⡯⠨⠨⠨⠈⡈⠨⡈⡈⡈⣈⡈⠈⡈⡈⡈⡈⡇⠀⠀⠀⠀
⠀⢸⡨⡪⡪⠊⠴⠿⡌⠪⡨⡂⣿⡿⠖⠈⠪⡪⡨⡻⣦⡀⠀⠀⠀
⣠⡯⡪⡊⡰⠿⠹⠿⢿⣦⣈⣂⣿⡿⠿⠿⠷⠈⡪⡪⡨⣳⠀⠀⠀
⡯⡪⡨⡂⢰⡇⠘⠃⢰⡟⣿⣿⢳⡆⠘⠃⢸⡆⠨⡪⡪⣺⠀⠀⠀
⣯⡪⡪⡂⣜⠧⠀⠀⠜⣡⣶⣶⡘⠧⠀⠀⠴⠃⢐⢕⢅⢵⠃⠀⠀
⠘⢮⡨⡢⠈⡻⣧⣻⣿⣯⣙⣋⣽⣿⣿⡏⠠⠪⡨⣪⡾⠁⠀⠀⠀
⠀⠀⠉⠉⡯⡪⡂⠈⡙⡛⠛⠛⠛⡛⡋⡀⠨⡪⣺⠁⠀⠀⠀⠀⠀
⠀⣀⣀⣠⡯⡈⠀⣊⡪⠈⠒⠗⠊⢈⣈⣂⠈⡊⡯⠤⣄⠀⠀⠀⠀
⢸⣱⣿⣷⡌⢰⣿⣿⣿⣄⠀⠀⢰⣿⣿⣿⣧⢊⣾⣿⣿⠀⠀⠀⠀
⠸⣝⣿⣟⣃⢸⣿⣿⣿⣿⠀⠀⣿⣿⣿⣿⣿⣨⠿⠿⠟⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠹⢿⣿⣿⡿⠓⠒⠒⠿⣿⣿⡿⠋⠀⠀⠀⠀⠀⠀
"""
dibujo2 = """\
⠸⢾⣿⣿⣿⣧⠰⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⢮⢃⣾⣿⣿⠀⠀
⠀⠀⣺⣿⣿⣿⠄⢃⡀⠀⠀⠀⢀⣀⡀⠀⠀⢀⠀⠠⠀⡀⠸⢃⣾⣿⠋⠉⠀⠀
⡀⢉⠿⠛⠉⣰⣼⣶⠍⡠⡾⢠⣷⣿⣿⣥⠀⠸⣖⡈⣦⣍⠲⣌⠻⢿⣷⢢⢀⣀
⣴⠀⢂⣤⣿⣿⠿⠁⡐⠞⠃⠨⣿⣽⣿⣻⡇⣾⡿⢇⠘⢽⣷⡈⢚⡆⠉⡚⣸⣿
⡋⠠⡀⠻⠟⠫⠁⠠⠜⠁⠂⠘⠱⢿⣿⣿⡇⢹⡟⠝⠘⠂⠙⠍⠀⠡⠀⠀⠻⠿
⢁⢟⣧⡀⠀⠂⢀⣠⣶⣶⣧⠰⣿⣿⣿⣿⡇⣸⣿⣷⢰⣷⣶⣦⡀⠀⢡⡶⠀⠿
⢬⣾⣿⣷⡎⣰⣿⣿⣿⣿⣿⣆⢳⣼⣿⣿⡇⢻⣿⠇⣼⣿⣿⣿⣿⣦⡀⠮⢁⠰
⣿⣿⣿⣿⠁⣿⣿⡿⠟⠛⠛⠿⣦⠹⣿⣿⢡⡘⢋⣴⡿⠿⠛⠻⠿⣿⡇⠘⡭⡀
⣟⣽⣿⣿⠸⠛⢁⣤⠠⠄⠀⠀⢨⣿⣦⣥⣾⣿⣿⣥⡄⠠⠀⠀⠀⣈⢑⠀⣿⠃
⢿⣿⣿⣿⢸⣦⣹⣿⣆⠰⠾⣦⣿⣿⣿⣿⣿⣿⣿⣿⣿⣄⠰⠿⣳⣧⣿⠀⢸⣶
⠊⢿⣿⣿⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡄⢸⣿
⠐⠘⣿⣿⡈⣿⣿⣿⣿⣏⣛⠿⣿⣿⣿⣿⣿⣿⣿⣿⡿⢿⣋⣽⣿⣿⣿⠁⢸⡾
⠀⠀⠙⣿⣇⢹⣿⣿⣿⣿⣿⣿⣿⣶⣾⣿⣿⣶⣶⣿⣿⣿⣿⣿⣿⣿⠏⠀⣎⡟
⣀⠠⣲⠀⠙⠂⠻⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠟⠋⠁⠀⠠⠊⠀
⣿⡇⣿⠀⠀⠀⠀⠀⠀⠈⠉⠉⢉⡹⣿⣿⡟⣉⠉⠉⠀⠀⠀⠀⠀⠀⠀⠀⢰⣥
"""
dibujo3 = """\
⢀⢨⢪⢪⢪⠪⠪⠊⠌⡐⢐⢀⠂⠔⡀⡂⢂⠂⡂⡐⡐⠠⠁⠅⠣⠱⡑⡕⢔⢄
⢕⢕⠅⠇⠊⠄⠡⠨⠐⡐⢐⠐⣈⢄⠂⠀⠂⢐⣐⠐⠠⠡⠁⠅⠌⡐⡈⠌⠢⡣
⠕⠡⠈⠄⠅⠌⠨⠠⢁⢂⠂⢄⡾⣇⢠⣿⣳⡄⣟⣧⠈⠄⠅⠅⡁⡂⠔⡈⡐⠠
⠨⠠⠡⠡⠨⠈⠄⠅⡂⢂⠂⢺⢯⣏⠘⠗⠟⢈⣷⡻⠆⠡⢈⠂⡂⢂⠡⢐⠠⢁
⡠⠡⠨⠠⠡⠨⠈⠔⠠⠡⠨⠀⠻⠽⠳⠖⠖⣟⠾⠝⠀⡁⠂⡂⢂⢁⠂⡂⠌⠄
⡪⡢⡡⠈⠄⢁⠈⡀⠂⡀⠂⡈⠀⠄⠂⡀⠂⡀⠠⠀⠂⡀⠂⠠⠀⠄⠂⡀⠅⢬
⡪⣊⠆⠐⡀⡢⡐⡐⢔⢐⠅⡢⠁⠄⡁⠄⠂⡐⢀⠁⡂⠐⢈⠠⠁⠄⠁⠄⠠⢸
⡪⡪⢂⣐⣀⠂⠊⡈⠢⠑⠌⠢⠂⢁⠀⢂⠁⠄⠂⠐⠠⢈⠠⠐⠀⠅⠨⢀⠡⡴
⡪⢊⢼⣫⢾⣸⢣⢲⢲⢱⠈⡢⠪⠠⠨⠠⡐⠠⠡⡈⠢⢐⠐⡜⢈⠨⠂⠢⡀⢝
⢊⢰⢿⢸⠇⡏⣮⢿⣽⡡⡁⡆⠡⠡⢑⠠⠂⠡⢑⠐⠡⢁⠂⡑⠅⡂⡂⠡⡂⢨
⠌⣞⡯⠸⡁⡂⣽⣛⡾⠯⡢⠸⣪⠨⠠⡈⠌⠪⡀⠌⢌⠐⠄⠨⡂⢠⠨⠂⢶⠐
⢇⢇⠣⢁⠂⠄⠷⠻⠻⠻⡯⣧⣝⢽⣪⡶⣵⡥⡿⠼⠢⠱⠥⠨⡐⡜⠖⡩⠀⢨
⠕⡕⡨⠐⠨⢀⢱⣽⢍⠔⣮⡳⣟⣿⢯⡿⣯⢯⠔⠜⣽⣽⣖⠐⠄⡂⢇⠂⠅⡰
⢗⠌⠄⠅⡨⠐⢬⡻⣾⣼⣾⣿⣟⣿⣻⣟⣿⣧⣷⣳⣿⣿⡯⡈⡂⠆⡑⠨⢈⢎
⢡⢃⠨⠐⠠⠈⠄⠯⣷⣻⡾⣷⡿⣯⣿⢿⣽⣾⢯⣟⣾⣳⡏⠢⢐⢀⢂⢰⢑⠕
⢑⠡⡂⢍⠪⢢⡥⣦⢝⡷⣟⣿⣻⣿⣽⣿⣻⣾⣿⣽⡾⣷⠣⣑⠵⠊⠔⡡⠡⡑
⢂⡣⡊⢆⢃⢐⠅⠙⢿⡿⣿⣻⣯⣗⣖⣽⣽⣷⡿⣷⡿⢋⠂⠔⠀⠅⡂⠪⠨⡂
⢑⢌⠌⢆⢑⢅⡊⠄⠂⢉⠛⠿⣽⢿⣯⡿⣷⢟⠫⠁⠂⡐⢈⠠⡈⡐⠠⠈⢌⠢
⡑⡔⡱⢑⢑⠔⡄⠇⡅⡡⡀⡂⢆⢫⢫⢩⡢⡕⡅⢈⢐⠀⢐⠀⠂⠄⠅⡊⠠⣁
"""
dibujo4 = """\
⣿⣿⣿⠿⣿⡵⡀⣀⠁⠘⠛⠛⠛⠓⠒⠒⠂⠤⠀⠐⠶⣤⣄⡀⠀⠀⠀⠀⠀⠀
⣿⣿⡇⠀⢀⣬⣷⣿⠟⠉⠀⠴⠚⠍⠟⠛⠓⠒⠂⠀⠀⠐⠫⢭⡙⠲
⠿⠎⠃⠘⠛⢻⠟⠁⠀⠀⠀⠀⠀⠀⣀⣀⣀⣤⡠⢀⡆⠀⠀⢿⣶⡄⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠁⠀⢀⣤⢀⣴⣿⣱⣾⣿⣿⣿⢹⣿⢸⣷⠀⠀⠀⡽⡿⡄⠀⠀⠀
⠀⠀⠀⠀⠀⠀⣰⣿⣷⣾⣧⣬⡙⣿⣿⣿⣿⡀⣿⡌⠙⠀⠀⠀⠻⠈⠁⠀⠀⠀
⡠⠀⠂⠀⠀⠠⠟⠛⠛⠻⣿⣿⣿⣿⣿⣿⣿⣷⣿⣷⡀⠀⠀⡄⠀⠂⠀⠀⠀⠀
⣧⡞⠀⡠⣦⡄⠀⠀⢀⣀⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⢷⠄⠀⣧⠀⠀⠀⠀⠀⠀
⢰⠀⢰⣿⣿⡿⢄⣀⣶⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣦⡐⡻⠀⠀⠀⠀⠀⠀
⠀⢠⣿⣿⣿⣿⣿⣶⣾⣿⣿⣿⣿⣿⣿⣿⣿⠉⠉⠙⢿⣿⣿⡎⠀⠀⠀⠀⠀⠀
⠀⣾⣿⣿⣿⣿⣿⣿⣿⣿⣻⣿⣿⣿⣿⣿⡛⠀⠀⠀⠀⢹⡟⠀⠀⠀⠀⠀⠀⠀
⠀⢹⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣧⠣⣀⣀⡀⢦⢠⣵⠂⠀⠀⢀⡆⠀⠀
⠀⠈⣿⣿⣿⣯⢉⣻⣿⣿⣿⣿⣿⣿⣿⣿⣷⣭⣭⣶⣥⣾⣧⠂⠠⠰⡟⠀⠀⠀
⠀⠀⠘⣿⣿⣿⣿⣿⣿⡿⣿⡛⣿⣿⣿⣿⣿⣿⣿⣿⣿⠟⠁⠁⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠘⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀
⢀⣀⣄⣴⣭⣝⣻⡿⠿⠿⠿⠿⠿⠟⠛⠛⠉⠁⠀⠀⠀⠀⠀
"""
dibujo5 = """\
⡧⣾⣿⡿⣫⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣟⣿⣿⣿⣿⣷⣿⣻⣿⣮⡻⣿⣿⣿⣿
⠇⠛⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⣿⣿⣿⣿⣿⣿⣿⣿⣾⣿⣿⣞⢿⠋⠁
⣿⣻⣳⣿⣿⣿⣿⣿⣿⡿⣿⣿⣿⣿⣿⣽⣧⣿⣿⣿⣿⣿⣿⣿⣷⡽⠿⠃⠀⠀
⢾⢳⣿⣿⣿⡝⣿⣿⣿⣧⡽⣿⣿⣿⣿⣷⣻⢳⣿⣿⡿⣿⣿⣿⣭⣥⣤⣤⣶⠀
⡟⣿⣿⣿⣿⣇⣿⡇⣿⣿⣿⡵⡻⣿⣿⣿⣯⢾⣿⣿⣟⠆⡘⡿⣮⡛⡿⣿⣟⠗
⣿⣿⣿⣿⣿⡷⣿⣧⣜⠾⣿⣿⣵⣟⠿⡏⣿⣯⢿⣿⣿⠿⠎⠘⠓⠿⣬⢰⣿⣵
⣾⣿⣿⣿⣿⣿⣹⢿⣯⢸⡷⣶⣮⣥⣲⣜⢿⣿⣞⣏⡥⠒⠉⠩⠟⢧⣾⣼⡿⣿
⢿⣿⣿⣿⣿⣿⣯⡾⠟⣋⡩⠥⠤⢭⣻⣿⣿⣯⣻⢹⣄⣀⣐⣠⣤⣿⣿⣏⣿⣏
⢘⣹⣿⣿⣿⣿⣱⢴⡟⠁⠀⢄⠉⢉⣿⣿⣿⣿⣿⡿⣿⣿⣿⣿⣿⣿⣿⣿⡾⣿
⠇⢎⣿⣿⣿⣿⣿⣷⢷⣾⣼⣶⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⡿
⡕⣾⠼⣿⣿⣿⣯⢿⣟⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⢻⡾
⡹⢗⢰⣻⣿⣿⣿⣮⢿⡾⣿⣿⣿⣿⣿⣿⣿⣿⣟⣿⣿⣿⣿⣿⣿⣿⠟⠙⡾⠁
⣷⡽⣲⡢⣳⣻⣿⣿⣏⢿⡽⣿⣿⣿⣿⣿⣾⣿⣿⣿⣿⣿⣿⣿⢿⣿⡞⠇⣕⠐
⢴⠁⠀⠻⣷⣽⡽⣿⣿⣦⠿⡍⠻⣻⣿⠿⣿⣿⣿⣿⠿⠿⠋⠁⢸⣿⡇⡔⢀⣧
⣰⣾⣦⣀⠈⠻⣾⡾⢿⣿⣷⡘⠄⠉⠛⠉⠉⠛⠻⠋⠀⠀⠀⠀⢸⣿⡇⠀⢸⣿
⢸⣿⣿⣿⣷⣦⣀⠙⠳⠹⣿⣧⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣼⣿⠇⣴⠀⣿
"""
dibujo6 = """\
⣿⣿⣿⣿⣿⣿⡿⠁⠉⠉⠀⠀⠀⠈⠁⠀⠀⠀⠉⠉⠉⠉⠉⠙⠛⠻⠿⣿⣿⣿
⣿⣿⣿⣿⡿⠿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠻
⣿⣿⣿⡿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⣿⣿⡿⠁⠀⠀⠀⠀⠀⢸⣄⠀⠀⠀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⣿⡿⠀⡀⠀⠀⠀⢀⠀⠘⠟⣂⠀⠀⠓⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⣿⠃⣰⡇⠀⠀⠀⣼⡆⠀⢸⣿⣷⡀⠀⠐⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⡏⢰⣿⠁⠀⠀⠀⠿⢷⢠⢸⣴⡆⠀⣄⠀⢻⣄⢤⡀⠀⣤⠀⣴⣛⠣⡀⠀⠀⠀
⢣⣿⣿⠀⢠⡇⠀⣶⢰⡆⣾⣇⠀⠀⣿⡆⣼⣿⣿⣿⣆⢹⣸⢿⣿⣷⡄⠀⠀⠀
⣿⣿⣿⠀⣼⡇⠀⣿⢠⣧⣍⣛⡒⣒⣋⣴⣿⣿⣿⣿⣿⣷⡏⡼⠟⣋⠁⠀⠀⠀
⣿⣿⣿⢰⣿⡏⢘⣩⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣥⡶⠟⠁⠀⠀⠀⠀
⣿⣿⣿⣸⣿⣇⢣⡙⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣧⣶⣿⡄⠀⣀⠀⠀
⣿⣿⣿⣿⣿⣿⣎⠻⣿⠿⠿⢛⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⠀⣿⣷⠖
⣿⣿⣿⣿⣿⣿⣿⣷⠙⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⠀⣿⡏⣼
⣿⣿⣿⣿⣿⣿⣿⡏⠀⠀⠙⣿⣿⣿⣿⣿⣿⣿⠿⠟⠻⢿⣿⣿⣿⡇⠀⣿⡇⣿
⣿⣿⣿⣿⣿⣿⣿⡇⠀⠀⠀⠈⠛⠛⠛⠛⣩⣴⣾⣿⣿⢰⣬⡙⢿⡇⠀⣿⡇⣿
"""
dibujo7 = """\
⠀⠀⠀⠀⠀⠘⠛⠿⢧⡀⠀⡀⠀⠀⠀⠀⠀⠈⠡⠒⠃⠀⠈⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠈⢁⠒⣷⣄⠈⢦⡀⠀⠀⠀⠀⢠⡤⠶⠠⠃⢂⣠⡄⠀⠀⠀⠀
⠀⠀⠀⢀⣄⣀⣓⣉⣾⣿⣿⣷⣬⡻⣶⣄⠀⠀⠘⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀
⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣶⣤⡈⢻⣿⣿⣿⣿⣿⠄⠀⠀⠀
⠀⠀⠀⠈⢿⣿⣿⣿⣿⣿⣿⣿⣻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀
⠀⠀⠀⠀⠈⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡟⠁⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠘⣻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢿⣿⣿⣿⣿⠋⠀⢀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠐⠙⣿⣿⣭⣝⣛⣛⣛⣫⣭⣶⣿⣿⣿⡿⠋⠀⠀⠈⠘⠀⠀⠀
"""
dibujo8 = """\
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠴⠦⢀⢀⡀⠀⠀⠠⣤⣴⣶⣶⣶⣤⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣤⣶⣿⣿⣿⣿⣿⣿⣿⣿⣿⣮⣍⠉⠛⡏⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣄⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⢀⣼⣿⣿⡿⣿⡿⡃⣿⣿⣟⢿⣿⣿⣿⣿⣿⣿⣿⣿⣷⡀⠀
⠀⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⠁⡟⣝⣽⡜⣿⣯⣗⡝⢿⡻⣿⣿⣿⣿⣿⣿⣷⠀
⠀⠀⠀⠀⠀⢠⣿⣿⣿⣿⡏⣧⠹⢟⢿⣿⣷⡵⣛⣛⠷⣭⣪⢿⣿⣿⣿⣿⣿⠀
⠀⠀⠀⠀⢠⣿⣿⣿⣿⠇⠁⣕⣦⣷⣿⣿⣿⣿⣷⣧⣞⣪⣿⣾⢹⣿⣿⣿⣿⠇
⠀⠀⣀⣴⡿⣿⣿⣿⡟⠀⣧⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢯⣿⣿⣿⣿⣿⠀
⠀⠉⠉⠀⠀⢿⣿⣿⡇⠈⢿⣯⠉⠘⠛⣛⣛⢛⣂⣉⡻⣻⢫⣿⣿⣿⣿⣿⣿⠀
⠀⠀⠀⠀⠀⠘⡟⢿⡇⠀⠈⠻⣆⡾⣿⣿⣿⣿⣿⣟⣵⢧⣿⣿⣿⣿⢿⡿⠁⠄
⠀⠀⠀⠀⠀⠀⠘⠈⢿⡀⠀⠀⠈⠙⠳⠿⠿⠷⠿⠟⠛⣸⢫⡟⣿⡏⢸⠁⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠈⠳⠀⠀⠀⢀⠀⣠⣀⣀⣀⡄⠀⠃⠘⢀⠟⠀⠈⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣤⢆⢘⡇⣿⣿⣿⡿⣣⣶⢀⢀⣈⡀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⢠⣾⣿⣏⡿⡾⠿⠟⠿⢷⣿⡿⣡⡟⣿⣿⣿⣷⡄⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⣾⣿⡿⣾⠩⣖⠹⣨⢉⣮⢟⣲⣿⢻⣿⣿⣿⣿⣿⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣹⡟⢆⢋⢪⣥⠠⢿⣷⣿⣿⣾⣿⣿⣿⣿⣿⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⣿⢷⣿⣿⣷⣷⣾⣗⣠⣼⣿⣿⣿⢻⣿⣿⣿⣿⣿⠀⠀⠀
"""
dibujo9 = """\
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢳⣿⡄⠈⣿⣿⣿⣿⣿⣿⣿⣿⣿
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡸⡟⠃⠀⣿⣿⠿⠿⣿⠿⢿⣿⣿
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠿⠛⠋⠉⣀⡀⢀⣀⠙⠄⠈⠋⠈⠉⠀⠀⠀⠀⢀⣹
⣿⣿⠿⠿⠿⣿⣿⣿⢟⠥⢂⠀⠐⠈⢉⠁⠀⠀⡀⠀⠀⠀⠀⠀⠀⢀⣤⣾⣿⣿
⡿⡄⡼⢊⠛⠂⢉⡀⠀⠀⠀⣰⣿⣿⡿⣡⣿⣿⣇⣦⡀⠀⠀⠀⠀⠀⠙⣿⣿⣿
⣧⠁⠀⠋⠀⠀⠀⢠⣾⡇⣼⣿⣿⡟⣼⣿⣿⡿⣺⣿⡇⢢⠀⢀⠀⢀⠀⠘⣿⣿
⣿⡡⡂⠀⠗⢀⢀⣾⡞⣸⣿⣿⡟⣸⣿⣿⣿⢣⣿⣿⢰⣆⠁⠈⣢⡎⠀⠀⢸⣿
⣿⢇⣾⠃⠀⡞⣼⣿⢇⣿⣿⣿⢣⣿⣿⣿⡏⣾⣿⠇⣾⣿⡆⢀⠟⠁⠀⠀⠀⣿
⣿⣸⡟⠀⠀⣇⡿⢸⢸⢿⣿⢣⢸⣿⣿⠣⢰⡟⡟⣼⣿⣿⡇⠀⢤⠀⠀⠀⠀⣿
⡇⣿⠃⠀⠀⣿⡇⡏⠘⢸⡏⡄⠁⣿⠣⠀⢞⠄⣬⣭⣭⣭⠅⣴⡘⠀⠀⠀⠀⣿
⢡⣿⣴⠀⠀⢻⡇⠃⠀⠃⠘⠛⠴⢁⣷⣷⣿⣾⣿⠿⠿⠿⠸⢻⡇⣰⠀⠀⠀⣿
⢸⣿⡇⠀⠀⠈⢿⢰⣤⡀⠀⠀⢀⣾⣿⣿⣿⣿⣧⣄⠂⠀⠀⢀⢄⠃⠀⠀⢰⣿
⣿⣿⠁⠀⣰⢰⠠⡁⠙⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢃⠀⣸⠀⠀⣸⣿
⣿⣿⠀⠀⣿⢸⡀⠁⡹⡾⠛⠹⣿⣿⣛⢿⡿⢟⣻⣿⣿⣿⣵⠏⡀⣿⡆⠀⣿⣿
⣿⡇⠀⢰⣿⢸⣷⠀⣿⣦⡀⢰⣿⣿⣿⣿⣿⣿⣿⣿⡿⠛⣡⣾⡇⣿⡇⠀⣿⣿
⣿⠁⠀⣾⣿⢸⡿⢸⣿⣿⣿⣦⡈⣙⠻⢿⠿⢛⣋⢁⣴⣾⣿⣿⡇⣿⠇⠀⣿⣿
"""
dibujo10 = """\
⡏⣼⣿⣿⣿⢋⣾⣿⣿⣿⠏⠾⢿⡟⣼⣿⢸⣿⣿⣧⠹⣿⣿⠏⠶⠾⣦⢻⡇⣿
⢸⣿⣿⣿⡏⣾⣿⠟⣿⠁⣾⣿⠇⣴⢹⣿⡇⢹⣿⣿⡆⠏⣶⣿⣿⡿⢂⢸⡇⣿
⢸⣿⣿⡟⢸⡿⢫⡾⢇⣿⡶⣂⣶⣶⣾⣿⣿⡞⣿⣿⣿⠈⣶⡆⠶⣾⣿⢸⡇⣿
⣾⣿⣿⡇⠜⣤⠟⠄⠾⠛⠐⠶⢬⣹⣿⣿⣿⣷⢹⣿⣿⢸⣀⠶⠙⠛⠟⢄⡇⣿
⣿⣿⣿⠄⠊⡠⠠⠛⠁⠉⠉⡐⢠⡈⣿⣿⣿⣿⣇⢹⣿⠘⣠⠔⠉⢈⠑⢦⡁⡇
⢻⣿⣯⢰⣎⣡⣥⠄⠄⣀⢀⢀⠸⣷⣿⣿⣿⣿⣿⣇⠟⣴⣿⡀⠄⠄⠄⢸⡇⢸
⠸⣿⣿⢸⣿⡏⢩⢸⠄⠛⢰⣴⢀⣿⣿⣿⣿⣿⣿⣿⣤⣿⠏⡄⠺⣈⠄⡾⠁⣽
⣄⢻⣿⢸⣿⣿⡘⣿⣿⣿⣿⠟⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⢿⠿⣫⣾⠏⣸⢋
⣿⢠⡹⣇⠹⣿⣷⣜⣛⣛⣣⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣾⣿⡿⠘⣃⣼
⣿⡞⣷⣮⣕⠙⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡟⣴⣾⣯⣿
⣿⡇⠻⣿⣿⣿⣶⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠟⣱⣿⣿⣿⣿
⣿⡇⢷⣎⡹⠿⣿⣿⣿⣿⣿⣿⣿⣏⡉⠙⢛⣋⣵⣾⣿⣿⠿⣃⣶⠻⣿⣏⣿⣿
⣿⣇⢸⠿⣛⣥⣶⣭⣝⣛⡻⠿⢿⣿⣿⣿⡿⠿⣫⣭⣶⣶⣿⣿⣿⣷⡛⢻⣿⣿
"""
dibujo11 = """\
⣿⣿⣿⡇⣿⣿⣿⣿⣿⠘⣿⣿⣿⣿⣿⣿⣿⣿⣿⠿⡏⢸⣿⡆⣿⡇⠶⠟⣛⣩
⣿⣿⣿⠃⣿⣿⣿⣿⡿⠀⠟⢛⣛⣛⢻⣿⣿⣿⣿⢰⡇⠀⣶⠀⣦⣬⡁⢻⣿⣿
⣿⣿⣿⠀⣿⢛⣩⣴⣶⢠⢸⣿⣿⡇⢸⣿⣿⢻⡇⣼⢠⠀⣿⠀⢻⣿⡇⢸⣿⣿
⣿⣿⣿⡇⣿⣿⣿⣿⡏⢸⡘⣿⣿⠀⣿⣿⡿⢸⢁⢃⣾⠀⡿⢸⡆⣿⡇⢸⣿⣿
⣿⣿⣿⡇⢿⠃⠻⣿⡇⣸⣷⡈⡇⠂⣿⠟⡁⠀⡈⣼⣿⢀⢃⣿⣧⠘⣰⡆⠉⢿
⣿⣿⣿⡇⡈⠈⣷⣌⡃⣿⣿⣷⣀⠀⢋⣼⢃⠂⣰⣿⡿⢈⣼⣿⣿⣴⣿⡇⣸⢸
⣿⣿⣿⠁⢳⡠⠛⣛⣉⣭⣭⣍⣙⣻⣿⣷⣾⣾⣿⣿⣿⣿⣭⠤⢶⠒⠶⣬⣿⠸
⡈⣙⢛⡃⠾⠟⡋⠉⡁⢤⡀⢀⣉⡛⢿⣿⣿⣿⣿⣿⣿⣏⠀⠴⠉⠟⣸⠆⡉⢠
⣷⡦⢰⡇⣶⣀⣉⣭⣤⣬⣥⣬⣭⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⣿
⣿⠁⣼⡇⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡍⣿⣿⣿⣿⣿⣿⣿⢠⣿
⣿⠀⣿⡇⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⢸⣿
⠇⡄⢻⣷⠸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠇⣾⡟
⡄⠸⠘⣿⡇⢻⣿⣿⣿⣿⣿⣿⣿⣿⡟⠻⣿⣿⣿⣿⠟⣻⣿⣿⣿⣿⠏⡼⠟
⠓⡀⠲⣌⣉⣈⠻⢿⣿⣿⣿⣿⣿⣿⣿⣷⣬⣭⣉⣥⣾⣿⣿⣿⠟⡁⢰⡀⠶⣶
⠸⢿⡷⠀⠸⠿⣷⡆⣌⡛⠿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠟⣡⣾⣇⢸⡇⡆⣿
"""
# ── Imprimir dibujo
show(dibujo1)
show(dibujo2)
show(dibujo3)
show(dibujo4)
show(dibujo5)
show(dibujo6)
show(dibujo7)
show(dibujo8)
show(dibujo9)
show(dibujo10)
show(dibujo11)
stdscr.addstr("\nPulsa una tecla")
# ── Esperar a que el usuario apriete una tecla
stdscr.getch()
# ── Volver a enseñar el cursor antes de terminar
curses.curs_set(ON)
# ── Terminar. Volver a la pantalla original del terminal
curses.endwin()Este es el resultado:
![]()
En este experimento voy a mostrar todos los píxeles de la pantalla. En cada carácter hay 8 píxeles, situados en dos columnas. El carácter es este ⣿
- Fichero: Ej-02-screen-test.py
#!/usr/bin/env python3
# ──────────────────────────────────────────────────────
# ── Mostrando todos los pixeles de la pantalla de texto
# ──────────────────────────────────────────────────────
import curses
# ────── Constantes para determinar la visibilidad del cursor
ON = 2
OFF = 0
# ────── Inicializacion
stdscr = curses.initscr()
# ── Ocultar el cursor
curses.curs_set(OFF)
# ── Mostrar todos los píxeles de la pantalla
for y in range(23):
stdscr.addstr(y, 0, "⣿" * 80)
# ── Esperar a que el usuario apriete una tecla
stdscr.getch()
# ── Volver a enseñar el cursor antes de terminar
curses.curs_set(ON)
# ── Terminar. Volver a la pantalla original del terminal
curses.endwin()Así es como queda el terminal:
![]()
Entre línea y línea de caracteres hay una separación, pero no impiden que se pueda usar como pantalla gráfica
Vamos a empezar suponiendo que sólo tenemos una pantalla de un único carácter. Dentro de este carácter puede haber en total 8 píxeles
Para familiarizarnos con los píxeles y los códigos unicode de braile vamos a hacer algunas animaciones sencillas. Comenzamos con animaciones de 2 fotogramas, haciendo que el pixel se mueva horizontalmente por las 4 filas del carácter
- Fichero: Ej-03-pant-1x1-anim-1.py
#!/usr/bin/env python3
# ──────────────────────────────────────────────────────
# ── Pantalla 1x1. Animaciones sencillas
# ──────────────────────────────────────────────────────
import curses
import time
# ────── Tiempo de espera entre fotogramas
WAIT = 0.5
# ────────────────────────────────────────────────────────────
# ── Generar la animacion a partir de la lista de caracteres
# ────────────────────────────────────────────────────────────
def animate(anim):
# ── Numero de veces a repetir la animacion
for _ in range(4):
# ── Animación de los caracteres dados
for car in anim:
# ── Mostrar caracter actual y esperar
stdscr.addstr(0, 0, car)
stdscr.refresh()
time.sleep(WAIT)
# ────────────────
# ── MAIN
# ────────────────
# ────── Caracteres de la animación
anim1 = ['⠁', '⠈']
anim2 = ['⠂', '⠐']
anim3 = ['⠄', '⠠']
anim4 = ['⡀', '⢀']
# ────── Constantes para determinar la visibilidad del cursor
ON = 2
OFF = 0
# ────── Inicializacion
stdscr = curses.initscr()
# ── Ocultar el cursor
curses.curs_set(OFF)
animate(anim1)
animate(anim2)
animate(anim3)
animate(anim4)
stdscr.addstr(2, 0, "Pulsa una tecla")
# ── Esperar a que el usuario apriete una tecla
stdscr.getch()
# ── Volver a enseñar el cursor antes de terminar
curses.curs_set(ON)
# ── Terminar. Volver a la pantalla original del terminal
curses.endwin()Este es el resultado:
![]()
El pixel se mueve horizontalmente por las 4 filas del carácter
Para seguir familiarizándome con los caracteres, voy a hacer ahora unas animaciones del pixel en vertical, en las dos columnas. El código es el mismo que antes, pero sólo cambia la lista con los fotogramas de la animación. Ahora la animación tiene 4 fotogramas para cada columna
# ────── Caracteres de la animación
anim1 = ['⠁', '⠂', '⠄', '⡀']
anim2 = ['⠈', '⠐', '⠠', '⢀']- Fichero: Ej-04-pant-1x1-anim-2.py
Este es el resultado:
![]()
Vamos a hacer una animación más, de 8 fotogramas. Ahora el pixel recorre el perímetro del carácter en sentido horario
El código sigue siendo el mismo. Estos son los fotogramas de la nueva animación:
# ────── Caracteres de la animación
anim = ['⠁', '⠈', '⠐', '⠠', '⢀', '⡀', '⠄', '⠂']- Fichero: Ej-05-pant-1x1-anim-3-perim.py
Este es el resultado:
![]()
El primer carácter del bloque braile tiene todos los píxeles apagados. Su valor es 0x2800. El último carácter es el 0x28FF, y tiene todos los píxeles encendidos. Hay por tanto 256 caracteres unicode. Esto se puede representar mediante un byte normal, pero lo que tenemos que determinar es el orden de los pixeles dentro del carácter, y ver al bit de qué peso se corresponden con el byte natural
Para obtener el carácter a partir de su código unicode utilizamos la función chr(). Esta es la llamada a realizar:
chr(0x2800 + i)Donde i es un byte normal, que va desde 0 hasta 0xFF (255). En lo que estamos interesados es en concoer el mapeado entre el byte normal y su representación en pantalla. Por ello vamos a probar este programa contador, que realiza una animación de 255 fotogramas, uno por cada carácter braile
- Fichero: Ej-06-pant-1x1-anim-count
#!/usr/bin/env python3
# ──────────────────────────────────────────────────────
# ── Pantalla 1x1. Contador de píxeles
# ──────────────────────────────────────────────────────
import curses
import time
# ────── Tiempo de espera entre fotogramas
WAIT = 0.2
# ────────────────
# ── MAIN
# ────────────────
# ────── Constantes para determinar la visibilidad del cursor
ON = 2
OFF = 0
# ────── Inicializacion
stdscr = curses.initscr()
# ── Ocultar el cursor
curses.curs_set(OFF)
# ── Animación del contador. Recorrer todos los caracteres braile
# ── mostrándolo en la posión (0,0) y esperando un tiempo
for i in range(256):
# ── Obtener el carácter unicode a partir de su codigo
car = chr(0x2800 + i)
# ── Mostrarlo en la pantalla
stdscr.addstr(0, 0, car)
stdscr.refresh()
time.sleep(WAIT)
stdscr.addstr(2, 0, "Pulsa una tecla")
# ── Esperar a que el usuario apriete una tecla
stdscr.getch()
# ── Volver a enseñar el cursor antes de terminar
curses.curs_set(ON)
# ── Terminar. Volver a la pantalla original del terminal
curses.endwin()En esta figura se muestran los pesos de 8 píxeles que representan el binario natural. El de la derecha es el 0, y tiene peso 1. El siguiente es el bit 1, con peso 2... así hasta llegar al pixel de la izquierda que es el 7 con un peso de 128
Al observar la simulación del contador Braile, obtenemos el peso de cada píxel. El pixel que parpadea a la máxima frecuencia tendrá el peso 1, el siguiente más rápido es el 2, luego el 4... y por último el más lento tendrá un peso de 128
En esta figura se muestran los pesos encontrados. El orden es diferente al esperado. Los menos pesos los tienen los 3 bits de la primera columna, desde el superior al inferior: 1, 2, y 4. Los siguientes pesos están en esos mismos pixeles pero de la siguiente columna: 8, 16, 32
Los mayores pesos están en los píxeles de la última fila. El de la izquierda tiene 64 y el de la derecha 128
Dentro de un caracter (pantalla 1x1) estamos interesados en poder encender el pixel indicado por las coordenadas (x,y), donde
Este mapeo se consigue con la siguiente función:
Para comprobar su funcionamiento, escribimos esta función en python:
# ──────────────────────────────────────────────────────────────────────
# ── Obtener el codigo unicode braile (byte) a partir de la posicion
# ── del pixel (x,y) dentro del carácter
# ── x ∈ [0,1]
# ── y ∈ [0,3]
# ──────────────────────────────────────────────────────────────────────
def braile_from_pos(x, y):
# ──── La funcion tiene valores diferentes segun los casos
# ──── Caso normal (y<3)
# ──── Caso especial (y=3)
cod = 1 << (3*x + y) if y < 3 else 1 << (x + 6)
return codEn el siguiente programa se hace la animación del movimiento horizontal del pixel para las 4 líneas (animación que ya hemos hecho anteriormente), pero ahora llamando a la funcion plot(x,y). Cuando se dibuja un pixel se borra el anterior
- Fichero: Ej-07-pant-1x1-plot.py
#!/usr/bin/env python3
# ──────────────────────────────────────────────────────
# ── Pantalla 1x1. Funcion de plot
# ──────────────────────────────────────────────────────
import curses
import time
# ────── Tiempo de espera entre fotogramas
WAIT = 0.4
# ──────────────────────────────────────────────────────────────────────
# ── Obtener el codigo unicode braile (byte) a partir de la posicion
# ── del pixel (x,y) dentro del carácter
# ── x ∈ [0,1]
# ── y ∈ [0,3]
# ──────────────────────────────────────────────────────────────────────
def braile_from_pos(x, y):
# ──── La funcion tiene valores diferentes segun los casos
# ──── Caso normal (y<3)
# ──── Caso especial (y=3)
cod = 1 << (3*x + y) if y < 3 else 1 << (x + 6)
return cod
# ──────────────────────────────────────────────────────────────────────
# ── Dibujar en la pantalla 1x1 el pixel de la posicion (x,y)
# ── x ∈ [0,1]
# ── y ∈ [0,3]
# ── Al dibujar un pixel se borra el anterior
# ──────────────────────────────────────────────────────────────────────
def plot(x, y):
# -- Obtener el byte a partir de (x,y)
b = braile_from_pos(x, y)
# ── Obtener el carácter unicode a partir de su codigo
car = chr(0x2800 + b)
# ── Mostrarlo en la pantalla
stdscr.addstr(0, 0, car)
stdscr.refresh()
# ────────────────
# ── MAIN
# ────────────────
# ────── Constantes para determinar la visibilidad del cursor
ON = 2
OFF = 0
# ────── Inicializacion
stdscr = curses.initscr()
# ── Ocultar el cursor
curses.curs_set(OFF)
# ── Animacion horizontal para cada linea
for y in range(4):
# ── Repetir la animacion horizontal
for _ in range(3):
# ── Animación en horizontal
for x in range(2):
plot(x, y)
time.sleep(WAIT)
stdscr.addstr(2, 0, "Pulsa una tecla")
# ── Esperar a que el usuario apriete una tecla
stdscr.getch()
# ── Volver a enseñar el cursor antes de terminar
curses.curs_set(ON)
# ── Terminar. Volver a la pantalla original del terminal
curses.endwin()La animación es la mismo que hemos hecho antes
El objetivo ahora es hacer un ploteado persistente. Esto es, que NO se borren los píxeles anteriores. Para ello tengo que definirme mi propia pantalla virtual, de 1x1. El plot se hace primero en esta pantalla, pero aplicando un OR entre lo que había antes y el nuevo pixel a dibujar. El valor resultante es el que tenemos en la pantalla virtual, que luego la enviamos a la pantalla física para dibujarlo
En este ejemplo encendemos todos los píxeles del carácter, uno a uno, mediante la nueva rutina de plot. Al dibujar un pixel el resto permanecen
- Fichero: Ej-08-pant-1x1-plot-persistent.py
#!/usr/bin/env python3
# ──────────────────────────────────────────────────────
# ── Pantalla 1x1. Funcion de plot persistente
# ──────────────────────────────────────────────────────
import curses
import time
# ────── Tiempo de espera entre fotogramas
WAIT = 0.4
# ────── Pantalla virtual de 1x1 pixeles
pantalla = [[0]]
# ────── Refrescar la pantalla 1x1 en la pantalla de ncurses
def pantalla_refresh():
stdscr.addstr(0, 0, chr(0x2800 + pantalla[0][0]))
stdscr.refresh()
# ──────────────────────────────────────────────────────────────────────
# ── Obtener el codigo unicode braile (byte) a partir de la posicion
# ── del pixel (x,y) dentro del carácter
# ── x ∈ [0,1]
# ── y ∈ [0,3]
# ──────────────────────────────────────────────────────────────────────
def braile_from_pos(x, y):
# ──── La funcion tiene valores diferentes segun los casos
# ──── Caso normal (y<3)
# ──── Caso especial (y=3)
cod = 1 << (3*x + y) if y < 3 else 1 << (x + 6)
return cod
# ──────────────────────────────────────────────────────────────────────
# ── Dibujar en la pantalla 1x1 el pixel de la posicion (x,y)
# ── x ∈ [0,1]
# ── y ∈ [0,3]
# ── El ploteado se hace en la pantalla virtual 1x1, y se combina con
# ── lo que ya hubiese antes
# ──────────────────────────────────────────────────────────────────────
def plot(x, y):
# -- Obtener el byte a partir de (x,y)
b = braile_from_pos(x, y)
# ── Obtener el valor actual de la pantalla
value = pantalla[0][0]
# ── Calcular el nuevo valor
value = value | b
# ── Actualizar la pantalla virtual
pantalla[0][0] = value
# ── Mostrarlo en la pantalla real
pantalla_refresh()
# ────────────────
# ── MAIN
# ────────────────
# ────── Constantes para determinar la visibilidad del cursor
ON = 2
OFF = 0
# ────── Inicializacion
stdscr = curses.initscr()
# ── Ocultar el cursor
curses.curs_set(OFF)
# ───────── Dibujar todos los pixeles
# ── Para cada linea...
for y in range(4):
# ── Dibujar pixeles en la linea actual
for x in range(2):
plot(x, y)
time.sleep(WAIT)
stdscr.addstr(2, 0, "Pulsa una tecla")
# ── Esperar a que el usuario apriete una tecla
stdscr.getch()
# ── Volver a enseñar el cursor antes de terminar
curses.curs_set(ON)
# ── Terminar. Volver a la pantalla original del terminal
curses.endwin()Este es el resultado:
![]()
Ahora pasamos a una pantalla de 2x1 caracteres, que se corresponde con una de 4x4 píxeles. Hay que transformar las coordenadas de pixel (x,y) a las del carácter en pantalla, y en ese carácter activar el pixel. Tengo que pensar cómo hacerlo...
Ya lo tengo solucionado. Tenemos 3 tipos de coordenadas:
- Coordenadas del pixel (x,y). Son las coordenadas absolutas del pixel, tomando como referencia el origen, que está en el pixel de la esquina izquierda superior
- Coordenadas del carácter (xc,yc): Son las coordenadas del carácter donde está el pixel
- Coordenadas locales (xl, yl): Son las coordenadas del pixel referidas al carácter actual
Al hacer un plot(x,y) partimos de las coordenadas del pixel y hay que obtener las coordenadas de carácter (xc,yc) y las coordenadas locales (xl, yl). La relación entre las coordenadas se muestra en esta figura
La coordenada x del pixel tiene sólo 2 bits (porque su rango de valores es de 0 a 3)
- El bit de mayo peso de la coordenada x es la coordenada de carácter xc
- El bit de menor peso de la coordeanda x es la coordenada local xl
La coordenada y del pixel tiene también sólo 2 bits (el rango es el mismo, desde 0 hasta 3). Pero ahora la coordenada de carácter es siempre cero (porque sólo hay una única linea de caracteres):
La coordenada local coincide con la coordenada y:
En este ejemplo se rellena toda la pantalla con pixeles, usando la nueva función plot(x,y)
- Fichero: Ej-09-pant-2x1-plot.py
#!/usr/bin/env python3
# ──────────────────────────────────────────────────────
# ── Pantalla 1x1. Funcion de plot persistente
# ──────────────────────────────────────────────────────
import curses
import time
# ────── Tiempo de espera entre fotogramas
WAIT = 0.4
# ────── Pantalla virtual de 2x1 pixeles
pantalla = [[0, 0]]
# ────── Refrescar la pantalla 1x1 en la pantalla de ncurses
def pantalla_refresh():
stdscr.addstr(0, 0, chr(0x2800 + pantalla[0][0]))
stdscr.addstr(0, 1, chr(0x2800 + pantalla[0][1]))
stdscr.refresh()
# ──────────────────────────────────────────────────────────────────────
# ── Obtener el codigo unicode braile (byte) a partir de la posicion
# ── del pixel (x,y) dentro del carácter
# ── x ∈ [0,1]
# ── y ∈ [0,3]
# ──────────────────────────────────────────────────────────────────────
def braile_from_pos(x, y):
# ──── La funcion tiene valores diferentes segun los casos
# ──── Caso normal (y<3)
# ──── Caso especial (y=3)
cod = 1 << (3*x + y) if y < 3 else 1 << (x + 6)
return cod
# ──────────────────────────────────────────────────────────────────────
# ── Dibujar en la pantalla 2x1 el pixel de la posicion (x,y)
# ── x ∈ [0,1]
# ── y ∈ [0,3]
# ── El ploteado se hace en la pantalla virtual, y se combina con
# ── lo que ya hubiese antes
# ──────────────────────────────────────────────────────────────────────
def plot(x, y):
# ── Obtener las coordenadas del carácter
xc = x >> 1
yc = y >> 2
# ── Obtener las coordenadas locales
xl = x & 0x01
yl = y
# ── Obtener el byte a partir de (xl, yl)
b = braile_from_pos(xl, yl)
# ── Obtener el valor actual de la pantalla
value = pantalla[yc][xc]
# ── Calcular el nuevo valor
value = value | b
# ── Actualizar la pantalla virtual
pantalla[yc][xc] = value
# ── Mostrarlo en la pantalla real
pantalla_refresh()
# ────────────────
# ── MAIN
# ────────────────
# ────── Constantes para determinar la visibilidad del cursor
ON = 2
OFF = 0
# ────── Inicializacion
stdscr = curses.initscr()
# ── Ocultar el cursor
curses.curs_set(OFF)
# ───────── Dibujar todos los pixeles
# ── Para cada linea...
for y in range(4):
# ── Dibujar pixeles en la linea actual
for x in range(4):
plot(x, y)
time.sleep(WAIT)
stdscr.addstr(2, 0, "Pulsa una tecla")
# ── Esperar a que el usuario apriete una tecla
stdscr.getch()
# ── Volver a enseñar el cursor antes de terminar
curses.curs_set(ON)
# ── Terminar. Volver a la pantalla original del terminal
curses.endwin()Este es el resultado:
![]()
En la pantalla de 4x1 caracteres disponemos de 8x4 píxeles
- Coordenada x de pixel: 3 bits
$x = x_2x_1x_0$ - Coordenada x del carácter:
$x_c = x_2x_1$ (2 bits) - Coordenada x local
$x_l = x_0$ (1 bit)
- Coordenada y de pixel: 2 bits
$y = y_1y_0$ - Coordenada y del carácter:
$y_c = 0$ - Coordenada y del pixel:
$y_l = y_1y_0$
En este ejemplo se rellena toda la pantalla con píxeles:
- Fichero: Ej-10-pant-4x1-plot.py
#!/usr/bin/env python3
# ──────────────────────────────────────────────────────
# ── Pantalla 4x1. Funcion de plot persistente
# ──────────────────────────────────────────────────────
import curses
import time
# ────── Tiempo de espera entre fotogramas
WAIT = 0.1
# ────── Pantalla virtual de 4x1 pixeles
pantalla = [
[0, 0, 0, 0], # ── y = 0
]
# ────── Refrescar la pantalla 4x1 en la pantalla de ncurses
def pantalla_refresh():
for x in range(4):
stdscr.addstr(0, x, chr(0x2800 + pantalla[0][x]))
stdscr.refresh()
# ──────────────────────────────────────────────────────────────────────
# ── Obtener el codigo unicode braile (byte) a partir de la posicion
# ── del pixel (x,y) dentro del carácter
# ── x ∈ [0,7]
# ── y ∈ [0,3]
# ──────────────────────────────────────────────────────────────────────
def braile_from_pos(x, y):
# ──── La funcion tiene valores diferentes segun los casos
# ──── Caso normal (y<3)
# ──── Caso especial (y=3)
cod = 1 << (3*x + y) if y < 3 else 1 << (x + 6)
return cod
# ──────────────────────────────────────────────────────────────────────
# ── Dibujar en la pantalla 2x1 el pixel de la posicion (x,y)
# ── x ∈ [0,7]
# ── y ∈ [0,3]
# ── El ploteado se hace en la pantalla virtual, y se combina con
# ── lo que ya hubiese antes
# ──────────────────────────────────────────────────────────────────────
def plot(x, y):
# ── Obtener las coordenadas del carácter
xc = x >> 1
yc = y >> 2
# ── Obtener las coordenadas locales
xl = x & 0x01
yl = y
# ── Obtener el byte a partir de (xl, yl)
b = braile_from_pos(xl, yl)
# ── Obtener el valor actual de la pantalla
value = pantalla[yc][xc]
# ── Calcular el nuevo valor
value = value | b
# ── Actualizar la pantalla virtual
pantalla[yc][xc] = value
# ── Mostrarlo en la pantalla real
pantalla_refresh()
# ────────────────
# ── MAIN
# ────────────────
# ────── Constantes para determinar la visibilidad del cursor
ON = 2
OFF = 0
# ────── Inicializacion
stdscr = curses.initscr()
# ── Ocultar el cursor
curses.curs_set(OFF)
stdscr.addstr(1, 0, "0123")
# ───────── Dibujar todos los pixeles
# ── Para cada linea...
for y in range(4):
# ── Dibujar pixeles en la linea actual
for x in range(8):
plot(x, y)
time.sleep(WAIT)
stdscr.addstr(2, 0, "Pulsa una tecla")
# ── Esperar a que el usuario apriete una tecla
stdscr.getch()
# ── Volver a enseñar el cursor antes de terminar
curses.curs_set(ON)
# ── Terminar. Volver a la pantalla original del terminal
curses.endwin()Este es el resultado:
![]()
Ya tengo la pantalla 4x2 lista. Tiene 8x8 píxeles. Tanto la x como la y tiene 3 bits. Su estructura es la mostrada en este dibujo:
Este es el código:
- Fichero: Ej-11-pant-4x2-plot.py
#!/usr/bin/env python3
# ──────────────────────────────────────────────────────
# ── Pantalla 4x2. Funcion de plot persistente
# ──────────────────────────────────────────────────────
import curses
import time
# ────── Tiempo de espera entre fotogramas
WAIT = 0.1
# ────── Pantalla virtual de 4x2 pixeles
pantalla = [
[0, 0, 0, 0], # ── y = 0
[0, 0, 0, 0], # ── y = 1
]
# ────── Refrescar la pantalla 4x1 en la pantalla de ncurses
def pantalla_refresh():
for y in range(2):
for x in range(4):
stdscr.addstr(y, x, chr(0x2800 + pantalla[y][x]))
stdscr.refresh()
# ──────────────────────────────────────────────────────────────────────
# ── Obtener el codigo unicode braile (byte) a partir de la posicion
# ── del pixel (x,y) dentro del carácter
# ── x ∈ [0,7]
# ── y ∈ [0,7]
# ──────────────────────────────────────────────────────────────────────
def braile_from_pos(x, y):
# ──── La funcion tiene valores diferentes segun los casos
# ──── Caso normal (y<3)
# ──── Caso especial (y=3)
cod = 1 << (3*x + y) if y < 3 else 1 << (x + 6)
return cod
# ──────────────────────────────────────────────────────────────────────
# ── Dibujar en la pantalla 4x2 el pixel de la posicion (x,y)
# ── x ∈ [0,7]
# ── y ∈ [0,7]
# ── El ploteado se hace en la pantalla virtual, y se combina con
# ── lo que ya hubiese antes
# ──────────────────────────────────────────────────────────────────────
def plot(x, y):
# ── Obtener las coordenadas del carácter
xc = x >> 1
yc = y >> 2
# ── Obtener las coordenadas locales
xl = x & 0x01
yl = y & 0x03
# ── Obtener el byte a partir de (xl, yl)
b = braile_from_pos(xl, yl)
# ── Obtener el valor actual de la pantalla
value = pantalla[yc][xc]
# ── Calcular el nuevo valor
value = value | b
# ── Actualizar la pantalla virtual
pantalla[yc][xc] = value
# ── Mostrarlo en la pantalla real
pantalla_refresh()
# ────────────────
# ── MAIN
# ────────────────
# ────── Constantes para determinar la visibilidad del cursor
ON = 2
OFF = 0
# ────── Inicializacion
stdscr = curses.initscr()
# ── Ocultar el cursor
curses.curs_set(OFF)
stdscr.addstr(2, 0, "0123")
stdscr.addstr(0, 4, "0")
stdscr.addstr(1, 4, "1")
# ───────── Dibujar todos los pixeles
# ── Para cada linea...
for y in range(8):
# ── Dibujar pixeles en la linea actual
for x in range(8):
plot(x, y)
time.sleep(WAIT)
stdscr.addstr(3, 0, "Pulsa una tecla")
# ── Esperar a que el usuario apriete una tecla
stdscr.getch()
# ── Volver a enseñar el cursor antes de terminar
curses.curs_set(ON)
# ── Terminar. Volver a la pantalla original del terminal
curses.endwin()Este es el resultado:
![]()
Ya tengo la pantalla 8x4 lista. Tiene 16x16 píxeles. Pero está implementada de una forma genérica, por lo que se puede tener ya cualquier tamaño
- Fichero: Ej-12-pant-8x4-plot.py
#!/usr/bin/env python3
# ──────────────────────────────────────────────────────
# ── Pantalla genérica de WIDTH x HEIGHT caracteres
# ── Funcion de plot persistente
# ──────────────────────────────────────────────────────
import curses
import time
# ────── Dimensiones de la pantalla en caracteres
WIDTH = 8
HEIGHT = 4
# ────── Dimensiones de la pantalla en píxeles
PIX_WIDTH = 2 * WIDTH
PIX_HEIGHT = 4 * HEIGHT
# ────── Tiempo de espera entre fotogramas
WAIT = 10 / (PIX_WIDTH * PIX_HEIGHT)
# ────── Pantalla virtual de WIDTH x HEIGHT caracteres
pantalla = [[0 for _ in range(WIDTH)] for _ in range(HEIGHT)]
# ────── Refrescar la pantalla en la pantalla de ncurses
def pantalla_refresh():
for y in range(HEIGHT):
for x in range(WIDTH):
stdscr.addstr(y, x, chr(0x2800 + pantalla[y][x]))
stdscr.refresh()
# ──────────────────────────────────────────────────────────────────────
# ── Obtener el codigo unicode braile (byte) a partir de la posicion
# ── del pixel (x,y) dentro del carácter
# ── x ∈ [0, 1]
# ── y ∈ [0, 3]
# ──────────────────────────────────────────────────────────────────────
def braile_from_pos(x, y):
# ──── La funcion tiene valores diferentes segun los casos
# ──── Caso normal (y < 3)
# ──── Caso especial (y=3)
cod = 1 << (3*x + y) if y < 3 else 1 << (x + 6)
return cod
# ──────────────────────────────────────────────────────────────────────
# ── Dibujar en la pantalla el pixel de la posicion (x,y)
# ── x ∈ [0, PIX_WIDTH-1]
# ── y ∈ [0, PIX_HEIGHT-1]
# ── El ploteado se hace en la pantalla virtual, y se combina con
# ── lo que ya hubiese antes
# ──────────────────────────────────────────────────────────────────────
def plot(x, y):
# ── Obtener las coordenadas del carácter
xc = x >> 1
yc = y >> 2
# ── Obtener las coordenadas locales
xl = x & 0x01
yl = y & 0x03
# ── Obtener el byte a partir de (xl, yl)
b = braile_from_pos(xl, yl)
# ── Obtener el valor actual de la pantalla
value = pantalla[yc][xc]
# ── Calcular el nuevo valor
value = value | b
# ── Actualizar la pantalla virtual
pantalla[yc][xc] = value
# ── Mostrarlo en la pantalla real
pantalla_refresh()
# ────────────────
# ── MAIN
# ────────────────
# ────── Constantes para determinar la visibilidad del cursor
ON = 2
OFF = 0
# ────── Inicializacion
stdscr = curses.initscr()
# ── Ocultar el cursor
curses.curs_set(OFF)
# ── Imprimir las coordenadas x de caracteres en la parte inferior
for i in range(WIDTH):
stdscr.addstr(HEIGHT, i, str(i))
# ── Imprimir las coordenadas y de caracteres en la parte derecha
for i in range(HEIGHT):
stdscr.addstr(i, WIDTH, str(i))
# ───────── Dibujar todos los pixeles
# ── Para cada linea...
for y in range(PIX_HEIGHT):
# ── Dibujar pixeles en la linea actual
for x in range(PIX_WIDTH):
plot(x, y)
time.sleep(WAIT)
stdscr.addstr(HEIGHT+1, 0, "Pulsa una tecla")
# ── Esperar a que el usuario apriete una tecla
stdscr.getch()
# ── Volver a enseñar el cursor antes de terminar
curses.curs_set(ON)
# ── Terminar. Volver a la pantalla original del terminal
curses.endwin()Este es el resultado:
![]()
Con este experimento probamos la pantalla paramétrica con un tamaño mayor: 78x22 caracteres. No se utiliza el tamaño máximo de anchura de 80 porque se incluyen 2 caracteres para indicar la línea
#!/usr/bin/env python3
# ──────────────────────────────────────────────────────
# ── Pantalla genérica de WIDTH x HEIGHT caracteres
# ── Funcion de plot persistente
# ──────────────────────────────────────────────────────
import curses
import time
# ────── Dimensiones de la pantalla en caracteres
WIDTH = 78
HEIGHT = 22
# ────── Dimensiones de la pantalla en píxeles
PIX_WIDTH = 2 * WIDTH
PIX_HEIGHT = 4 * HEIGHT
# ────── Tiempo de espera entre fotogramas
WAIT = 10 / (PIX_WIDTH * PIX_HEIGHT)
# ────── Pantalla virtual de WIDTH x HEIGHT caracteres
pantalla = [[0 for _ in range(WIDTH)] for _ in range(HEIGHT)]
# ────── Refrescar la pantalla en la pantalla de ncurses
def pantalla_refresh():
for y in range(HEIGHT):
for x in range(WIDTH):
stdscr.addstr(y, x, chr(0x2800 + pantalla[y][x]))
stdscr.refresh()
# ──────────────────────────────────────────────────────────────────────
# ── Obtener el codigo unicode braile (byte) a partir de la posicion
# ── del pixel (x,y) dentro del carácter
# ── x ∈ [0, 1]
# ── y ∈ [0, 3]
# ──────────────────────────────────────────────────────────────────────
def braile_from_pos(x, y):
# ──── La funcion tiene valores diferentes segun los casos
# ──── Caso normal (y < 3)
# ──── Caso especial (y=3)
cod = 1 << (3*x + y) if y < 3 else 1 << (x + 6)
return cod
# ──────────────────────────────────────────────────────────────────────
# ── Dibujar en la pantalla el pixel de la posicion (x,y)
# ── x ∈ [0, PIX_WIDTH-1]
# ── y ∈ [0, PIX_HEIGHT-1]
# ── El ploteado se hace en la pantalla virtual, y se combina con
# ── lo que ya hubiese antes
# ──────────────────────────────────────────────────────────────────────
def plot(x, y):
# ── Obtener las coordenadas del carácter
xc = x >> 1
yc = y >> 2
# ── Obtener las coordenadas locales
xl = x & 0x01
yl = y & 0x03
# ── Obtener el byte a partir de (xl, yl)
b = braile_from_pos(xl, yl)
# ── Obtener el valor actual de la pantalla
value = pantalla[yc][xc]
# ── Calcular el nuevo valor
value = value | b
# ── Actualizar la pantalla virtual
pantalla[yc][xc] = value
# ── Mostrarlo en la pantalla real
pantalla_refresh()
# ────────────────
# ── MAIN
# ────────────────
# ────── Constantes para determinar la visibilidad del cursor
ON = 2
OFF = 0
# ────── Inicializacion
stdscr = curses.initscr()
# ── Ocultar el cursor
curses.curs_set(OFF)
# ── Imprimir las coordenadas x de caracteres en la parte inferior
for i in range(WIDTH):
stdscr.addstr(HEIGHT, i, str(i % 10))
# ── Imprimir las coordenadas y de caracteres en la parte derecha
for i in range(HEIGHT):
stdscr.addstr(i, WIDTH, str(i))
# ───────── Dibujar todos los pixeles
# ── Para cada linea...
for y in range(PIX_HEIGHT):
# ── Dibujar pixeles en la linea actual
for x in range(PIX_WIDTH):
plot(x, y)
time.sleep(WAIT)
stdscr.addstr(HEIGHT+1, 0, "Pulsa una tecla")
# ── Esperar a que el usuario apriete una tecla
stdscr.getch()
# ── Volver a enseñar el cursor antes de terminar
curses.curs_set(ON)
# ── Terminar. Volver a la pantalla original del terminal
curses.endwin()Este es el resultado:
![]()
Voy a hacer ejemplos de animaciones con sprites. Las estoy reproduciendo de este otro log: Learn-zx-spectrum-asm
- Fichero: Ej-14-sprite-blink-led.py
#!/usr/bin/env python3
# ──────────────────────────────────────────────────────
# ── Ejemplo de dibujo de sprites en la pantalla
# ── Animación de un LED parpadeando
# ──────────────────────────────────────────────────────
import curses
import time
# ────── Dimensiones de la pantalla en caracteres
WIDTH = 78
HEIGHT = 22
# ────── Dimensiones de la pantalla en píxeles
PIX_WIDTH = 2 * WIDTH
PIX_HEIGHT = 4 * HEIGHT
# ────── Tiempo de espera entre fotogramas
WAIT = 10 / (PIX_WIDTH * PIX_HEIGHT)
# ────── Pantalla virtual de WIDTH x HEIGHT caracteres
pantalla = [[0 for _ in range(WIDTH)] for _ in range(HEIGHT)]
# ────── Borrar la pantalla virtual
def pantalla_cls():
for y in range(HEIGHT):
for x in range(WIDTH):
pantalla[y][x] = 0
# ────── Refrescar la pantalla en la pantalla de ncurses
def pantalla_refresh():
for y in range(HEIGHT):
for x in range(WIDTH):
stdscr.addstr(y, x, chr(0x2800 + pantalla[y][x]))
stdscr.refresh()
# ──────────────────────────────────────────────────────────────────────
# ── Obtener el codigo unicode braile (byte) a partir de la posicion
# ── del pixel (x,y) dentro del carácter
# ── x ∈ [0, 1]
# ── y ∈ [0, 3]
# ──────────────────────────────────────────────────────────────────────
def braile_from_pos(x, y):
# ──── La funcion tiene valores diferentes segun los casos
# ──── Caso normal (y < 3)
# ──── Caso especial (y=3)
cod = 1 << (3*x + y) if y < 3 else 1 << (x + 6)
return cod
# ──────────────────────────────────────────────────────────────────────
# ── Dibujar en la pantalla el pixel de la posicion (x,y)
# ── x ∈ [0, PIX_WIDTH-1]
# ── y ∈ [0, PIX_HEIGHT-1]
# ── El ploteado se hace en la pantalla virtual, y se combina con
# ── lo que ya hubiese antes
# ──────────────────────────────────────────────────────────────────────
def plot(x, y):
# ── Obtener las coordenadas del carácter
xc = x >> 1
yc = y >> 2
# ── Obtener las coordenadas locales
xl = x & 0x01
yl = y & 0x03
# ── Obtener el byte a partir de (xl, yl)
b = braile_from_pos(xl, yl)
# ── Obtener el valor actual de la pantalla
value = pantalla[yc][xc]
# ── Calcular el nuevo valor
value = value | b
# ── Actualizar la pantalla virtual
pantalla[yc][xc] = value
# ── Mostrarlo en la pantalla real
# pantalla_refresh()
def plot_sprite(x, y, sprite):
sprite_width = len(sprite[0])
sprite_height = len(sprite)
for j in range(sprite_height):
for i in range(sprite_width):
if sprite[j][i] == 'x':
plot(x + i, y + j)
# ────────────────
# ── MAIN
# ────────────────
# ────── Constantes para determinar la visibilidad del cursor
ON = 2
OFF = 0
# ────── Sprite
sprinte_ledon = [
" ",
" xx ",
" xxxx ",
" xxxxxx ",
" xxxxxx ",
" xxxx ",
" xx ",
" ",
]
sprite_ledoff = [
" ",
" xx ",
" x x ",
" x x ",
" x x ",
" x x ",
" xx ",
" "
]
# ────── Inicializacion
stdscr = curses.initscr()
# ── Ocultar el cursor
curses.curs_set(OFF)
for _ in range(10):
pantalla_cls()
plot_sprite(0, 0, sprinte_ledon)
pantalla_refresh()
time.sleep(0.5)
pantalla_cls()
plot_sprite(0, 0, sprite_ledoff)
pantalla_refresh()
time.sleep(0.5)
stdscr.addstr(3, 0, "Pulsa una tecla")
# ── Esperar a que el usuario apriete una tecla
stdscr.getch()
# ── Volver a enseñar el cursor antes de terminar
curses.curs_set(ON)
# ── Terminar. Volver a la pantalla original del terminal
curses.endwin()Este es el resultado:
![]()
Es el momento de hacer pruebas con los sprites del manic miner!!
- Fichero: Ej-15-sprite-manic-miner.py
Así es como quedan los sprites:
Resultado:
⢀⣤⣴⠆⠀⢀⣤⣴⠆⠀⢀⣤⣴⠆ ⠀⣠⣤⡶
⠀⢿⡾⠂⠀⠀⢿⡾⠂⠀⠀⢿⡾⠂ ⠀⠸⣷⠗⠀
⣰⣿⢿⣆⠀⢰⡏⣿⡆⠀⣰⣿⢿⣆ ⣠⣾⣿⣷⣄
⢩⡿⣳⡍⠀⠈⢻⡞⠁⠀⢩⡿⣳⡍ ⢉⡼⠟⢷⣩
⠈⠉⠈⠉⠀⠀⠈⠉⠀⠀⠈⠉⠈⠉ ⠈⠉⠀⠈⠁⠀
![]()
Y esta es la animación:
![]()
- Fichero: Ej-16-sprite-manic-miner-2.py
Este es el resultado:
![]()
Es el momento de dibujar trozos de la pantalla 1 del manic mine
Se puede jugar online al manic miner original del ZX-Spectrum en este enlace: https://funhtml5games.com/?play=manicminer
Este es el pantallazo de la pantalla 1:
![]()
El Manic Miner lo utilicé como ejemplo en este log: Learn-zx-spectrum-asm, para aprender asm del z80. Ahí están algunos sprites del Manic miner
En este ejemplo se dibuja una parte de la pantalla 1 (no es la origianal) donde hay llaves, suelo, ladrillos y estalactitas en el techo. En este escenario se anima el personaje, que se mueve de izquierda a derecha. No recoge las llaves de momento
- Fichero: Ej-17-Manic-miner-pantalla-1.py
Este es un pantallazo del juego:
![]()
En esta animación lo vemos en funcionamiento:
![]()
Es el momento de meter atributos, para que quede más bonito. Lo bueno es que los atributos se comportan igual que en el spectrum: Sólo se pueden definir por carácter, y NO por pixel
- Fichero: Ej-18-colores.py
#!/usr/bin/env python3
# ──────────────────────────────────────────────────────
# ── Pantalla 1 del Manic Miner
# ──────────────────────────────────────────────────────
import curses
import time
# ────── Dimensiones de la pantalla en caracteres
WIDTH = 80
HEIGHT = 23
# ────── Dimensiones de la pantalla en píxeles
PIX_WIDTH = 2 * WIDTH
PIX_HEIGHT = 4 * HEIGHT
# ────── Tiempo de espera entre fotogramas
WAIT = 0.1
# ────── Pantalla virtual de WIDTH x HEIGHT caracteres
pantalla = [[0 for _ in range(WIDTH)] for _ in range(HEIGHT)]
# ────── Atributos de la pantalla
pantalla_attr = [[0 for _ in range(WIDTH)] for _ in range(HEIGHT)]
# ────── Borrar la pantalla virtual
def pantalla_cls():
for y in range(HEIGHT):
for x in range(WIDTH):
pantalla[y][x] = 0
# ────── Refrescar la pantalla en la pantalla de ncurses
def pantalla_refresh():
for y in range(HEIGHT):
for x in range(WIDTH):
attr = pantalla_attr[y][x]
stdscr.addstr(y, x, chr(0x2800 + pantalla[y][x]), attr)
stdscr.refresh()
# ──────────────────────────────────────────────────────────────────────
# ── Obtener el codigo unicode braile (byte) a partir de la posicion
# ── del pixel (x,y) dentro del carácter
# ── x ∈ [0, 1]
# ── y ∈ [0, 3]
# ──────────────────────────────────────────────────────────────────────
def braile_from_pos(x, y):
# ──── La funcion tiene valores diferentes segun los casos
# ──── Caso normal (y < 3)
# ──── Caso especial (y=3)
cod = 1 << (3*x + y) if y < 3 else 1 << (x + 6)
return cod
# ──────────────────────────────────────────────────────────────────────
# ── Dibujar en la pantalla el pixel de la posicion (x,y)
# ── x ∈ [0, PIX_WIDTH-1]
# ── y ∈ [0, PIX_HEIGHT-1]
# ── El ploteado se hace en la pantalla virtual, y se combina con
# ── lo que ya hubiese antes
# ──────────────────────────────────────────────────────────────────────
def plot(x, y, attr=0):
# ── Obtener las coordenadas del carácter
xc = x >> 1
yc = y >> 2
# ── Obtener las coordenadas locales
xl = x & 0x01
yl = y & 0x03
# ── Obtener el byte a partir de (xl, yl)
b = braile_from_pos(xl, yl)
# ── Obtener el valor actual de la pantalla
value = pantalla[yc][xc]
# ── Calcular el nuevo valor
value = value | b
# ── Actualizar la pantalla virtual
pantalla[yc][xc] = value
pantalla_attr[yc][xc] = attr
# ── Mostrarlo en la pantalla real
# pantalla_refresh()
def plot_sprite(x, y, sprite, attr=0):
sprite_width = len(sprite[0])
sprite_height = len(sprite)
for j in range(sprite_height):
for i in range(sprite_width):
if sprite[j][i] == 'x':
plot(x + i, y + j, attr)
# ────────────────
# ── SPRITES
# ────────────────
ladrillos = [
"xx xxx x",
" ",
" xxx xxx",
" ",
"xx xxx x",
" ",
" xxx xxx",
" ",
]
suelo = [
"xxxxxxxx",
"xxxxxxxx",
"xx xx xx",
" xx xxx ",
"xx x x",
" x ",
" ",
" ",
]
llave = [
" xx ",
" x x ",
"x x ",
"x x ",
" xx x ",
" x ",
" x x ",
" x ",
]
estalactita = [
"xxxxxxxx",
"xxxxxxx ",
" xxxxxx ",
" xxxxx ",
" x xx ",
" x xx ",
" x ",
" x ",
]
# ────────────────────────────────────────────────
# ── Dibujo del escenario de la pantalla 1
# ────────────────────────────────────────────────
def dibujar_escenario():
col_red = curses.color_pair(2)
col_ladrillos = curses.color_pair(3)
col_yellow = curses.color_pair(4)
col_cyan = curses.color_pair(5)
col_green = curses.color_pair(7)
# ── Dibujo de los muros laterales
for y in range(14):
plot_sprite(0, y*4, ladrillos, col_ladrillos)
plot_sprite(152, y*4, ladrillos, col_ladrillos)
# ── Dibujo del suelo
for x in range(18):
plot_sprite(x*8 + 8, 8 * 5, suelo, col_red)
# ── Dibujo de la estalactita
plot_sprite(44, 0, estalactita, col_cyan)
plot_sprite(64, 0, estalactita, col_cyan)
# ── Dibujo de la llave
plot_sprite(36, 0, llave, col_cyan)
plot_sprite(64, 8, llave, col_magenta)
plot_sprite(116, 0, llave, col_yellow)
plot_sprite(96, 32, llave, col_green)
# ────── Sprite
manic1 = [
" ",
" xx ",
" xxxxx ",
" xxxxx ",
" xx x ",
" xxxxx ",
" xxxx ",
" xx ",
" xxxx ",
" xx xxx ",
" xx xxx ",
" xx xxx ",
" xxx xx ",
" xxxx ",
" xx ",
" xx ",
" xxx ",
" ",
]
manic2 = [
" ",
" xx ",
" xxxxx ",
" xxxxx ",
" xx x ",
" xxxxx ",
" xxxx ",
" xx ",
" xxxx ",
" xxxxxx ",
" xxxxxx ",
"xxxx xxx",
"xxxxx xx",
" xxxx ",
" xxx xx ",
" xx xxx ",
" xxx xxx",
" ",
]
manic3 = [
" ",
" xx ",
" xxxxx ",
" xxxxx ",
" xx x ",
" xxxxx ",
" xxxx ",
" xx ",
" xxxx ",
" xxxxxx ",
" xxxxxxxx ",
"xxxxxxxxxx",
"xx xxxx xx",
" xxxxx ",
" xxx xx x",
" xx xxx",
" xxx xx ",
" ",
]
# ────── Sprites para la animacion del personaje
personaje = [manic2, manic1, manic2, manic3]
# ────── Incremento del personaje (en pixeles) asociado
# ────── a cada fotograma
personaje_inc = [2, 2, 0, 2]
# ────────────────────────────────────────────────
# ── Dibujar el personnaje
# ── ENTRADA: Numero de fotograma: 0,1,2,3,4,5....
# ── SALIDA: Incremento en pixeles del personaje
# ────────────────────────────────────────────────
def dibujar_personaje(fotograma):
col_default = curses.color_pair(1)
# ── Dibujo del Manic Miner
plot_sprite(xp, yp, personaje[fotograma % 4], col_default)
return personaje_inc[fotograma % 4]
# ────────────────
# ── MAIN
# ────────────────
# ────── Constantes para determinar la visibilidad del cursor
ON = 2
OFF = 0
# ────── Inicializacion
stdscr = curses.initscr()
# ── Ocultar el cursor
curses.curs_set(OFF)
# ── Inicializar los colores
curses.start_color()
# ── Color por defecto (Tinta=blanco y papel=Negro)
curses.init_pair(1, curses.COLOR_WHITE, curses.COLOR_BLACK)
col_default = curses.color_pair(1)
# ── Definir resto de colores
curses.init_pair(2, curses.COLOR_RED, curses.COLOR_BLACK)
curses.init_pair(3, curses.COLOR_YELLOW, curses.COLOR_RED)
curses.init_pair(4, curses.COLOR_YELLOW, curses.COLOR_BLACK)
curses.init_pair(5, curses.COLOR_CYAN, curses.COLOR_BLACK)
curses.init_pair(6, curses.COLOR_MAGENTA, curses.COLOR_BLACK)
curses.init_pair(7, curses.COLOR_GREEN, curses.COLOR_BLACK)
col_red = curses.color_pair(2)
col_ladrillos = curses.color_pair(3)
col_yellow = curses.color_pair(4)
col_cyan = curses.color_pair(5)
col_magenta = curses.color_pair(6)
col_green = curses.color_pair(7)
# ── Posicion inicial del personaje
xp = 8
yp = 23
for i in range(90):
pantalla_cls()
dibujar_escenario()
# ── Dibujo del Manic Miner
xinc = dibujar_personaje(i)
# ── Incrementar posicion del personaje
# ── en el eje x, en funcion del fotograma
xp += xinc
pantalla_refresh()
stdscr.addstr(12, 5, "¡Manic Miner en modo Texto!", col_yellow)
stdscr.refresh()
time.sleep(WAIT)
stdscr.addstr(14, 5, "Pulsa una tecla")
# ── Esperar a que el usuario apriete una tecla
stdscr.getch()
# ── Volver a enseñar el cursor antes de terminar
curses.curs_set(ON)
# ── Terminar. Volver a la pantalla original del terminal
curses.endwin()Este es un pantallazo:
![]()
Y en esta animación lo vemos en funcionamiento:
![]()
🚧 TODO 🚧
- Refactorizar en clases
- Crear modulo pixel_text
- Subir a pypi?
- Controlar el manic miner con las teclas
- Implementar el salto