123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220 |
- import { Inspect } from "../common.ts";
- /* Directions */
- const Directions = {
- NORTH: {
- X: 0,
- Y: -1,
- },
- SOUTH: {
- X: 0,
- Y: 1,
- },
- EAST: {
- X: 1,
- Y: 0,
- },
- WEST: {
- X: -1,
- Y: 0,
- },
- NORTH_EAST: {
- X: 1,
- Y: -1,
- },
- NORTH_WEST: {
- X: -1,
- Y: -1,
- },
- SOUTH_EAST: {
- X: 1,
- Y: 1,
- },
- SOUTH_WEST: {
- X: -1,
- Y: 1,
- },
- }
- /**
- * Parse the schematics to find all possible Engine Parts
- * @param {string[][]} schematicsMap A 2D grid of characters making up a schematic
- * @returns {EnginePart[]} An array of potential Engine Parts
- */
- export function ParseSchematics(schematicsMap: string[][]): EnginePart[] {
- const engineParts: EnginePart[] = [];
- /** The current pointer within the schematics' 2D array */
- const schematicsPointer: Vector2 = {
- X: 0,
- Y: 0,
- };
- for(; schematicsPointer.Y < schematicsMap.length; schematicsPointer.Y++) {
- // Reset the X pointer each line
- schematicsPointer.X = 0;
- /** A line from the total schematics */
- const schematicsLine = schematicsMap[schematicsPointer.Y];
- // Create a reusable EnginePart store
- let part: EnginePart|null = null;
- for(; schematicsPointer.X < schematicsMap[schematicsPointer.Y].length; schematicsPointer.X++) {
- const char = schematicsMap[schematicsPointer.Y][schematicsPointer.X];
- // Check if the current character is a number
- if (/\d/.test(char)) {
- // Check if our EnginePart store is initialized
- if (part == null) { part = { PartNumber: 0, Coordinates: [] }; }
- if (part.PartNumber) {
- // Concatenate the number to the existing part of the Part Number
- part.PartNumber = Number("" + part.PartNumber + char);
- }
- else {
- // Start the new Part Number
- part.PartNumber = Number(char);
- }
- // Push the coordinates
- part.Coordinates.push({
- X: schematicsPointer.X,
- Y: schematicsPointer.Y,
- });
- }
- // If it's not
- else {
- // Check if the EnginePart store has a value
- if(part != null) {
- // If it does, store it and empty it
- engineParts.push(part);
- part = null;
- }
- }
- }
- if(part !== null) {
- engineParts.push(part);
- }
- }
- return engineParts;
- }
- /**
- * Validates all previously parsed Engine Parts
- *
- * An Engine Part is only valid if it's connected, even diagonally, to a
- * symbol other than `.`.
- *
- * @param {EnginePart[]} potentialParts All potential Engine Parts
- * @param {string[][]} schematicsMap A 2D grid of characters making up a schematic
- * @returns {EnginePart[]} A filtered list of all valid Engine Parts
- */
- export function ValidateEngineParts(potentialParts: EnginePart[], schematicsMap: string[][]): EnginePart[] {
- const validParts: EnginePart[] = [];
- for (const part of potentialParts) {
- let symbolFound = false;
- for (const point of part.Coordinates) {
- if (BordersASymbol(point, schematicsMap)) {
- symbolFound = true;
- validParts.push(part);
- break;
- }
- }
- }
- return validParts;
- }
- /**
- * Check if a point on the schematics map borders a symbol
- *
- * A symbol is any character other than a digit or a period.
- *
- * @param point A point on the schematics map
- * @param schematicsMap A 2D grid of characters making up a schematic
- * @returns {boolean} Whether the point borders a symbol or not
- */
- export function BordersASymbol(point: Vector2, schematicsMap: string[][]): boolean {
- // Initialize all border chars as NOPs
- let northernBorder = ".";
- let easternBorder = ".";
- let southernBorder = ".";
- let westernBorder = ".";
- let northEastBorder = ".";
- let northWestBorder = ".";
- let southEastBorder = ".";
- let southWestBorder = ".";
- // Check what borders exist
- const northExists = !!schematicsMap[point.Y + Directions.NORTH.Y];
- const southExists = !!schematicsMap[point.Y + Directions.SOUTH.Y];
- const eastExists = !!schematicsMap[point.Y][point.X + Directions.EAST.X];
- const westExists = !!schematicsMap[point.Y][point.X + Directions.WEST.X];
- // Find the border chars
- if(northExists) {
- northernBorder = schematicsMap[point.Y + Directions.NORTH.Y][point.X + Directions.NORTH.X];
- if(eastExists) {
- northEastBorder = schematicsMap[point.Y + Directions.NORTH_EAST.Y][point.X + Directions.NORTH_EAST.X];
- }
- if(westExists) {
- northWestBorder = schematicsMap[point.Y + Directions.NORTH_WEST.Y][point.X + Directions.NORTH_WEST.X];
- }
- }
- if(southExists) {
- southernBorder = schematicsMap[point.Y + Directions.SOUTH.Y][point.X + Directions.SOUTH.X];
- if(eastExists) {
- southEastBorder = schematicsMap[point.Y + Directions.SOUTH_EAST.Y][point.X + Directions.SOUTH_EAST.X];
- }
- if(westExists) {
- southWestBorder = schematicsMap[point.Y + Directions.SOUTH_WEST.Y][point.X + Directions.SOUTH_WEST.X];
- }
- }
- if (eastExists) {
- easternBorder = schematicsMap[point.Y + Directions.EAST.Y][point.X + Directions.EAST.X];
- }
- if (westExists) {
- westernBorder = schematicsMap[point.Y + Directions.WEST.Y][point.X + Directions.WEST.X];
- }
- // Combine all bordering characters into one long string
- const allBorders = northernBorder + easternBorder + southernBorder + westernBorder + northEastBorder + northWestBorder + southEastBorder + southWestBorder;
- return /[^0-9\.]/.test(allBorders);
- }
- /**
- * Split the schematics into a 2D grid of characters
- *
- * @param {string[]} schematics The array of lines from the schematics
- * @returns {string[][]} A 2D grid of characters
- */
- export function BuildSchematicsMap(schematics: string[]): string[][] {
- return schematics.map((schematicsLine) => schematicsLine.split(''));
- }
- /**
- * An engine part
- */
- export type EnginePart = {
- PartNumber: number,
- Coordinates: Vector2[],
- };
- /**
- * A gear on the schematics map
- *
- * A gear is any `*` symbol from the schematics map that borders
- * exactly two engine part numbers.
- */
- export type SchematicsGear = {
- Symbol: string,
- Coordinates: Vector2,
- GearRatio: number
- };
- /**
- * A position within a 2D grid
- */
- export type Vector2 = {
- X: number,
- Y: number,
- };
|