"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); }