tildefriends/packages/cory/xmas2016/xmas2016.js

177 lines
4.1 KiB
JavaScript

"use strict";
const kWidth = 15;
const kHeight = 10;
class Client {
async start() {
let self = this;
terminal.setTitle("Xmas 2016");
terminal.setSendKeyEvents(true);
terminal.split([{name: "terminal", style: "text-align: center"}]);
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) {
this.send({action: "move", delta: [dx, dy]});
}
}
class Server {
constructor() {
this.players = {};
}
async start() {
let self = this;
core.register("onMessage", function(sender, message) {
if (!self.players[sender.index]) {
self.players[sender.index] = [Math.floor(Math.random() * 8) + 1, 8];
}
switch (message.action) {
case "move":
self.move(sender.index, message.delta);
self.redisplay();
break;
case "ready":
self.redisplay();
break;
}
});
core.register("onSessionEnd", function(session) {
delete self.players[session.index];
self.redisplay();
});
}
occupied(position) {
if (position[0] < 1 || position[1] < 1 || position[0] >= kWidth - 1 || position[1] >= kHeight - 1) {
return true;
}
if (Object.values(this.players).some(x => position[0] == x[0] && position[1] == x[1])) {
return true;
}
}
move(index, delta) {
let newPosition = [
this.players[index][0] + delta[0],
this.players[index][1] + delta[1],
];
let pushPosition = [
this.players[index][0] + 2 * delta[0],
this.players[index][1] + 2 * delta[1],
];
if (!this.occupied(newPosition)) {
this.players[index] = newPosition;
} else if (this.occupied(newPosition) && !this.occupied(pushPosition)) {
for (var i in this.players) {
if (this.players[i][0] == newPosition[0] && this.players[i][1] == newPosition[1]) {
this.players[i] = pushPosition;
}
}
this.players[index] = newPosition;
}
}
redisplay() {
core.broadcast({action: "display", board: this.getBoard()});
}
getBoard() {
let board = [
"┌─────────────┐",
"│ . │",
"│ .#. │",
"│ .%##. │",
"│ .##%##. │",
"│ .%###%##. │",
"│ .##%###%##. │",
"│.#%##%###%##.│",
"│ | │",
"└─────────────┘",
];
let merry = false;
let colors = board.map(x => x.split("").map(y => '#fff'));
for (let i in this.players) {
let player = this.players[i];
merry = merry || (player[0] == 7 && player[1] == 1);
let character = player[0] == 7 && player[1] == 1 ? '*' : '@';
board[player[1]] = board[player[1]].slice(0, player[0]) + character + board[player[1]].slice(player[0] + 1);
}
if (merry) {
for (let i = 0; i < colors.length; i++) {
for (let j = 0; j < colors[i].length; j++) {
switch (board[i].charAt(j)) {
case '#':
case '.':
colors[i][j] = '#080';
break;
case '%':
colors[i][j] = '#f00';
break;
case '|':
colors[i][j] = '#880';
break;
case '*':
colors[i][j] = '#ff0';
break;
case '@':
{
const palette = ['#f88', '#8f8', '#88f', '#fff'];
colors[i][j] = palette[(i * colors.length + j) % palette.length];
}
break;
}
}
}
}
let result = board.map((r, row) => r.split("").map((v, column) => ({style: "color: " + colors[row][column], value: v})).concat(["\n"]));
if (merry) {
result.push("Merry Christmas!");
} else {
result.push("use ←↑→↓");
}
return result;
}
}
if (imports.terminal) {
new Client().start().catch(terminal.print);
} else {
new Server().start().catch(print);
}