diff --git a/python/bitmapfont.py b/python/bitmapfont.py index 8b7004e13b761072882a3393f7a36f71071faca4..b8e2fe881447cbe824ec4f80b333cd20f27fcd5c 100644 --- a/python/bitmapfont.py +++ b/python/bitmapfont.py @@ -1,147 +1,147 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # -*- coding: utf-8 -*- # 5x7 font from http://www.hwsw.no/snippets/5x7_LCD_font.php # every byte contains pixel data for one column, LSB is on top, MSB is ignored. +import clearscreen +import client FONT = { - " ": [0x00,0x00,0x00,0x00,0x00], - "!": [0x00,0x00,0x4F,0x00,0x00], - "\"": [0x00,0x03,0x00,0x03,0x00], - "#": [0x14,0x7F,0x14,0x7F,0x14], - "$": [0x24,0x2A,0x7F,0x2A,0x12], - "%": [0x23,0x13,0x08,0x64,0x62], - "&": [0x36,0x49,0x55,0x22,0x50], - "'": [0x00,0x00,0x03,0x00,0x00], - "(": [0x00,0x1C,0x22,0x41,0x00], - ")": [0x00,0x41,0x22,0x1C,0x00], - "*": [0x14,0x08,0x3E,0x08,0x14], - "+": [0x08,0x08,0x3E,0x08,0x08], - ",": [0x00,0x00,0x40,0x20,0x00], - "-": [0x00,0x08,0x08,0x08,0x00], - ".": [0x00,0x00,0x40,0x00,0x00], - "/": [0x20,0x10,0x08,0x04,0x02], + " ": [0x00, 0x00, 0x00, 0x00, 0x00], + "!": [0x00, 0x00, 0x4F, 0x00, 0x00], + '"': [0x00, 0x03, 0x00, 0x03, 0x00], + "#": [0x14, 0x7F, 0x14, 0x7F, 0x14], + "$": [0x24, 0x2A, 0x7F, 0x2A, 0x12], + "%": [0x23, 0x13, 0x08, 0x64, 0x62], + "&": [0x36, 0x49, 0x55, 0x22, 0x50], + "'": [0x00, 0x00, 0x03, 0x00, 0x00], + "(": [0x00, 0x1C, 0x22, 0x41, 0x00], + ")": [0x00, 0x41, 0x22, 0x1C, 0x00], + "*": [0x14, 0x08, 0x3E, 0x08, 0x14], + "+": [0x08, 0x08, 0x3E, 0x08, 0x08], + ",": [0x00, 0x00, 0x40, 0x20, 0x00], + "-": [0x00, 0x08, 0x08, 0x08, 0x00], + ".": [0x00, 0x00, 0x40, 0x00, 0x00], + "/": [0x20, 0x10, 0x08, 0x04, 0x02], + + "0": [0x3E, 0x51, 0x49, 0x45, 0x3E], + "1": [0x00, 0x42, 0x7F, 0x40, 0x00], + "2": [0x42, 0x61, 0x51, 0x49, 0x46], + "3": [0x21, 0x41, 0x45, 0x4B, 0x31], + "4": [0x18, 0x14, 0x12, 0x7F, 0x10], + "5": [0x27, 0x45, 0x45, 0x45, 0x39], + "6": [0x3C, 0x4A, 0x49, 0x49, 0x30], + "7": [0x01, 0x71, 0x09, 0x05, 0x03], + "8": [0x36, 0x49, 0x49, 0x49, 0x36], + "9": [0x06, 0x49, 0x49, 0x29, 0x1E], + ":": [0x00, 0x00, 0x24, 0x00, 0x00], + ";": [0x00, 0x00, 0x64, 0x00, 0x00], + "<": [0x08, 0x14, 0x22, 0x41, 0x00], + "=": [0x14, 0x14, 0x14, 0x14, 0x14], + ">": [0x00, 0x41, 0x22, 0x14, 0x08], + "?": [0x02, 0x01, 0x51, 0x09, 0x06], + + "@": [0x30, 0x49, 0x79, 0x41, 0x3E], + "A": [0x7E, 0x11, 0x11, 0x11, 0x7E], + "B": [0x7F, 0x49, 0x49, 0x49, 0x36], + "C": [0x3E, 0x41, 0x41, 0x41, 0x22], + "D": [0x7F, 0x41, 0x41, 0x22, 0x1C], + "E": [0x7F, 0x49, 0x49, 0x49, 0x41], + "F": [0x7F, 0x09, 0x09, 0x09, 0x01], + "G": [0x3E, 0x41, 0x49, 0x49, 0x7A], + "H": [0x7F, 0x08, 0x08, 0x08, 0x7F], + "I": [0x00, 0x41, 0x7F, 0x41, 0x00], + "J": [0x20, 0x40, 0x41, 0x3F, 0x01], + "K": [0x7F, 0x08, 0x14, 0x22, 0x41], + "L": [0x7F, 0x40, 0x40, 0x40, 0x40], + "M": [0x7F, 0x02, 0x0C, 0x02, 0x7F], + "N": [0x7F, 0x04, 0x08, 0x10, 0x7F], + "O": [0x3E, 0x41, 0x41, 0x41, 0x3E], - "0": [0x3E,0x51,0x49,0x45,0x3E], - "1": [0x00,0x42,0x7F,0x40,0x00], - "2": [0x42,0x61,0x51,0x49,0x46], - "3": [0x21,0x41,0x45,0x4B,0x31], - "4": [0x18,0x14,0x12,0x7F,0x10], - "5": [0x27,0x45,0x45,0x45,0x39], - "6": [0x3C,0x4A,0x49,0x49,0x30], - "7": [0x01,0x71,0x09,0x05,0x03], - "8": [0x36,0x49,0x49,0x49,0x36], - "9": [0x06,0x49,0x49,0x29,0x1E], - ":": [0x00,0x00,0x24,0x00,0x00], - ";": [0x00,0x00,0x64,0x00,0x00], - "<": [0x08,0x14,0x22,0x41,0x00], - "=": [0x14,0x14,0x14,0x14,0x14], - ">": [0x00,0x41,0x22,0x14,0x08], - "?": [0x02,0x01,0x51,0x09,0x06], - - "@": [0x30,0x49,0x79,0x41,0x3E], - "A": [0x7E,0x11,0x11,0x11,0x7E], - "B": [0x7F,0x49,0x49,0x49,0x36], - "C": [0x3E,0x41,0x41,0x41,0x22], - "D": [0x7F,0x41,0x41,0x22,0x1C], - "E": [0x7F,0x49,0x49,0x49,0x41], - "F": [0x7F,0x09,0x09,0x09,0x01], - "G": [0x3E,0x41,0x49,0x49,0x7A], - "H": [0x7F,0x08,0x08,0x08,0x7F], - "I": [0x00,0x41,0x7F,0x41,0x00], - "J": [0x20,0x40,0x41,0x3F,0x01], - "K": [0x7F,0x08,0x14,0x22,0x41], - "L": [0x7F,0x40,0x40,0x40,0x40], - "M": [0x7F,0x02,0x0C,0x02,0x7F], - "N": [0x7F,0x04,0x08,0x10,0x7F], - "O": [0x3E,0x41,0x41,0x41,0x3E], - - "P": [0x7F,0x09,0x09,0x09,0x06], - "Q": [0x3E,0x41,0x51,0x21,0x5E], - "R": [0x7F,0x09,0x19,0x29,0x46], - "S": [0x46,0x49,0x49,0x49,0x31], - "T": [0x01,0x01,0x7F,0x01,0x01], - "U": [0x3F,0x40,0x40,0x40,0x3F], - "V": [0x1F,0x20,0x40,0x20,0x1F], - "W": [0x3F,0x40,0x30,0x40,0x3F], - "X": [0x63,0x14,0x08,0x14,0x63], - "Y": [0x07,0x08,0x70,0x08,0x07], - "Z": [0x61,0x51,0x49,0x45,0x43], - "[": [0x00,0x7F,0x41,0x41,0x00], - "\\": [0x02,0x04,0x08,0x10,0x20], - "]": [0x00,0x41,0x41,0x7F,0x00], - "^": [0x04,0x02,0x01,0x02,0x04], - "_": [0x00,0x40,0x40,0x40,0x40], - - "`": [0x00,0x01,0x02,0x04,0x00], - "a": [0x20,0x54,0x54,0x54,0x78], - "b": [0x7F,0x50,0x48,0x48,0x30], - "c": [0x38,0x44,0x44,0x44,0x20], - "d": [0x38,0x44,0x44,0x48,0x7F], - "e": [0x38,0x54,0x54,0x54,0x18], - "f": [0x08,0x7E,0x09,0x01,0x02], - "g": [0x0C,0x54,0x54,0x54,0x3C], - "h": [0x7F,0x08,0x04,0x04,0x78], - "i": [0x00,0x44,0x7D,0x40,0x00], - "j": [0x20,0x40,0x44,0x3D,0x00], - "k": [0x7F,0x10,0x28,0x44,0x00], - "l": [0x00,0x41,0x7F,0x40,0x00], - "m": [0x78,0x04,0x18,0x04,0x78], - "n": [0x7C,0x08,0x04,0x04,0x78], - "o": [0x38,0x44,0x44,0x44,0x38], - - "p": [0x7C,0x14,0x14,0x14,0x08], - "q": [0x08,0x14,0x14,0x18,0x7C], - "r": [0x7C,0x08,0x04,0x04,0x08], - "s": [0x48,0x54,0x54,0x54,0x20], - "t": [0x04,0x3F,0x44,0x40,0x20], - "u": [0x3C,0x40,0x40,0x20,0x7C], - "v": [0x1C,0x20,0x40,0x20,0x1C], - "w": [0x3C,0x40,0x30,0x40,0x3C], - "x": [0x44,0x28,0x10,0x28,0x44], - "y": [0x0C,0x50,0x50,0x50,0x3C], - "z": [0x44,0x64,0x54,0x4C,0x44], - "{": [0x00,0x08,0x36,0x41,0x00], - "|": [0x00,0x00,0x7F,0x00,0x00], - "}": [0x00,0x41,0x36,0x08,0x00], - "~": [0x0C,0x02,0x0C,0x10,0x0C], - "\x7f": [0x55,0xAA,0x55,0xAA,0x55], + "P": [0x7F, 0x09, 0x09, 0x09, 0x06], + "Q": [0x3E, 0x41, 0x51, 0x21, 0x5E], + "R": [0x7F, 0x09, 0x19, 0x29, 0x46], + "S": [0x46, 0x49, 0x49, 0x49, 0x31], + "T": [0x01, 0x01, 0x7F, 0x01, 0x01], + "U": [0x3F, 0x40, 0x40, 0x40, 0x3F], + "V": [0x1F, 0x20, 0x40, 0x20, 0x1F], + "W": [0x3F, 0x40, 0x30, 0x40, 0x3F], + "X": [0x63, 0x14, 0x08, 0x14, 0x63], + "Y": [0x07, 0x08, 0x70, 0x08, 0x07], + "Z": [0x61, 0x51, 0x49, 0x45, 0x43], + "[": [0x00, 0x7F, 0x41, 0x41, 0x00], + "\\": [0x02, 0x04, 0x08, 0x10, 0x20], + "]": [0x00, 0x41, 0x41, 0x7F, 0x00], + "^": [0x04, 0x02, 0x01, 0x02, 0x04], + "_": [0x00, 0x40, 0x40, 0x40, 0x40], - u"ä": [0x20,0x55,0x54,0x55,0x78], - u"ü": [0x3C,0x41,0x40,0x21,0x7C], - u"ö": [0x38,0x45,0x44,0x45,0x38], - u"Ä": [0x7C,0x13,0x12,0x13,0x7C], - u"Ü": [0x3E,0x41,0x40,0x41,0x3E], - u"Ö": [0x3C,0x43,0x42,0x43,0x3C], - u"ß": [0x7F,0x01,0x49,0x4e,0x30], + "`": [0x00, 0x01, 0x02, 0x04, 0x00], + "a": [0x20, 0x54, 0x54, 0x54, 0x78], + "b": [0x7F, 0x50, 0x48, 0x48, 0x30], + "c": [0x38, 0x44, 0x44, 0x44, 0x20], + "d": [0x38, 0x44, 0x44, 0x48, 0x7F], + "e": [0x38, 0x54, 0x54, 0x54, 0x18], + "f": [0x08, 0x7E, 0x09, 0x01, 0x02], + "g": [0x0C, 0x54, 0x54, 0x54, 0x3C], + "h": [0x7F, 0x08, 0x04, 0x04, 0x78], + "i": [0x00, 0x44, 0x7D, 0x40, 0x00], + "j": [0x20, 0x40, 0x44, 0x3D, 0x00], + "k": [0x7F, 0x10, 0x28, 0x44, 0x00], + "l": [0x00, 0x41, 0x7F, 0x40, 0x00], + "m": [0x78, 0x04, 0x18, 0x04, 0x78], + "n": [0x7C, 0x08, 0x04, 0x04, 0x78], + "o": [0x38, 0x44, 0x44, 0x44, 0x38], - u"‘": [0x00,0x00,0x03,0x00,0x00], - u"’": [0x00,0x00,0x03,0x00,0x00], - u"‚": [0x00,0x00,0x60,0x00,0x00], + "p": [0x7C, 0x14, 0x14, 0x14, 0x08], + "q": [0x08, 0x14, 0x14, 0x18, 0x7C], + "r": [0x7C, 0x08, 0x04, 0x04, 0x08], + "s": [0x48, 0x54, 0x54, 0x54, 0x20], + "t": [0x04, 0x3F, 0x44, 0x40, 0x20], + "u": [0x3C, 0x40, 0x40, 0x20, 0x7C], + "v": [0x1C, 0x20, 0x40, 0x20, 0x1C], + "w": [0x3C, 0x40, 0x30, 0x40, 0x3C], + "x": [0x44, 0x28, 0x10, 0x28, 0x44], + "y": [0x0C, 0x50, 0x50, 0x50, 0x3C], + "z": [0x44, 0x64, 0x54, 0x4C, 0x44], + "{": [0x00, 0x08, 0x36, 0x41, 0x00], + "|": [0x00, 0x00, 0x7F, 0x00, 0x00], + "}": [0x00, 0x41, 0x36, 0x08, 0x00], + "~": [0x0C, 0x02, 0x0C, 0x10, 0x0C], + "\x7f": [0x55, 0xAA, 0x55, 0xAA, 0x55], - u"“": [0x00,0x03,0x00,0x03,0x00], - u"”": [0x00,0x03,0x00,0x03,0x00], - u"„": [0x00,0x60,0x00,0x60,0x00], + u"ä": [0x20, 0x55, 0x54, 0x55, 0x78], + u"ü": [0x3C, 0x41, 0x40, 0x21, 0x7C], + u"ö": [0x38, 0x45, 0x44, 0x45, 0x38], + u"Ä": [0x7C, 0x13, 0x12, 0x13, 0x7C], + u"Ü": [0x3E, 0x41, 0x40, 0x41, 0x3E], + u"Ö": [0x3C, 0x43, 0x42, 0x43, 0x3C], + u"ß": [0x7F, 0x01, 0x49, 0x4e, 0x30], - u"›": [0x00,0x00,0x28,0x10,0x00], - u"‹": [0x00,0x10,0x28,0x00,0x00], - u"»": [0x28,0x10,0x28,0x10,0x00], - u"«": [0x00,0x10,0x28,0x10,0x28], + u"‘": [0x00, 0x00, 0x03, 0x00, 0x00], + u"’": [0x00, 0x00, 0x03, 0x00, 0x00], + u"‚": [0x00, 0x00, 0x60, 0x00, 0x00], - u"☐": [0xff,0x41,0x41,0x41,0xff], + u"“": [0x00, 0x03, 0x00, 0x03, 0x00], + u"”": [0x00, 0x03, 0x00, 0x03, 0x00], + u"„": [0x00, 0x60, 0x00, 0x60, 0x00], + + u"›": [0x00, 0x00, 0x28, 0x10, 0x00], + u"‹": [0x00, 0x10, 0x28, 0x00, 0x00], + u"»": [0x28, 0x10, 0x28, 0x10, 0x00], + u"«": [0x00, 0x10, 0x28, 0x10, 0x28], + + u"☐": [0xff, 0x41, 0x41, 0x41, 0xff], } -import client -import clearscreen -def test(): +def test() -> None: clearscreen.clear() - client.write(0,0,"Hello World!") + client.write(0, 0, "Hello World!") x = 0 y = 1 for c in sorted(FONT.keys()): - client.blit(x*client.PWIDTH, y*client.PHEIGHT, - client.PWIDTH, client.PHEIGHT, client.char_to_pixel_segment(c)) + client.blit(x * client.PWIDTH, y * client.PHEIGHT, + client.PWIDTH, client.PHEIGHT, client.char_to_pixel_segment(c)) x += 1 - if(x > 15): + if (x > 15): x = 0 y += 1 diff --git a/python/brightness_test.py b/python/brightness_test.py index cc67d0c06fdcd6e49eae05b5184eba1e6cd4ad12..efd3525d94dd883e263a7024435d75028411fa1a 100755 --- a/python/brightness_test.py +++ b/python/brightness_test.py @@ -1,11 +1,13 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 import client -def bright(b, x, y, w, h): - pixels = [b] * w * h - client.blit(x,y,w,h,pixels) -if __name__=="__main__": +def bright(b: int, x: int, y: int, w: int, h: int) -> None: + pixels = bytes([b] * w * h) + client.blit(x, y, w, h, pixels) + + +if __name__ == "__main__": bright(0, 0, 0, 480, 70) - for i in range(0,16): - bright(i*16, i*20, 0, 19, 70) + for i in range(0, 16): + bright(i * 16, i * 20, 0, 19, 70) diff --git a/python/cat.py b/python/cat.py old mode 100644 new mode 100755 index 3081ceb7e366935803072458075264527d66e99a..0a0312ee83e8603aca9db85ee28f6d52f1a43e5c --- a/python/cat.py +++ b/python/cat.py @@ -1,11 +1,10 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 import sys import client # read lines from stdin and write them to the display. -line = sys.stdin.readline().decode("utf8") -while(line != ""): +line = sys.stdin.readline() +while line != "": client.writeline(line) - line = sys.stdin.readline().decode("utf8") - + line = sys.stdin.readline() diff --git a/python/clearscreen.py b/python/clearscreen.py index 1e451973d69fcd7422f1689f040250276912fd20..c62cc1311030043cc4b3d7839892fef0df873adf 100755 --- a/python/clearscreen.py +++ b/python/clearscreen.py @@ -1,10 +1,11 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 import client -import random -def clear(): - pixels = [0] * client.HEIGHT * client.WIDTH - client.blit(0,0,client.WIDTH,client.HEIGHT,pixels) -if __name__=="__main__": +def clear(value: int = 0) -> None: + pixels = bytes([value,] * (client.HEIGHT * client.WIDTH)) + client.blit(0, 0, client.WIDTH, client.HEIGHT, pixels) + + +if __name__ == "__main__": clear() diff --git a/python/client.py b/python/client.py index 063050fbbcbbfa1650b7ea3f887cdb6f72e69464..9897fb296a6f7e72a926bdc34beb2d9fc601fa70 100644 --- a/python/client.py +++ b/python/client.py @@ -1,6 +1,10 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 # -*- coding: utf-8 -*- +from typing import Sequence +import zmq +import struct +import sys import os import bitmapfont @@ -9,28 +13,25 @@ SPLIT_I = 0 SPLIT = os.environ.get("SPLIT") if SPLIT: - SPLIT = list(map(int, SPLIT.split('/'))) - SPLIT_N = SPLIT[1] - SPLIT_I = SPLIT[0]-1 + SPLITx = [int(s) for s in SPLIT.split('/', 1)] + SPLIT_N = SPLITx[1] + SPLIT_I = SPLITx[0] - 1 -NUM_SEG_X = 96 -NUM_SEG_Y = 10 +NUM_SEG_X: int = 96 +NUM_SEG_Y: int = 10 PWIDTH = 5 -WIDTH = int(PWIDTH*NUM_SEG_X/SPLIT_N) -WOFFSET = (WIDTH*SPLIT_I) +WIDTH = PWIDTH * NUM_SEG_X // SPLIT_N +WOFFSET = WIDTH * SPLIT_I PHEIGHT = 7 PPAD = 5 -HEIGHT = int(PHEIGHT*NUM_SEG_Y) +HEIGHT = PHEIGHT * NUM_SEG_Y -import sys SERVER = "tcp://mensadisplay:5556" if len(sys.argv) >= 2: - SERVER = sys.argv[1] + SERVER = sys.argv[1] -import struct -import zmq context = zmq.Context() socket = context.socket(zmq.REQ) @@ -40,84 +41,103 @@ socket.connect(SERVER) # RAW PIXEL HANDLING ################################################################################ -def set_pixel(x, y, v): - x += WOFFSET - tx = struct.pack('<BiiB', 0, x, y, v) - socket.send_multipart([tx, b'']) - rx = socket.recv() - #print("Received reply %s [%r]" % ((x, y, v), rx)) -def set_pixels(pixels): - msg = [] - for x, y, v in pixels: +def set_pixel(x: int, y: int, v: int) -> None: + x += WOFFSET + tx = struct.pack('<BiiB', 0, x, y, v) + socket.send_multipart([tx, b'']) + socket.recv() + + +def set_pixels(pixels: Sequence[tuple[int, int, int]]) -> None: + msg = [] + for x, y, v in pixels: + x += WOFFSET + msg.append(struct.pack('<BiiB', 0, x, y, v)) + socket.send_multipart(msg + [b'']) + socket.recv() + + +def blit(x: int, y: int, w: int, h: int, pixels: bytes, rec: bool = True) -> None: x += WOFFSET - msg.append(struct.pack('<BiiB', 0, x, y, v)) - socket.send_multipart(msg + [b'']) - rx = socket.recv() + assert w * h == len(pixels) + msg = struct.pack('<Biiii', 1, x, y, w, h) + pixels + socket.send_multipart([msg, b'']) + if rec: + socket.recv() -def blit(x, y, w, h, pixels, rec=True): - x += WOFFSET - assert w*h == len(pixels) - msg = struct.pack('<Biiii', 1, x, y, w, h)+bytes(pixels) - socket.send_multipart([msg, b'']) - if rec: - rx = socket.recv() -def rec(): - rx = socket.recv() +def rec() -> bytes: + return socket.recv() ################################################################################ # TEXT RENDERING WITH BITMAP FONT ################################################################################ + # screen buffer used for text handling -SCREENBUFFER = [0] * WIDTH * HEIGHT +SCREENBUFFER = bytearray(WIDTH * HEIGHT) + -# blit to screen buffer, also updates screen -def screenbuf_blit(x, y, w, h, pixels): +def screenbuf_blit(x: int, y: int, w: int, h: int, pixels: bytes) -> None: + """ + blit to screen buffer, also updates screen + """ blit(x, y, w, h, pixels) - assert w*h == len(pixels) + assert w * h == len(pixels) for dy in range(0, h): for dx in range(0, w): - if(y+dy >= HEIGHT or x+dx >= WIDTH): + if y + dy >= HEIGHT or x + dx >= WIDTH: return - pix = pixels[dy * w + dx]; - SCREENBUFFER[(y+dy) * WIDTH + (x+dx)] = pix + pix = pixels[dy * w + dx] + SCREENBUFFER[(y + dy) * WIDTH + (x + dx)] = pix + -# scroll the screen buffer up y pixels, also updates screen -def screenbuf_scroll(y): +def screenbuf_scroll(y: int) -> None: + """ + scroll the screen buffer up y pixels, also updates screen + """ buf = SCREENBUFFER for dy in range(y, HEIGHT): for x in range(0, WIDTH): - SCREENBUFFER[(dy-y) * WIDTH + x] = buf[dy * WIDTH + x] + SCREENBUFFER[(dy - y) * WIDTH + x] = buf[dy * WIDTH + x] screenbuf_render() -# draw screen buffer to screen -def screenbuf_render(): + +def screenbuf_render() -> None: + """ + draw screen buffer to screen + """ blit(0, 0, WIDTH, HEIGHT, SCREENBUFFER) -# return array of size PWIDTH * PHEIGHT (indexed by row, then column) -def char_to_pixel_segment(c): - pixels = [0] * PWIDTH * PHEIGHT - if(c not in list(bitmapfont.FONT.keys())): - c = "☐"; +def char_to_pixel_segment(c: str) -> bytes: + """ + return array of size PWIDTH * PHEIGHT (indexed by row, then column) + """ + pixels = bytearray(PWIDTH * PHEIGHT) + + if (c not in list(bitmapfont.FONT.keys())): + c = "☐" for x in range(0, PWIDTH): for y in range(0, PHEIGHT): - pix = (bitmapfont.FONT[c][x] & (1<<y)) >> y + pix = (bitmapfont.FONT[c][x] & (1 << y)) >> y pixels[y * PWIDTH + x] = pix * 255 return pixels -# write string, starting at segment x,y. Tabs are expanded to 8 spaces, new -# lines always begin at the given x position. No boundary checks are done, text -# may be clipped at the border, in this case the function returns. -# This function returns a tuple (x,y,success) where (x,y) gives the position of -# the last character written, and success is set to False if the function -# returned because of clipped text. -def write(x, y, string): + +def write(x: int, y: int, string: str) -> tuple[int, int, bool]: + """ + write string, starting at segment x,y. Tabs are expanded to 8 spaces, new + lines always begin at the given x position. No boundary checks are done, text + may be clipped at the border, in this case the function returns. + This function returns a tuple (x, y, success) where (x, y) gives the position of + the last character written, and success is set to False if the function + returned because of clipped text. + """ orig_x = x - string = string.replace("\t", " "*8) + string = string.replace("\t", " " * 8) for c in string: if c == "\n": y += 1 @@ -126,34 +146,39 @@ def write(x, y, string): pass else: pixels = char_to_pixel_segment(c) - screenbuf_blit(x*PWIDTH, y*PHEIGHT, PWIDTH, PHEIGHT, pixels) + screenbuf_blit(x * PWIDTH, y * PHEIGHT, PWIDTH, PHEIGHT, pixels) x += 1 - if(x > NUM_SEG_X): - return (x,y,False) + if (x > NUM_SEG_X): + return (x, y, False) + + return (x, y, True) - return (x,y,True) # write line to screen as if on a terminal, scroll up if neccessary cur_line = 0 -def writeline(string): + + +def writeline(string: str) -> None: global cur_line - if(cur_line >= NUM_SEG_Y): + if cur_line >= NUM_SEG_Y: scrollline() cur_line -= 1 - (new_x, new_y, success) = write(0, cur_line, string.strip("\r\n")) + new_x, new_y, _ = write(0, cur_line, string.strip("\r\n")) cur_line = new_y # clear remaining row - clear_chars = (NUM_SEG_X-new_x) + clear_chars = (NUM_SEG_X - new_x) screenbuf_blit(new_x * PWIDTH, cur_line * PHEIGHT, - clear_chars * PWIDTH, PHEIGHT, - [0] * clear_chars * PWIDTH * PHEIGHT) + clear_chars * PWIDTH, PHEIGHT, + bytes(clear_chars * PWIDTH * PHEIGHT)) cur_line += 1 -# scroll the content y lines up and clear last line -def scrollline(y = 1): - screenbuf_scroll(y*PHEIGHT) - screenbuf_blit(0, (NUM_SEG_Y-1) * PHEIGHT, WIDTH, PHEIGHT, - [0] * WIDTH * PHEIGHT) + +def scrollline(y: int = 1) -> None: + """ + scroll the content y lines up and clear last line + """ + screenbuf_scroll(y * PHEIGHT) + screenbuf_blit(0, (NUM_SEG_Y - 1) * PHEIGHT, WIDTH, PHEIGHT, bytes(WIDTH * PHEIGHT)) diff --git a/python/clock.py b/python/clock.py index ffd1c008ada5568c632aa856e0ae84f2d5329c0a..038c3a9ed5413553a60b815222a8920b5eb10347 100755 --- a/python/clock.py +++ b/python/clock.py @@ -1,12 +1,9 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 import font_client - from datetime import datetime - import dateutil.tz while True: - #font_client.draw(datetime.now().isoformat(), points=30) - font_client.draw(datetime.now(dateutil.tz.tzlocal()).isoformat(), points=10) - + # font_client.draw(datetime.now().isoformat(), points=30) + font_client.draw(datetime.now(dateutil.tz.tzlocal()).isoformat(), points=20) diff --git a/python/cornerclock.py b/python/cornerclock.py index dda96a3a6c0771024453442a8305e91392c2a72e..389ac9fcf27c4e17ff0f14643054f984fd33de68 100755 --- a/python/cornerclock.py +++ b/python/cornerclock.py @@ -1,4 +1,4 @@ -#/usr/bin/env python +#!/usr/bin/env python3 import datetime import time @@ -6,6 +6,5 @@ import client while True: t = datetime.datetime.now().strftime(" %H:%M:%S") - client.write(client.NUM_SEG_X - len(t), 0, t); + client.write(client.NUM_SEG_X - len(t), 0, t) time.sleep(1) - diff --git a/python/dodecahedra.py b/python/dodecahedra.py old mode 100644 new mode 100755 index 705b0bb44ba9e0356bb88b15833adc31210ce42c..1fdd441d5b23146372625f3211ac7acd9af3d874 --- a/python/dodecahedra.py +++ b/python/dodecahedra.py @@ -1,5 +1,6 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 # Raoul, Hackover 2014, GPL v2 +from typing import Any, List import client import time from numpy import sin, cos, pi, array, clip, linspace, dot @@ -17,6 +18,7 @@ xmax = client.WIDTH - sigma * B ymax = client.HEIGHT - tau * B - 2 NT = 12 + def cube(a=10): vert = [(-a, -a, -a), (-a, a, -a), @@ -46,26 +48,26 @@ edge_map_cube = [(0, 1), def dode(a=15): p = 1.618033 q = 1.0 - vert = [(-q, -q, -q), # 0 + vert = [(-q, -q, -q), # 0 (-q, q, -q), (q, q, -q), (q, -q, -q), - (-q, -q, q), # 4 + (-q, -q, q), # 4 (-q, q, q), (q, q, q), (q, -q, q), - (0, 1/p, p), # 8 - (0, -1/p, p), - (0, 1/p, -p), - (0, -1/p, -p), - (p, 0, 1/p), # 12 - (-p, 0, 1/p), - (p, 0, -1/p), - (-p, 0, -1/p), - (1/p, p, 0), # 16 - (-1/p, p, 0), - (1/p, -p, 0), - (-1/p, -p, 0)] + (0, 1 / p, p), # 8 + (0, -1 / p, p), + (0, 1 / p, -p), + (0, -1 / p, -p), + (p, 0, 1 / p), # 12 + (-p, 0, 1 / p), + (p, 0, -1 / p), + (-p, 0, -1 / p), + (1 / p, p, 0), # 16 + (-1 / p, p, 0), + (1 / p, -p, 0), + (-1 / p, -p, 0)] # # 5---------6 # / 8 / @@ -79,7 +81,7 @@ def dode(a=15): # |Y 11 / # 0-X-------3 # - return a*array(vert) + return a * array(vert) edge_map_dode = [(3, 14), @@ -92,11 +94,11 @@ edge_map_dode = [(3, 14), (4, 13), (5, 13), (13, 15), - (1,10), - (2,10), + (1, 10), + (2, 10), (0, 11), (3, 11), - (10,11), + (10, 11), (4, 9), (7, 9), (5, 8), @@ -114,28 +116,28 @@ edge_map_dode = [(3, 14), (17, 16)] -def rotatex(vertl, phi = pi/3): - Rx = array([[1, 0, 0], - [0, cos(phi), sin(phi)], +def rotatex(vertl, phi=pi / 3): + Rx = array([[1, 0, 0], + [0, cos(phi), sin(phi)], [0, -sin(phi), cos(phi)]]) return dot(Rx, vertl.T).T -def rotatey(vertl, phi = pi/3): - Ry = array([[ cos(phi), 0, sin(phi)], - [ 0, 1, 0], +def rotatey(vertl, phi=pi / 3): + Ry = array([[cos(phi), 0, sin(phi)], + [0, 1, 0], [-sin(phi), 0, cos(phi)]]) return dot(Ry, vertl.T).T -def rotatez(vertl, phi = pi/3): - Rz = array([[ cos(phi), sin(phi), 0], +def rotatez(vertl, phi=pi / 3): + Rz = array([[cos(phi), sin(phi), 0], [-sin(phi), cos(phi), 0], - [ 0, 0, 1]]) + [0, 0, 1]]) return dot(Rz, vertl.T).T -def propagate(x, v): +def propagate(x, v) -> None: ti = x[:] + v[:] x[:] = ti if abs(ti[0]) < xmin or abs(ti[0]) > xmax: @@ -159,8 +161,8 @@ def project(vertlist): def reflect(v1, v2, n): - v1n = v1 - 2*dot(v1, n) * n - v2n = v2 - 2*dot(v2, n) * n + v1n = v1 - 2 * dot(v1, n) * n + v2n = v2 - 2 * dot(v2, n) * n return v1n, v2n @@ -168,32 +170,31 @@ def line(u, v): xd = v[0] - u[0] yd = v[1] - u[1] t = linspace(0, 1, NT) - lx = u[0] + xd*t - ly = u[1] + yd*t + lx = u[0] + xd * t + ly = u[1] + yd * t return lx.round(), ly.round() def show(vl, el): - pixels = [] - pixelsold = [] + pixels: list[tuple[int, int, int]] = [] + pixelsold: list[tuple[int, int, int]] = [] for e in el: lx, ly = line(vl[e[0]], vl[e[1]]) - for lxi, lyi in zip(lx, ly): - pixels.append( (lxi, lyi, 255) ) - pixelsold.append( (lxi, lyi, 0) ) - + for lxi, lyi in zip(map(int, lx), map(int, ly)): + pixels.append((lxi, lyi, 255)) + pixelsold.append((lxi, lyi, 0)) return pixels, pixelsold -def clear(): - pixels = [0] * client.HEIGHT * client.WIDTH +def clear() -> None: + pixels = bytes(client.HEIGHT * client.WIDTH) client.blit(0, 0, client.WIDTH, client.HEIGHT, pixels) -if __name__=="__main__": - x1 = array([CENX-100, CENY, 0]) +if __name__ == "__main__": + x1 = array([CENX - 100, CENY, 0]) v1 = array([1.5, 0.75, 0]) - x2 = array([CENX+100, CENY, 0]) + x2 = array([CENX + 100, CENY, 0]) v2 = array([-2.5, -0.25, 0]) c1 = dode(16) @@ -201,22 +202,22 @@ if __name__=="__main__": m = edge_map_dode offset = len(c1) - m += [(mi[0]+offset, mi[1]+offset) for mi in m] + m += [(mi[0] + offset, mi[1] + offset) for mi in m] - c1 = rotatez(c1, pi/4.0) - c1 = rotatex(c1, pi/3.0) - c2 = rotatez(c2, pi/4.0) - c2 = rotatex(c2, pi/3.0) + c1 = rotatez(c1, pi / 4.0) + c1 = rotatex(c1, pi / 3.0) + c2 = rotatez(c2, pi / 4.0) + c2 = rotatex(c2, pi / 3.0) - r1y = pi/50 - r1z = pi/30 - r2y = -pi/30 - r2z = -pi/50 + r1y = pi / 50 + r1z = pi / 30 + r2y = -pi / 30 + r2z = -pi / 50 ti = 0 - pixold = [] + pixold: list[tuple[int, int, int]] = [] clear() - while(True): + while (True): c1 = rotatey(c1, r1y) c1 = rotatez(c1, r1z) c2 = rotatey(c2, r2y) @@ -227,28 +228,28 @@ if __name__=="__main__": n = x1 - x2 if norm(n) < 54: - v1, v2 = reflect(v1, v2, n/norm(n)) - ry = clip(2*random.uniform(), -1.5, 1.5) - rz = clip(2*random.uniform(), -1.5, 1.5) - r1y = clip(r1y*ry, -0.28, 0.28) - r1z = clip(r1z*rz, -0.28, 0.28) - r2y = clip(r2y*ry, -0.28, 0.28) - r2z = clip(r2z*rz, -0.28, 0.28) + v1, v2 = reflect(v1, v2, n / norm(n)) + ry = clip(2 * random.uniform(), -1.5, 1.5) + rz = clip(2 * random.uniform(), -1.5, 1.5) + r1y = clip(r1y * ry, -0.28, 0.28) + r1z = clip(r1z * rz, -0.28, 0.28) + r2y = clip(r2y * ry, -0.28, 0.28) + r2z = clip(r2z * rz, -0.28, 0.28) cc1 = project(move(c1, x1)) cc2 = project(move(c2, x2)) - pix, pixoldn = show(cc1+cc2, m) - client.set_pixels(pixold+pix) + pix, pixoldn = show(cc1 + cc2, m) + client.set_pixels(pixold + pix) pixold = pixoldn ti += 1 if ti > 2000: ti = 0 pixold = [] - x1 = array([CENX-100, CENY, 0]) + x1 = array([CENX - 100, CENY, 0]) v1 = array([1.5, 0.75, 0]) - x2 = array([CENX+100, CENY, 0]) + x2 = array([CENX + 100, CENY, 0]) v2 = array([-2.5, -0.25, 0]) clear() diff --git a/python/fire.py b/python/fire.py index 00106adc79b01c868df38627eb12744481928cff..74f7b388a737de93f901c0ee3fac345d531fb5e0 100755 --- a/python/fire.py +++ b/python/fire.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 import client import random import math @@ -6,54 +6,63 @@ import math """ Fire effect """ cool_offs = 0 -cool_map = [0] * client.HEIGHT * client.WIDTH -for x in range(1, client.WIDTH-2): - for y in range(1, client.HEIGHT-2): - cool_map[y*client.WIDTH + x] = random.random() * 3 + math.sin((x + random.random()*10)/480.0*math.pi*7) * math.sin((y + random.random() * 10)/70.0*math.pi*5) * 3 +cool_map = [0,] * (client.HEIGHT * client.WIDTH) +for x in range(1, client.WIDTH - 2): + for y in range(1, client.HEIGHT - 2): + cool_map[y * client.WIDTH + x] = int(random.random() * 3 + math.sin((x + random.random() * 10) / 480.0 * math.pi * 7) * math.sin((y + random.random() * 10) / 70.0 * math.pi * 5) * 3) -def init_fire(): - current = [0] * client.HEIGHT * client.WIDTH +def init_fire() -> bytes: + current = bytearray(client.HEIGHT * client.WIDTH) return current -# Smooth image and cool (darken) pixels according to cool_map -def avg_cooled(x, y, buf): - res = 0 - res += buf[(y*client.WIDTH) + x-1] - res += buf[(y*client.WIDTH) + x+1] - res += buf[(y*client.WIDTH-1) + x] - res += buf[(y*client.WIDTH+1) + x] - res += buf[(y*client.WIDTH) + x] - res = int(res / 5.0 - cool_map[(y+ cool_offs)%client.HEIGHT*client.WIDTH + x]) - if res < 0: - res = 0 - return res - -# Move everything up one pixel and generate new fire at the bottom -def move_and_smooth(current, new): + +def avg_cooled(x: int, y: int, buf: bytes) -> int: + """ + Smooth image and cool (darken) pixels according to cool_map + """ + res = 0 + res += buf[(y * client.WIDTH) + x - 1] + res += buf[(y * client.WIDTH) + x + 1] + res += buf[(y * client.WIDTH - 1) + x] + res += buf[(y * client.WIDTH + 1) + x] + res += buf[(y * client.WIDTH) + x] + res = int(res / 5.0 - cool_map[(y + cool_offs) % client.HEIGHT * client.WIDTH + x]) + if res < 0: + res = 0 + return res + +# + + +def move_and_smooth(current: bytes, new: bytearray) -> None: + """ + Move everything up one pixel and generate new fire at the bottom + """ global cool_offs - for x in range(1, client.WIDTH-2): - for y in range(1, client.HEIGHT-2): - new[y*client.WIDTH + x] = avg_cooled(x, y+1, current) - for i in range(5, client.WIDTH-5, 3): + for x in range(1, client.WIDTH - 2): + for y in range(1, client.HEIGHT - 2): + new[y * client.WIDTH + x] = avg_cooled(x, y + 1, current) + for i in range(5, client.WIDTH - 5, 3): bright = int(random.random() * 180 + 70) - new[(client.HEIGHT-1) * client.WIDTH + i] = bright - new[(client.HEIGHT-1) * client.WIDTH + i + 1] = bright - new[(client.HEIGHT-1) * client.WIDTH + i + 2] = bright - new[(client.HEIGHT-2) * client.WIDTH + i] = bright - new[(client.HEIGHT-2) * client.WIDTH + i + 1] = bright - new[(client.HEIGHT-2) * client.WIDTH + i + 2] = bright + new[(client.HEIGHT - 1) * client.WIDTH + i] = bright + new[(client.HEIGHT - 1) * client.WIDTH + i + 1] = bright + new[(client.HEIGHT - 1) * client.WIDTH + i + 2] = bright + new[(client.HEIGHT - 2) * client.WIDTH + i] = bright + new[(client.HEIGHT - 2) * client.WIDTH + i + 1] = bright + new[(client.HEIGHT - 2) * client.WIDTH + i + 2] = bright # The cool map moves as well cool_offs = (cool_offs - 1) % client.HEIGHT -if __name__=="__main__": + +if __name__ == "__main__": current = init_fire() - new = [0] * client.HEIGHT * client.WIDTH - sending = [(x*x)/256 for x in current] + new = bytearray(client.HEIGHT * client.WIDTH) + sending = bytes([(x * x) // 256 for x in current]) while (True): - client.blit(0, 0, client.WIDTH, client.HEIGHT, sending, rec = False) - move_and_smooth(current, new) - current = new - # x^2 will work better with the brightness levels we have - sending = [(x*x)/256 for x in current] - client.rec() + client.blit(0, 0, client.WIDTH, client.HEIGHT, sending, rec=False) + move_and_smooth(current, new) + current = new + # x^2 will work better with the brightness levels we have + sending = bytes([(x * x) // 256 for x in current]) + client.rec() diff --git a/python/font_client.py b/python/font_client.py index 68f71fe0ae9d22a5828725b761e07389ac6be552..3e9ea7ec37d36ca059a22887f6870ad668874986 100755 --- a/python/font_client.py +++ b/python/font_client.py @@ -1,6 +1,8 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 -import sys, client +import sys +from typing import Optional +import client import pygame pygame.init() @@ -9,7 +11,8 @@ screen = pygame.Surface((client.WIDTH, client.HEIGHT), depth=8) prev_screen = None -def send(screen): + +def send(screen: pygame.Surface) -> None: global prev_screen w = screen.get_width() h = screen.get_height() @@ -24,66 +27,68 @@ def send(screen): xs.add(x) ys.add(y) else: - xs = set((0, client.WIDTH-1)) - ys = set((0, client.HEIGHT-1)) + xs = set((0, client.WIDTH - 1)) + ys = set((0, client.HEIGHT - 1)) if not xs: return prev_screen = screen.copy() pixels = [] - for y in range(min(ys), max(ys)+1): - for x in range(min(xs), max(xs)+1): + for y in range(min(ys), max(ys) + 1): + for x in range(min(xs), max(xs) + 1): pixels.append(pxarray[x][y]) del pxarray - client.blit(min(xs), min(ys), max(xs)-min(xs)+1, max(ys)-min(ys)+1, pixels) + client.blit(min(xs), min(ys), max(xs) - min(xs) + 1, max(ys) - min(ys) + 1, bytes(pixels)) + prev_mx = None font = None -def draw(text, mark=None, points=None): + +def draw(text: str, mark: Optional[int] = None, points: Optional[int] = None) -> None: global prev_mx, font points = points if points else 35 if mark else 60 font = pygame.font.SysFont("DejaVu Sans Mono", points, bold=True) count = len(text) - text = font.render(text, True, (255, 255, 255), (0, 0, 0)) - screen.set_palette(text.get_palette()) + rendered_text = font.render(text, True, (255, 255, 255), (0, 0, 0)) + screen.set_palette(rendered_text.get_palette()) screen.fill((0, 0, 0)) - w = text.get_width() - h = text.get_height() - x = (client.WIDTH-w)/2 - y = (client.HEIGHT-h)/2 + w = rendered_text.get_width() + h = rendered_text.get_height() + x = (client.WIDTH - w) / 2 + y = (client.HEIGHT - h) / 2 if mark: - cw = w/count - mx = x+cw*(mark+0.5) + cw = w / count + mx = x + cw * (mark + 0.5) if not mx == prev_mx: for size in range(240, 5, -15): pygame.draw.line(screen, 255, - (mx, 0), - (mx, client.HEIGHT-1), - size) + (mx, 0), + (mx, client.HEIGHT - 1), + size) send(screen) pygame.draw.line(screen, 0, - (mx, 0), - (mx, client.HEIGHT-1), - size) + (mx, 0), + (mx, client.HEIGHT - 1), + size) prev_mx = mx pygame.draw.line(screen, 255, - (mx, 0), - (mx, client.HEIGHT-1), - 5) - screen.blit(text, (x, y)) + (mx, 0), + (mx, client.HEIGHT - 1), + 5) + screen.blit(rendered_text, (x, y)) send(screen) -if __name__=="__main__": + +if __name__ == "__main__": if len(sys.argv) >= 3: - text = sys.argv[2].decode('utf-8') + text = sys.argv[2] else: text = "Hello World!" + mark: Optional[int] = None if len(sys.argv) >= 4: mark = int(sys.argv[3]) - else: - mark = None draw(text, mark) diff --git a/python/fonts/5x7.pcf.gz b/python/fonts/5x7.pcf.gz new file mode 100644 index 0000000000000000000000000000000000000000..e58bdef21e6a55a8204cb1f682687608710a7fee Binary files /dev/null and b/python/fonts/5x7.pcf.gz differ diff --git a/python/gol-client.py b/python/gol-client.py index 7acdb9442c0ec497b7c1a753d7d567a00e913734..c39bb7f5b75ffa57b9700d338610ab631b61a918 100755 --- a/python/gol-client.py +++ b/python/gol-client.py @@ -1,59 +1,28 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 +import random +import time +from typing import Sequence import client SIZE = 1 -import time -def rect(x,y,w,h,r,g,b): +def rect(x: int, y: int, w: int, h: int, r: int, g: int, b: int) -> None: pixels = [] - for i in xrange(x,x+w): - for j in xrange(y,y+h): - #pixel(i,j,r,g,b) + for i in range(x, x + w): + for j in range(y, y + h): + # pixel(i,j,r,g,b) pixels.append((i, j, r)) client.set_pixels(pixels) -def draw(x, y, v): - rect(x*SIZE, y*SIZE, SIZE, SIZE, 255*v, 255*v, 255*v) - -import random - -class Game(object): - def __init__(self, state, infinite_board = True): - self.state = state - self.width = state.width - self.height = state.height - self.infinite_board = infinite_board - - def step(self, count = 1): - for generation in range(count): - new_board = [[False] * self.width for row in range(self.height)] - - for y, row in enumerate(self.state.board): - for x, cell in enumerate(row): - neighbours = self.neighbours(x, y) - previous_state = self.state.board[y][x] - should_live = neighbours == 3 or (neighbours == 2 and previous_state == True) - new_board[y][x] = should_live - - self.state.update(new_board) - - def neighbours(self, x, y): - count = 0 - - for hor in [-1, 0, 1]: - for ver in [-1, 0, 1]: - if not hor == ver == 0 and (self.infinite_board == True or (0 <= x + hor < self.width and 0 <= y + ver < self.height)): - count += self.state.board[(y + ver) % self.height][(x + hor) % self.width] - return count +def draw(x: int, y: int, v: int) -> None: + rect(x * SIZE, y * SIZE, SIZE, SIZE, 255 * v, 255 * v, 255 * v) - def display(self): - return self.state.display() class State(object): - def __init__(self, positions, x, y, width, height): + def __init__(self, positions: str, x: int, y: int, width: int, height: int): self.width = width self.height = height self.board = [[False] * self.width for row in range(self.height)] @@ -63,23 +32,23 @@ class State(object): for l, row in enumerate(positions.splitlines()): for r, cell in enumerate(row.strip()): if cell == 'o': - active_cells.append((r,l)) + active_cells.append((r, l)) board = [[False] * width for row in range(height)] - for cell in active_cells: - board[cell[1] + y][cell[0] + x] = True + for active_cell in active_cells: + board[active_cell[1] + y][active_cell[0] + x] = True self.update(board) - def update(self, new): + def update(self, new: Sequence[Sequence[bool]]) -> None: for y, row in enumerate(new): for x, cell in enumerate(row): if self.board[y][x] != cell: self.board[y][x] = cell draw(x, y, cell) - def display(self): + def display(self) -> str: output = '' for y, row in enumerate(self.board): @@ -92,6 +61,41 @@ class State(object): return output + +class Game(object): + def __init__(self, state: State, infinite_board: bool = True): + self.state = state + self.width = state.width + self.height = state.height + self.infinite_board = infinite_board + + def step(self, count: int = 1) -> None: + for generation in range(count): + new_board = [[False] * self.width for row in range(self.height)] + + for y, row in enumerate(self.state.board): + for x, cell in enumerate(row): + neighbours = self.neighbours(x, y) + previous_state = self.state.board[y][x] + should_live = neighbours == 3 or (neighbours == 2 and previous_state == True) + new_board[y][x] = should_live + + self.state.update(new_board) + + def neighbours(self, x: int, y: int) -> int: + count = 0 + + for hor in [-1, 0, 1]: + for ver in [-1, 0, 1]: + if not hor == ver == 0 and (self.infinite_board == True or (0 <= x + hor < self.width and 0 <= y + ver < self.height)): + count += self.state.board[(y + ver) % self.height][(x + hor) % self.width] + + return count + + def display(self) -> str: + return self.state.display() + + glider = """ oo. o.o @@ -111,10 +115,10 @@ oo........o...o.oo....o.o........... """ my_game = Game(State(gun, - x = 20, y = 10, - width = client.WIDTH/SIZE, height = client.HEIGHT/SIZE) -) + x=20, y=10, + width=client.WIDTH // SIZE, height=client.HEIGHT // SIZE) + ) while True: - #print my_game.display() + # print my_game.display() my_game.step(1) diff --git a/python/irc.py b/python/irc.py old mode 100644 new mode 100755 index 386f8c000d2b6b1897664657eb3f21ee81a55fc5..306b18e897a9a41ee12f85fdb6f5ec067308dbdd --- a/python/irc.py +++ b/python/irc.py @@ -1,52 +1,53 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 -import sys import socket import string import client -def printline(nick, msg, me=False): - l = len(nick) + 3 - if me: - nick = "* %s " % nick - else: - nick = "<%s> " % nick - while msg: - client.writeline("%s%s" % (nick, msg[:96-len(nick)])) - nick = " " * len(nick) - msg = msg[96-len(nick):].strip() -HOST="irc.freenode.net" -PORT=6667 -NICK="mensadisplay" -IDENT="mensadisplay" -REALNAME="MensaDisplay" -readbuffer="" +def printline(nick: str, msg: str, me: bool = False) -> None: + l = len(nick) + 3 + if me: + nick = "* %s " % nick + else: + nick = "<%s> " % nick + while msg: + client.writeline("%s%s" % (nick, msg[:96 - len(nick)])) + nick = " " * len(nick) + msg = msg[96 - len(nick):].strip() -s=socket.socket( ) + +HOST = "irc.libera.chat" +PORT = 6667 +NICK = "mensadisplay" +IDENT = "mensadisplay" +REALNAME = "MensaDisplay" +readbuffer = b"" + +s = socket.socket() s.connect((HOST, PORT)) -s.send("NICK %s\r\n" % NICK) -s.send("USER %s %s bla :%s\r\n" % (IDENT, HOST, REALNAME)) -s.send("JOIN #stratum0\r\n") -while 1: - readbuffer=readbuffer+s.recv(1024) - temp=string.split(readbuffer, "\n") - readbuffer=temp.pop( ) +s.send(f"NICK {NICK}\r\n".encode("utf-8")) +s.send(f"USER {IDENT} {HOST} bla :{REALNAME}\r\n".encode("utf-8")) +s.send(b"JOIN #stratum0\r\n") +while True: + readbuffer = readbuffer + s.recv(1024) + temp = readbuffer.split(b"\n") + readbuffer = temp.pop() - for line in temp: - line = string.rstrip(line) - line = string.split(line) - print line - if line[1] == "PRIVMSG": - nick = line[0].split("!")[0][1:] - msg = " ".join(line[3:])[1:] - try: - if msg.startswith("\x01ACTION"): - #me - printline(nick, msg[8:-1].decode("utf8"), True) - else: - printline(nick, msg.decode("utf8")) - except UnicodeEncodeError: - pass - if(line[0]=="PING"): - s.send("PONG %s\r\n" % line[1]) \ No newline at end of file + for line in temp: + line = line.rstrip() # string.rstrip(line) + words = line.split() + print(words) + if words[1] == b"PRIVMSG": + nick = words[0].split(b"!")[0][1:].decode("utf8") + msg = b" ".join(words[3:])[1:] + try: + if msg.startswith(b"\x01ACTION"): + # me + printline(nick, msg[8:-1].decode("utf8"), True) + else: + printline(nick, msg.decode("utf8")) + except UnicodeEncodeError: + pass + if (words[0] == b"PING"): + s.send(b"PONG " + words[1] + b"\r\n") diff --git a/python/munching.py b/python/munching.py index 3a783dbd9d02b4f0c31f46824fc04f1ab1fa846b..fb16412c927086b3026f7108be837a5944097c65 100755 --- a/python/munching.py +++ b/python/munching.py @@ -1,23 +1,22 @@ -#!/usr/bin/python +#!/usr/bin/env python3 import client import random import time import clearscreen -if __name__=="__main__": +if __name__ == "__main__": t = 0 s = 64 - pixels = [0] * client.HEIGHT * client.WIDTH + pixels = bytearray(client.HEIGHT * client.WIDTH) clearscreen.clear() while True: if t == 63: time.sleep(1) - t = (t+1) % 64 + t = (t + 1) % 64 for x in range(client.WIDTH): for y in range(client.HEIGHT): - #pixels[s * x + y] = 0 if (y == (x^t)) else 1 - pixels[s * x + y] = 0 if ((x&y&t)) else 255 + # pixels[s * x + y] = 0 if (y == (x^t)) else 1 + pixels[s * x + y] = 0 if ((x & y & t)) else 255 client.blit(0, 0, client.WIDTH, client.HEIGHT, pixels) - print t - #time.sleep(0.09) - + print(t) + # time.sleep(0.09) diff --git a/python/random_pixel.py b/python/random_pixel.py index 6c7fee927c9040b4cc51575631491b24cfd2abe9..244005dd063120d63850f6525005b25ff70f2e97 100755 --- a/python/random_pixel.py +++ b/python/random_pixel.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 import client import random import time @@ -6,18 +6,17 @@ import time blockx = 5 blocky = 7 -if __name__=="__main__": - while(True): - x = random.random() * (client.WIDTH/blockx) - y = random.random() * (client.HEIGHT/blocky) - x = int(x) * blockx - y = int(y) * blocky - if random.random() > 0.5: +if __name__ == "__main__": + while True: + x = random.random() * (client.WIDTH / blockx) + y = random.random() * (client.HEIGHT / blocky) + x = int(x) * blockx + y = int(y) * blocky + if random.random() > 0.5: bright = random.random() - bright = (bright * bright) * 255 - pix = [int(bright)] * blockx * blocky - client.blit(x, y, blockx, blocky, pix) - else: - pix = [0] * blockx * blocky - client.blit(x, y, blockx, blocky, pix) - + bright = (bright * bright) * 255 + pix = bytes([int(bright)] * blockx * blocky) + client.blit(x, y, blockx, blocky, pix) + else: + pix = bytes([0] * blockx * blocky) + client.blit(x, y, blockx, blocky, pix) diff --git a/python/reddit.py b/python/reddit.py index 0d0eaba3139623bd94b0ae332a7dc8292f13b6d2..fe1df9c9c3678657c0d525323f5fdae221e1bab4 100755 --- a/python/reddit.py +++ b/python/reddit.py @@ -1,34 +1,27 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 # 10x48x5x7 Pixel -import client, praw +import client +import praw from time import sleep +import os SERVER = "tcp://localhost:5570" XOFF = 0 YOFF = 0 TEXT = "" -r = praw.Reddit(user_agent='Stratum0 Braunschweig Mensadisplay Parser') -reddit = ["opensource" - ,"linux" - ,"netsec" - ,"sysadmin" - ,"worldnews" - ,"shittyaskscience" - ,"showerthoughts" - ,"explainlikeimcalvin" - ,"pettyrevenge" - ,"all"] +r = praw.Reddit( + client_id=os.environ.get("REDDIT_CLIENT_ID"), + client_secret=os.environ.get("REDDIT_CLIENT_SECRET"), + user_agent='Stratum0 Braunschweig Mensadisplay Parser') +reddit = ["opensource", "linux", "netsec", "sysadmin", "worldnews", "shittyaskscience", "showerthoughts", "explainlikeimcalvin", "pettyrevenge", "all"] while True: - for i in reddit: - client.writeline("reddit.com/r/" + i) - submissions = r.get_subreddit(i).get_hot(limit=9) - subs = [unicode(x) for x in submissions] - for i in range(0,9): - votes,title = subs[i].split(' :: ',1) - TEXT = '%s :: %s' % (votes.rjust(5),title) - print(repr(TEXT)) - client.writeline(TEXT) - sleep(10) + for i in reddit: + client.writeline("reddit.com/r/" + i) + for submission in r.subreddit(i).hot(limit=9): + TEXT = f'{submission.upvote_ratio:5.0f} :: {submission.title}' + print(TEXT) + client.writeline(TEXT) + sleep(10) diff --git a/python/requirements.txt b/python/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..d49aed1e1ac53d040ac761f321e1c4170a55f1f9 --- /dev/null +++ b/python/requirements.txt @@ -0,0 +1,6 @@ +numpy +praw +pygame +python-dateutil +pyzmq +requests diff --git a/python/speedtest.py b/python/speedtest.py index 974775e77369ad627f9882134701e98f05fd1248..60177f1b3be806db7037c5bf39b609f2ccf27606 100755 --- a/python/speedtest.py +++ b/python/speedtest.py @@ -1,8 +1,8 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 import client import random -if __name__=="__main__": +if __name__ == "__main__": for y in range(0, client.HEIGHT): for x in range(0, client.WIDTH): - client.set_pixel(x,y,255) + client.set_pixel(x, y, 255) diff --git a/python/test-client.py b/python/test-client.py index ee3aede1693ce24aff82115512507fb3380fd32d..8a01c3b48397328d0da798c008218a9470306878 100755 --- a/python/test-client.py +++ b/python/test-client.py @@ -1,29 +1,29 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 -import sys, client +import pygame +import sys +import client SERVER = "tcp://localhost:5570" XOFF = 0 YOFF = 0 TEXT = "Hello World!" -if __name__=="__main__": - if len(sys.argv) >= 4: - XOFF = int(sys.argv[2]) - YOFF = int(sys.argv[3]) - if len(sys.argv) >= 5: - TEXT = sys.argv[4] - -import pygame -pygame.init() +if __name__ == "__main__": + if len(sys.argv) >= 4: + XOFF = int(sys.argv[2]) + YOFF = int(sys.argv[3]) + if len(sys.argv) >= 5: + TEXT = sys.argv[4] -font = pygame.font.Font("/usr/share/fonts/X11/misc/5x7.pcf.gz", 7) -text = font.render(TEXT, True, (255, 255, 255), (0, 0, 0)) -pxarray = pygame.PixelArray(text) -pixels = [] -for x in range(text.get_width()): - for y in range(text.get_height()): - pixels.append((XOFF+x, YOFF+y, pxarray[x][y])) -del pxarray -client.set_pixels(pixels) + pygame.init() + font = pygame.font.Font("./fonts/5x7.pcf.gz", 7) + text = font.render(TEXT, True, (255, 255, 255), (0, 0, 0)) + pxarray = pygame.PixelArray(text) + pixels = [] + for x in range(text.get_width()): + for y in range(text.get_height()): + pixels.append((XOFF + x, YOFF + y, pxarray[x][y])) + del pxarray + client.set_pixels(pixels) diff --git a/python/test-proxy.py b/python/test-proxy.py index 93f6d498ef37a9ea5975f2ace79c3c3d18429319..cb5ad4c43e5aa5467e7e621d505454bd5785813a 100755 --- a/python/test-proxy.py +++ b/python/test-proxy.py @@ -1,6 +1,7 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 -import zmq, sys +import zmq +import sys context = zmq.Context() @@ -18,4 +19,3 @@ zmq.device(zmq.QUEUE, frontend, backend) frontend.close() backend.close() context.term() - diff --git a/python/test-server.py b/python/test-server.py index af124c0ad5a2431507b241e62e5894915be81462..bf42e23ee7b20afb327aa541b353c3414c66bad4 100755 --- a/python/test-server.py +++ b/python/test-server.py @@ -1,38 +1,42 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 +import sys +import pygame +import zmq +import struct PWIDTH = 5 -WIDTH = PWIDTH*96 +WIDTH = PWIDTH * 96 PHEIGHT = 7 PPAD = 5 -HEIGHT = (PHEIGHT+PPAD)*9+PHEIGHT +HEIGHT = (PHEIGHT + PPAD) * 9 + PHEIGHT ZOOM = 2 -import pygame, sys pygame.init() -size = (WIDTH*ZOOM, HEIGHT*ZOOM) +size = (WIDTH * ZOOM, HEIGHT * ZOOM) screen = pygame.display.set_mode(size) -import struct -import zmq context = zmq.Context() socket = context.socket(zmq.REP) socket.bind("tcp://*:5570") -def set_pixel(x, y, v): + +def set_pixel(x: int, y: int, v: int) -> None: # 1 bit per pixel - v = v/255.0 - row = y / 7 + v = v // 255 + row = y // 7 if row in [0, 1, 2, 9]: - c = (0xff*v, 0, 0) + c = (0xff * v, 0, 0) elif row in [3, 4, 5]: - c = (0, 0xff*v, 0) + c = (0, 0xff * v, 0) else: - c = (0xff*v, 0xa5*v, 0) - y += y / PHEIGHT * PPAD - screen.fill(c, (x*ZOOM, y*ZOOM, ZOOM, ZOOM)) + c = (0xff * v, 0xa5 * v, 0) + y += y // PHEIGHT * PPAD + screen.fill(c, (x * ZOOM, y * ZOOM, ZOOM, ZOOM)) + +BLIT_HEADER_SIZE = struct.calcsize('<Biiii') while True: for event in pygame.event.get(): if event.type == pygame.QUIT: @@ -44,22 +48,22 @@ while True: continue messages = socket.recv_multipart() - #print("New multimessage") + # print("New multimessage") for message in messages: if not message: break cmd, = struct.unpack_from('<B', message) - #print repr(message) - if cmd == 0: # set pixel + # print(repr(message)) + if cmd == 0: # set pixel cmd, x, y, v = struct.unpack_from('<BiiB', message) - #print("Received set pixel: %r, %r, %r, %r" % (cmd, x, y, v)) + # print("Received set pixel: %r, %r, %r, %r" % (cmd, x, y, v)) set_pixel(x, y, v) - elif cmd == 1: # blit + elif cmd == 1: # blit cmd, x, y, w, h = struct.unpack_from('<Biiii', message) - #print("Received blit: %r, %r, %r, %r, %r" % (cmd, x, y, w, h)) + # print("Received blit: %r, %r, %r, %r, %r" % (cmd, x, y, w, h)) for r in range(h): for c in range(w): - set_pixel(x+c, y+r, ord(message[17+r*w+c])) + set_pixel(x + c, y + r, message[BLIT_HEADER_SIZE + r * w + c]) else: cmd, = struct.unpack_from('<B', message) print("Received unknown: %r" % (cmd,))