tildefriends/packages/cory/emojipush/emojipush.js

202 lines
4.5 KiB
JavaScript

"use strict";
class Client {
async start() {
let self = this;
terminal.setTitle("Emoji Push");
terminal.setSendKeyEvents(true);
self.send({action: "ready"});
core.register("key", function(event) {
if (event.type == "keydown") {
switch (event.keyCode) {
case 37:
self.requestMove(-1, 0);
break;
case 38:
self.requestMove(0, -1);
break;
case 39:
self.requestMove(1, 0);
break;
case 40:
self.requestMove(0, 1);
break;
}
}
});
core.register("onMessage", function(sender, message) {
if (message.action == "display") {
terminal.cork();
terminal.clear();
terminal.print(message.board);
terminal.uncork();
}
});
}
async send(message) {
(await core.getService("server")).postMessage(message);
}
async requestMove(dx, dy) {
await this.send({action: "move", delta: [dx, dy]});
}
}
class Server {
constructor() {
this.rows = 17;
this.columns = 17;
this.players = {};
this.objects = [];
for (let i = 2; i < this.rows - 1; i += 2) {
for (let j = 2; j < this.columns - 1; j += 2) {
let block = new Entity();
block.position = [j, i];
block.symbol = '#';
this.objects.push(block);
}
}
}
async start() {
let self = this;
core.register("onMessage", function(sender, message) {
if (!self.players[sender.index]) {
let player = new Entity();
player.symbol = '@';
player.position = self.findNewPlayerPosition();
self.players[sender.index] = player;
self.objects.push(player);
}
switch (message.action) {
case "move":
self.move(sender.index, message.delta);
self.redisplay();
break;
case "ready":
self.redisplay();
break;
}
});
core.register("onSessionEnd", function(session) {
let player = self.players[session.index];
if (player) {
delete self.players[session.index];
self.objects.splice(self.objects.indexOf(player), 1);
self.redisplay();
}
});
}
occupied(position) {
let board = this.getBoard();
if (position[0] < 0 || position[1] < 0 || position[1] >= board.length || position[0] >= board[position[1]].length) {
return true;
}
if (board[position[1]].charAt(position[0]) != ' ') {
return true;
}
if (this.objects.some(x => position[0] == x.position[0] && position[1] == x.position[1])) {
return true;
}
}
move(index, delta) {
let newPosition = [
this.players[index].position[0] + delta[0],
this.players[index].position[1] + delta[1],
];
if (!this.occupied(newPosition)) {
this.players[index].position = newPosition;
}
}
findNewPlayerPosition() {
let best = null;
let bestDistance = -1;
let players = Object.values(this.players);
for (let i = 0; i < this.rows; i++) {
for (let j = 0; j < this.columns; j++) {
if (!this.occupied([j, i])) {
let distance = Math.min.apply(null, players.map(x => Math.sqrt(
(x.position[0] - j) * (x.position[0] - j)
+ (x.position[1] - i) * (x.position[1] - i))));
if (distance > bestDistance) {
best = [j, i];
bestDistance = distance;
}
}
}
}
return best;
}
redisplay() {
let board;
try {
board = this.getBoardString();
} catch (error) {
board = error;
}
core.broadcast({action: "display", board: board});
}
getBoard() {
let board = [];
for (let i = 0; i < this.rows; i++) {
let row = "";
for (let j = 0; j < this.columns; j++) {
if (i == 0 && j == 0) {
row += '┌';
} else if (i == 0 && j == this.columns - 1) {
row += '┐';
} else if (i == this.rows - 1 && j == 0) {
row += '└';
} else if (i == this.rows - 1 && j == this.columns - 1) {
row += '┘';
} else if (i == 0 || i == this.rows - 1) {
row += '─';
} else if (j == 0 || j == this.columns - 1) {
row += '│';
} else {
row += ' ';
}
}
board.push(row);
}
for (let object of this.objects) {
board[object.position[1]] = board[object.position[1]].slice(0, object.position[0]) + object.symbol + board[object.position[1]].slice(object.position[0] + 1);
}
return board;
}
getBoardString() {
let board = this.getBoard();
let colors = board.map(x => x.split("").map(y => '#fff'));
return board.map((r, row) => r.split("").map((v, column) => ({style: "color: " + colors[row][column], value: v})).concat(["\n"]));
}
}
class Entity {
constructor() {
this.position = [0, 0];
this.symbol = '?';
this.color = '#fff';
}
}
if (imports.terminal) {
new Client().start().catch(terminal.print);
} else {
new Server().start().catch(print);
}