1 const express = require("express");
2 const cors = require("cors");
3 const body_parser = require("body-parser");
8 /* Load each of our game mini-apps. */
9 var empires = require("./empires");
17 return [null,null,null,null].map(() => LMNO.letters.charAt(Math.floor(Math.random() * LMNO.letters.length))).join('');
22 var id = this.generate_id();
23 } while (id in this.ids);
25 const game = new empires.Game();
37 /* Some letters we don't use in our IDs:
39 * 1. Vowels (AEIOU) to avoid accidentally spelling an unfortunate word
40 * 2. Lowercase letters (replace with corresponding capital on input)
41 * 3. N (replace with M on input)
42 * 4. P (replace with B on input)
43 * 5. S (replace with F on input)
45 LMNO.letters = "BCDFGHJKLMQRTVWXYZ";
47 const lmno = new LMNO();
49 /* Force a game ID into a canonical form as described above. */
50 function lmno_canonize(id) {
52 id = id.toUpperCase();
54 /* Replace unused letters with nearest phonetic match. */
55 id = id.replace(/N/g, 'M');
56 id = id.replace(/P/g, 'B');
57 id = id.replace(/S/g, 'F');
59 /* Replace unused numbers nearest visual match. */
60 id = id.replace(/0/g, 'O');
61 id = id.replace(/1/g, 'I');
62 id = id.replace(/5/g, 'S');
67 app.post('/new/:game_engine', (request, response) => {
68 const game_engine = request.params.game_engine;
69 const game_id = lmno.create_game(game_engine);
70 response.send(JSON.stringify(game_id));
73 /* Redirect any requests to a game ID at the top-level.
75 * Specifically, after obtaining the game ID (from the path) we simply
76 * lookup the game engine for the corresponding game and then redirect
77 * to the engine- and game-specific path.
79 app.get('/[a-zA-Z0-9]{4}', (request, response) => {
80 const game_id = request.path.replace(/\//g, "");
81 const canon_id = lmno_canonize(game_id);
83 /* Redirect user to page with the canonical ID in it. */
84 if (game_id !== canon_id) {
85 response.redirect(301, `/${canon_id}/`);
89 const game = lmno.ids[game_id];
90 if (game === undefined) {
91 response.sendStatus(404);
94 response.redirect(301, `/${game.engine}/${game.id}/`);
97 /* LMNO middleware to lookup the game. */
98 app.use('/empires/:game_id([a-zA-Z0-9]{4})', (request, response, next) => {
99 const game_id = request.params.game_id;
100 const canon_id = lmno_canonize(game_id);
102 /* Redirect user to page with the canonical ID in it. */
103 if (game_id !== canon_id) {
104 const new_url = request.originalUrl.replace("/empires/" + game_id,
105 "/empires/" + canon_id);
106 response.redirect(301, new_url);
110 request.game = lmno.ids[game_id].game;
111 if (request.game === undefined) {
112 response.sendStatus(404);
118 /* Mount sub apps. only _after_ we have done all the middleware we need. */
119 app.use('/empires/[a-zA-Z0-9]{4}/', empires.app);
121 app.listen(4000, function () {
122 console.log('LMNO server listening on localhost:4000');