Created
September 23, 2017 16:50
-
-
Save diestrin/a62cc405243ba2d153511500fcecd34c to your computer and use it in GitHub Desktop.
This file contains hidden or 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
| const cube = | |
| `+---+ | |
| / /| | |
| +---+ | | |
| | | + | |
| | |/ | |
| +---+`.split('\n'); | |
| /** | |
| * @typedef {{x: number, y: number, z: number}} Coords | |
| */ | |
| /** | |
| * Utility to build ranges | |
| * | |
| * @param {number} from | |
| * @param {number} to | |
| * @return {number[]} | |
| */ | |
| function getRange(from, to) { | |
| return '.' | |
| .repeat(Math.abs(from - to) + 1) | |
| .split('') | |
| .map((dot, index) => from + index); | |
| } | |
| /** | |
| * Converts the input array to a 3D space coords | |
| * | |
| * @param {number[][]} input | |
| * @return {Coords} | |
| */ | |
| function getCoords(input) { | |
| const x = input[0].length; | |
| const y = input.length; | |
| const z = input.reduce((highest, row) => { | |
| const tower = row.reduce((_highest, tower) => | |
| _highest > tower ? _highest : tower | |
| , 0); | |
| return highest > tower ? highest : tower | |
| }, 0); | |
| return {x, y, z}; | |
| } | |
| /** | |
| * Generates the canvas with the correct width and height | |
| * | |
| * @param {number[][]} input | |
| * @param {Coords} coords | |
| * @return {string[]} | |
| */ | |
| function getLayout(input, coords) { | |
| const height = input | |
| .map(row => | |
| row.reduce((rowHighest, tower) => | |
| rowHighest > tower ? rowHighest : tower, 0)) | |
| .reverse() | |
| .map((highest, index) => (highest * 3 + 1) + (index * 2) + 2) | |
| .reduce((result, rowHighest) => result > rowHighest ? result : rowHighest); | |
| const width = input | |
| .map(row => row.filter(n => n).length) | |
| .reverse() | |
| .map((widest, index) => (widest * 4 + 1) + (index * 2) + 2) | |
| .reduce((result, widest) => result > widest ? result : widest); | |
| return ('.'.repeat(width) + '\n').repeat(height).split('\n'); | |
| } | |
| /** | |
| * Converts a 3D space point into a 2D space point on the X axys | |
| * | |
| * @param {Coords} coords | |
| * @return {number} | |
| */ | |
| function getX({x, y}) { | |
| const yPoints = (y - 1) * 2; | |
| const xPoints = (x - 1) * 4; | |
| return xPoints + yPoints; | |
| } | |
| /** | |
| * Converts a 3D space point into a 2D space point on the Y axys | |
| * | |
| * @param {Coords} coords | |
| * @return {number} | |
| */ | |
| function getY({y, z}, layout) { | |
| const height = layout.length - 1; | |
| const zPoints = (z - 1) * 3 + 6; | |
| const yPoints = (y - 1) * 2; | |
| const yBase = yPoints + zPoints; | |
| return height - yBase; | |
| } | |
| /** | |
| * Draw a single cube given the x,y,z coords | |
| * | |
| * @param {Coords} coords | |
| * @param {string[]} layout | |
| */ | |
| function drawCube(coords, layout) { | |
| const x = getX(coords); | |
| const y = getY(coords, layout); | |
| getRange(0, 5).forEach(i => { | |
| const start = i < 2 ? 2 - i : 0; | |
| const end = i >= 4 ? 10 - i : 7; | |
| const line = layout[y + i]; | |
| layout[y + i] = line.slice(0, x + start) + cube[i] + line.slice(x + end); | |
| }); | |
| } | |
| /** | |
| * Draw a specific row in a spacific floor | |
| * | |
| * @param {boolean[]} row | |
| * @param {number} rowNum | |
| * @param {number} floorNum | |
| * @param {string[]} layout | |
| */ | |
| function drawRow(row, rowNum, floorNum, layout) { | |
| row.forEach((shouldRender, index) => { | |
| if (shouldRender) { | |
| drawCube({x: index + 1, y: rowNum, z: floorNum}, layout); | |
| } | |
| }); | |
| } | |
| /** | |
| * Draw a specific floor | |
| * | |
| * @param {boolean[][]} floor | |
| * @param {number} floorNum | |
| * @param {number} layout | |
| */ | |
| function drawFloor(floor, floorNum, layout) { | |
| floor.forEach((row, index, arr) => { | |
| drawRow(row, arr.length - index, floorNum, layout); | |
| }); | |
| } | |
| /** | |
| * Draw the whole table with all the cubes | |
| * | |
| * @param {number[][]} _input | |
| */ | |
| function cubes(input) { | |
| const _input = [...input]; | |
| const coords = getCoords(_input); | |
| const layout = getLayout(_input, coords); | |
| getRange(1, coords.z) | |
| .map(z => ({ | |
| floorNum: z, | |
| floor: _input.reduce((result, row) => [ | |
| ...result, row.map(cell => cell >= z) | |
| ], []), | |
| })) | |
| .forEach(result => drawFloor(result.floor, result.floorNum, layout)); | |
| return layout; | |
| } | |
| /** | |
| * Print the result | |
| * | |
| * @param {string[]} layout | |
| */ | |
| function print(layout) { | |
| console.log('\n' + layout.join('\n')); | |
| } | |
| print(cubes([ | |
| [2, 2, 1, 2, 2], | |
| [2, 2, 1, 1, 2], | |
| [3, 2, 1, 2, 2] | |
| ])); | |
| print(cubes([ | |
| [3, 3, 3, 3, 3], | |
| [2, 2, 2, 2, 2], | |
| [1, 1, 1, 1, 1] | |
| ])); | |
| print(cubes([ | |
| [1, 1, 1, 1, 1], | |
| [2, 2, 2, 2, 2], | |
| [3, 3, 3, 3, 3] | |
| ])); | |
| print(cubes([ | |
| [1, 1, 1, 1, 1], | |
| [2, 2, 2, 2, 2], | |
| [1, 1, 1, 1, 1] | |
| ])); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment