Last active
March 4, 2022 01:13
-
-
Save mtso/e06d2c654685f955e7153639229de93c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"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))); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"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