This commit is contained in:
sample-text-here 2021-06-25 17:48:30 -06:00
parent e8e9bfd6ec
commit 5d8a047949
4 changed files with 155 additions and 7 deletions

View file

@ -1,12 +1,12 @@
# hundred
a coding challenge i made for myself; how much
can i fit in one hundred lines or less?
a coding challenge i made for myself; how much can i fit in one hundred
lines or less?
i'll try to keep these understandable and not
mangle/minify them. if you want to use them,
you probrably should edit them to your liking
first.
i'll try to keep these understandable and not mangle/minify them. if
you want to use them, you probrably should edit them to your liking
first. **note: many of these are buggy. please double check before
using them**
- `server.js` basic http server based off of express
- `templater.js` pre-render your webpages server side
@ -19,3 +19,5 @@ first.
- `tictactoe.js` (deno) two player tic-tac-toe game
- `xml.js` xml/html parser
- `p2p.js` sample p2p protocol implementation
- `canvas.js` a terminal canvas emulator with many, many known bugs
- `input.js` simple terminal raw input

99
canvas.js Normal file
View file

@ -0,0 +1,99 @@
const block = "\u2580"
const nl = s => s.str.replace(/\n/g, `\n\x1b[${s.x + 1}G`)
const fmt = s => `\x1b[${Math.floor(s.y / 2) + 1};${s.x + 1}H${nl(s)}`;
class Color {
static black = 0;
static red = 1;
static green = 2;
static yellow = 3;
static blue = 4;
static purple = 5;
static cyan = 6;
static white = 7;
}
class Canvas {
constructor(w, h) {
if(h) this.rw = w, this.rh = h;
this.strs = [];
this.buffer = [];
for(let i = 0; i < this.height; i++) this.buffer.push([]);
this.clear();
this.color = Color.black;
}
flush(clear = true) {
let curtop = -1, curbot = -1;
let runtop = true, runbot = true;
let str = "\x1b[0;0H";
for(let i = 0; i < this.height; i += 2) {
for(let j = 0; j < this.width; j++) {
const top = this.buffer[i][j], bottom = this.buffer[i + 1][j];
const resumed = !(runtop || runbot);
runtop = top !== -1, runbot = bottom !== -1;
if(!(runtop || runbot)) continue;
if(resumed) str += `\x1b[${i / 2 + 1};${j + 1}H`;
if(top !== curtop) {
str += `\x1b[3${top === -1 ? 0 : top}m`;
curtop = top;
}
if(bottom !== curbot) {
str += `\x1b[4${bottom === -1 ? 0 : bottom}m`;
curbot = bottom;
}
str += block;
}
}
if(curtop !== -1 || curbot !== -1) str += "\x1b[0m";
for(let i of this.strs) str += fmt(i);
process.stdout.write(str);
if(clear) this.clear();
}
clear() {
for(let i = 0; i < this.height; i++) {
for(let j = 0; j < this.width; j++) {
this.buffer[i][j] = -1;
}
}
while(this.strs.length) this.strs.pop();
}
pixel(x, y) {
this.buffer[y][x] = this.color;
}
rect(x, y, w, h) {
for(let i = y; i < y + h; i++) {
for(let j = x; j < x + w; j++) {
this.buffer[i][j] = this.color;
}
}
}
text(str, x, y) {
this.strs.push({ str, x, y });
}
canvas(c, x, y, flush = true) {
for(let i = 0; i < c.height; i++) {
for(let j = 0; j < c.width; j++) {
if(c.buffer[i][j] !== -1) this.buffer[i + y][j + x] = c.buffer[i][j];
}
}
for(let i of c.strs) this.strs.push({ str: i.str, x: i.x + x, y: i.y + y });
if(flush) c.clear();
}
get width() {
return this.rw ? this.rw : process.stdout.columns;
}
get height() {
return this.rh ? this.rh : process.stdout.rows * 2;
}
static color = Color;
}
module.exports = Canvas;

47
input.js Normal file
View file

@ -0,0 +1,47 @@
const EventEmitter = require("events");
const Keys = {
up: Buffer.from([0x1B, 0x5B, 0x41]),
down: Buffer.from([0x1B, 0x5B, 0x42]),
right: Buffer.from([0x1B, 0x5B, 0x43]),
left: Buffer.from([0x1B, 0x5B, 0x44]),
left: Buffer.from([0x1B, 0x5B, 0x44]),
tab: Buffer.from([0x07]),
enter: Buffer.from([0x0A]),
space: Buffer.from([0x20]),
};
function isPrint(char) {
if(char >= 'a' && char <= 'z') return true;
if(char >= 'A' && char <= 'Z') return true;
if(char >= '0' && char <= '9') return true;
if(char >= '[' && char <= '_') return true;
if(char >= '{' && char <= '~') return true;
return false;
}
class Input extends EventEmitter {
constructor(stream) {
super();
stream.on("data", this.handle.bind(this));
this.stream = stream;
}
handle(data) {
for(let i in Keys) {
if(data.equals(Keys[i])) this.emit(i);
}
const key = data.toString();
if(isPrint(key)) this.emit(key);
this.emit("data", data);
}
hijack() {
this.stream.setRawMode(true);
}
close() {
this.stream?.setRawMode(false);
}
}
module.exports = Input;

View file

@ -34,6 +34,7 @@ function parse(route, url) {
url = url.slice(i.length);
} else return null;
}
if(url.length) return null;
return data;
}
@ -91,7 +92,6 @@ class Server extends http.Server {
js: "text/javascript",
json: "application/json",
png: "image/png",
jpg: "image/jpeg",
jpeg: "image/jpeg",
};
}