Skip to content

Instantly share code, notes, and snippets.

@mtso
Last active March 4, 2022 01:13
Show Gist options
  • Save mtso/e06d2c654685f955e7153639229de93c to your computer and use it in GitHub Desktop.
Save mtso/e06d2c654685f955e7153639229de93c to your computer and use it in GitHub Desktop.
"use strict";
var C;
(function (C) {
C[C["NOWALL"] = 0] = "NOWALL";
C[C["NOP"] = 1] = "NOP";
C[C["WALL"] = 2] = "WALL";
C[C["DOT"] = 3] = "DOT";
C[C["P1"] = 4] = "P1";
C[C["P2"] = 5] = "P2";
})(C || (C = {}));
function coord(note) {
var x = note.toUpperCase()[0].charCodeAt(0) - 65;
var y = +note.toUpperCase().slice(1) - 1;
return [x * 2, y * 2];
}
function note(coord) {
var xAxis = String.fromCharCode(65 + Math.floor(coord[0] / 2));
var yAxis = Math.floor(coord[1] / 2);
return xAxis + yAxis;
}
function getCell(board, coord) {
var _a = getSize(board), width = _a[0], height = _a[1];
var x = coord[0], y = coord[1];
if (x >= width || x < 0 || y >= height || y < 0) {
throw new Error("getCell invalid coord (".concat(x, ", ").concat(y, ")"));
}
return board[y][x];
}
function setCell(board, coord, cell) {
return board.map(function (r, y) {
return r.map(function (c, x) {
if (y === coord[1] && x === coord[0]) {
return cell;
}
else {
return c;
}
});
});
}
/** @return [from, wall, to] */
function getSpan(fromS, toS) {
var from = coord(fromS);
var to = coord(toS);
if (from[0] === to[0] && Math.abs(from[1] - to[1]) === 2) {
if (from[1] - to[1] > 0) {
return [from, [from[0], to[1] + 1], to];
}
else {
return [from, [from[0], from[1] + 1], to];
}
}
else if (from[1] === to[1] && Math.abs(from[0] - to[0]) === 2) {
if (from[0] - to[0] > 0) {
return [from, [to[0] + 1, from[1]], to];
}
else {
return [from, [from[0] + 1, from[1]], to];
}
}
else {
throw new Error("Invalid move ".concat(fromS, "-").concat(toS));
}
}
function getSize(board) {
if (board.length < 1) {
return [0, 0];
}
else {
return [board[0].length, board.length];
}
}
function getRoomsSurroundingWall(board, wall) {
var _a = getSize(board), width = _a[0], height = _a[1];
var rooms = [];
if (wall[1] % 2 === 0) {
if (wall[1] + 1 < height) {
rooms.push([wall[0], wall[1] + 1]);
}
if (wall[1] - 1 >= 0) {
rooms.push([wall[0], wall[1] - 1]);
}
}
else if (wall[1] % 2 === 1) {
if (wall[0] + 1 < width) {
rooms.push([wall[0] + 1, wall[1]]);
}
if (wall[0] - 1 >= 0) {
rooms.push([wall[0] - 1, wall[1]]);
}
}
return rooms;
}
function getWallsSurroundingRoom(board, room) {
var _a = getSize(board), width = _a[0], height = _a[1];
var walls = [];
if (room[1] + 1 < height) {
walls.push([room[0], room[1] + 1]);
}
if (room[1] - 1 >= 0) {
walls.push([room[0], room[1] - 1]);
}
if (room[0] + 1 < width) {
walls.push([room[0] + 1, room[1]]);
}
if (room[0] - 1 >= 0) {
walls.push([room[0] - 1, room[1]]);
}
return walls;
}
function isEnclosed(board, room) {
var walls = getWallsSurroundingRoom(board, room);
return walls.every(function (wall) { return getCell(board, wall) === C.WALL; });
}
function getRoomSize(board) {
var _a = getSize(board), width = _a[0], height = _a[1];
return Math.floor(width / 2) * Math.floor(height / 2);
}
function flatMap(l) {
return l.reduce(function (a, n) { return a.concat(n); }, []);
}
function isOutOfBounds(board, coord) {
var _a = getSize(board), width = _a[0], height = _a[1];
var x = coord[0], y = coord[1];
return x >= width || x < 0 || y >= height || y < 0;
}
function getInitialState(isP1Start) {
return {
isP1: isP1Start !== false,
p1Score: 0,
p2Score: 0,
isOver: false
};
}
function stepGame(board, state, answer) {
// 1. Check input.
if (state.isOver) {
throw new Error("Game is over!");
}
var _a = answer.toUpperCase().split(/\-|\s/), fromS = _a[0], toS = _a[1], _ = _a.slice(2);
var _b = getSpan(fromS, toS), from = _b[0], wall = _b[1], to = _b[2];
if (isOutOfBounds(board, from) || isOutOfBounds(board, to)) {
throw new Error("Input \"".concat(answer, "\" is out of bounds!"));
}
if (getCell(board, wall) !== C.NOWALL) {
throw new Error("A wall is already there! Please choose another.");
}
// 2. Place wall.
var boardP = setCell(board, wall, C.WALL);
var rooms = getRoomsSurroundingWall(boardP, wall);
// 3. Mark enclosed rooms from the latest wall placement.
var roomsEnclosed = rooms.filter(function (room) { return isEnclosed(boardP, room) && getCell(boardP, room) === C.NOP; });
var score = roomsEnclosed.length;
var boardPP = roomsEnclosed.reduce(function (board, room) { return setCell(board, room, state.isP1 ? C.P1 : C.P2); }, boardP);
// 4. Calculate new scores.
var p1Score = state.p1Score + (state.isP1 ? score : 0);
var p2Score = state.p2Score + (state.isP1 ? 0 : score);
var newState = {
isP1: score > 0 ? state.isP1 : !state.isP1,
p1Score: p1Score,
p2Score: p2Score,
isOver: p1Score + p2Score >= getRoomSize(board),
roomSize: getRoomSize(board)
};
return [boardPP, newState];
}
function generateBoard(w, h) {
var board = [];
for (var r = 0; r < h - 1; r++) {
var cornerRow_1 = flatMap(Array(w - 1).fill([C.DOT, C.NOWALL])).concat([
C.DOT,
]);
var noCornerRow = flatMap(Array(w - 1).fill([C.NOWALL, C.NOP])).concat([
C.NOWALL,
]);
board.push(cornerRow_1);
board.push(noCornerRow);
}
var cornerRow = flatMap(Array(w - 1).fill([C.DOT, C.NOWALL])).concat([
C.DOT,
]);
board.push(cornerRow);
return board;
}
var cellToChar = function (c, y) {
switch (c) {
case C.NOWALL:
return " ";
case C.NOP:
return " ";
case C.WALL:
return y % 2 === 0 ? "-" : "|";
case C.DOT:
return "•";
case C.P1:
return "1";
case C.P2:
return "2";
default:
return " ";
}
};
function formatBoard(board) {
var rows = board.map(function (r, y) { return r.map(function (c) { return cellToChar(c, y); }).join(""); });
// Add axes for algebraic notation.
var _a = getSize(board), width = _a[0], _ = _a[1];
var xAxis = " " +
Array(Math.ceil(width / 2))
.fill(0)
.map(function (_, i) { return String.fromCharCode(i + 65); })
.join(" ");
var formatYAxis = function (y) {
var yN = Math.floor(y / 2) + 1;
return y % 2 === 0 ? "".concat(yN) : " ";
};
return [xAxis].concat(rows.map(function (row, y) { return formatYAxis(y) + row; })).join("\n");
}
console.log(formatBoard(generateBoard(3, 3)));
"use strict";
var C;
(function (C) {
C[C["NOWALL"] = 0] = "NOWALL";
C[C["NOP"] = 1] = "NOP";
C[C["WALL"] = 2] = "WALL";
C[C["DOT"] = 3] = "DOT";
C[C["P1"] = 4] = "P1";
C[C["P2"] = 5] = "P2";
})(C || (C = {}));
function coord(note) {
var x = note.toUpperCase()[0].charCodeAt(0) - 65;
var y = +note.toUpperCase().slice(1) - 1;
return [x * 2, y * 2];
}
function note(coord) {
var xAxis = String.fromCharCode(65 + Math.floor(coord[0] / 2));
var yAxis = Math.floor(coord[1] / 2);
return xAxis + yAxis;
}
function getCell(board, coord) {
var _a = getSize(board), width = _a[0], height = _a[1];
var x = coord[0], y = coord[1];
if (x >= width || x < 0 || y >= height || y < 0) {
throw new Error("getCell invalid coord (".concat(x, ", ").concat(y, ")"));
}
return board[y][x];
}
function setCell(board, coord, cell) {
return board.map(function (r, y) {
return r.map(function (c, x) {
if (y === coord[1] && x === coord[0]) {
return cell;
}
else {
return c;
}
});
});
}
/** @return [from, wall, to] */
function getSpan(fromS, toS) {
var from = coord(fromS);
var to = coord(toS);
if (from[0] === to[0] && Math.abs(from[1] - to[1]) === 2) {
if (from[1] - to[1] > 0) {
return [from, [from[0], to[1] + 1], to];
}
else {
return [from, [from[0], from[1] + 1], to];
}
}
else if (from[1] === to[1] && Math.abs(from[0] - to[0]) === 2) {
if (from[0] - to[0] > 0) {
return [from, [to[0] + 1, from[1]], to];
}
else {
return [from, [from[0] + 1, from[1]], to];
}
}
else {
throw new Error("Invalid move ".concat(fromS, "-").concat(toS));
}
}
function getSize(board) {
if (board.length < 1) {
return [0, 0];
}
else {
return [board[0].length, board.length];
}
}
function getRoomsSurroundingWall(board, wall) {
var _a = getSize(board), width = _a[0], height = _a[1];
var rooms = [];
if (wall[1] % 2 === 0) {
if (wall[1] + 1 < height) {
rooms.push([wall[0], wall[1] + 1]);
}
if (wall[1] - 1 >= 0) {
rooms.push([wall[0], wall[1] - 1]);
}
}
else if (wall[1] % 2 === 1) {
if (wall[0] + 1 < width) {
rooms.push([wall[0] + 1, wall[1]]);
}
if (wall[0] - 1 >= 0) {
rooms.push([wall[0] - 1, wall[1]]);
}
}
return rooms;
}
function getWallsSurroundingRoom(board, room) {
var _a = getSize(board), width = _a[0], height = _a[1];
var walls = [];
if (room[1] + 1 < height) {
walls.push([room[0], room[1] + 1]);
}
if (room[1] - 1 >= 0) {
walls.push([room[0], room[1] - 1]);
}
if (room[0] + 1 < width) {
walls.push([room[0] + 1, room[1]]);
}
if (room[0] - 1 >= 0) {
walls.push([room[0] - 1, room[1]]);
}
return walls;
}
function isEnclosed(board, room) {
var walls = getWallsSurroundingRoom(board, room);
return walls.every(function (wall) { return getCell(board, wall) === C.WALL; });
}
function getRoomSize(board) {
var _a = getSize(board), width = _a[0], height = _a[1];
return Math.floor(width / 2) * Math.floor(height / 2);
}
function flatMap(l) {
return l.reduce(function (a, n) { return a.concat(n); }, []);
}
function isOutOfBounds(board, coord) {
var _a = getSize(board), width = _a[0], height = _a[1];
var x = coord[0], y = coord[1];
return x >= width || x < 0 || y >= height || y < 0;
}
function getInitialState(isP1Start) {
return {
isP1: isP1Start !== false,
p1Score: 0,
p2Score: 0,
isOver: false
};
}
function stepGame(board, state, answer) {
// 1. Check input.
if (state.isOver) {
throw new Error("Game is over!");
}
var _a = answer.toUpperCase().split(/\-|\s/), fromS = _a[0], toS = _a[1], _ = _a.slice(2);
var _b = getSpan(fromS, toS), from = _b[0], wall = _b[1], to = _b[2];
if (isOutOfBounds(board, from) || isOutOfBounds(board, to)) {
throw new Error("Input \"".concat(answer, "\" is out of bounds!"));
}
if (getCell(board, wall) !== C.NOWALL) {
throw new Error("A wall is already there! Please choose another.");
}
// 2. Place wall.
var boardP = setCell(board, wall, C.WALL);
var rooms = getRoomsSurroundingWall(boardP, wall);
// 3. Mark enclosed rooms from the latest wall placement.
var roomsEnclosed = rooms.filter(function (room) { return isEnclosed(boardP, room) && getCell(boardP, room) === C.NOP; });
var score = roomsEnclosed.length;
var boardPP = roomsEnclosed.reduce(function (board, room) { return setCell(board, room, state.isP1 ? C.P1 : C.P2); }, boardP);
// 4. Calculate new scores.
var p1Score = state.p1Score + (state.isP1 ? score : 0);
var p2Score = state.p2Score + (state.isP1 ? 0 : score);
var newState = {
isP1: score > 0 ? state.isP1 : !state.isP1,
p1Score: p1Score,
p2Score: p2Score,
isOver: p1Score + p2Score >= getRoomSize(board),
roomSize: getRoomSize(board)
};
return [boardPP, newState];
}
function generateBoard(w, h) {
var board = [];
for (var r = 0; r < h - 1; r++) {
var cornerRow_1 = flatMap(Array(w - 1).fill([C.DOT, C.NOWALL])).concat([
C.DOT,
]);
var noCornerRow = flatMap(Array(w - 1).fill([C.NOWALL, C.NOP])).concat([
C.NOWALL,
]);
board.push(cornerRow_1);
board.push(noCornerRow);
}
var cornerRow = flatMap(Array(w - 1).fill([C.DOT, C.NOWALL])).concat([
C.DOT,
]);
board.push(cornerRow);
return board;
}
var cellToChar = function (c, y) {
switch (c) {
case C.NOWALL:
return " ";
case C.NOP:
return " ";
case C.WALL:
return y % 2 === 0 ? "-" : "|";
case C.DOT:
return "•";
case C.P1:
return "1";
case C.P2:
return "2";
default:
return " ";
}
};
function formatBoard(board) {
var rows = board.map(function (r, y) { return r.map(function (c) { return cellToChar(c, y); }).join(""); });
// Add axes for algebraic notation.
var _a = getSize(board), width = _a[0], _ = _a[1];
var xAxis = " " +
Array(Math.ceil(width / 2))
.fill(0)
.map(function (_, i) { return String.fromCharCode(i + 65); })
.join(" ");
var formatYAxis = function (y) {
var yN = Math.floor(y / 2) + 1;
return y % 2 === 0 ? "".concat(yN) : " ";
};
return [xAxis].concat(rows.map(function (row, y) { return formatYAxis(y) + row; })).join("\n");
}
const newInputHandler = () => {
const width = Math.min(Math.max(+(process.env["W"] || 5), 0), 26);
const height = Math.min(Math.max(+(process.env["H"] || 5), 0), 26);
let board = generateBoard(width, height);
let state = getInitialState();
let error = null;
return (input) => {
if (input) {
try {
const [newBoard, newState] = stepGame(board, state, input.trim());
board = newBoard;
state = newState;
error = null;
} catch (err) {
error = err.message;
}
}
if (state.isOver) {
let result = "";
if (state.p1Score === state.p2Score) {
result = "Tie!";
} else if (state.p1Score > state.p2Score) {
result = "Player 1 won!";
} else if (state.p2Score > state.p1Score) {
result = "Player 2 won!";
}
const finalResult = formatBoard(board) + `\n${result}`;
console.clear();
console.log(finalResult);
} else {
const view = formatBoard(board);
const info = !!error ? "!! " + error : "";
const prompt = `${state.isP1 ? "P1" : "P2"} > `;
console.clear();
process.stdout.write([view, info, prompt].join("\n"))
}
}
}
const inputHandler = newInputHandler();
inputHandler("");
process.stdin.on("data", (data) => inputHandler(data.toString().trim()))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment