3d12's recent activity

  1. Comment on Paramount Plus and Showtime become ‘Paramount Plus with Showtime’ in ~tv

    3d12
    Link Parent
    Paramount+ with Showtime: Deluxe Ultimate Complete Streaming Service of the Year Edition

    Paramount+ with Showtime: Deluxe Ultimate Complete Streaming Service of the Year Edition

  2. Comment on This shall be my last post about MUD games in ~games

    3d12
    Link Parent
    Yeah, that's the site for ATS. They've got ship systems, some kind of commodity-based economy, and automated trading vessels going between stations; lots of really interesting mechanics which lend...

    Yeah, that's the site for ATS. They've got ship systems, some kind of commodity-based economy, and automated trading vessels going between stations; lots of really interesting mechanics which lend themselves well to players trying to generate their own content instead of having it randomly generated for them.

    The social interaction is difficult sometimes, yeah. It's especially hard to get people onto the same timeframe for multiple scenes over an arc. But it just takes getting involved and putting yourself out there, just like any other community.

    2 votes
  3. Comment on This shall be my last post about MUD games in ~games

    3d12
    Link
    Great write-up, lou! I used to be really into MU* games, spending most of that time on a Star Trek MUSH around 2009. What really struck me about that type of game is the freedom and creativity...

    Great write-up, lou!

    I used to be really into MU* games, spending most of that time on a Star Trek MUSH around 2009. What really struck me about that type of game is the freedom and creativity allowed in building and describing things.

    As an analogy, some games will give me color sliders to change the RGB values of my character's armor. But no game (that I know of) gives me the ability to import my own meshes and textures to make my armor look like literally whatever I want. That's the kind of freedom given to text.

    Aside from just description, you make an excellent point about mechanics. The MUSH I played on used Aspace (originally from and still used by Among the Stars TrekMUSH) and that system is so incredible from a ship systems and command perspective. Easily the most fun I've had piloting a spaceship in any game.

    3 votes
  4. Comment on Advent of Code 2022 post-mortem discussion in ~comp.advent_of_code

    3d12
    Link
    Confirmed, there is no day 26. Instead, how about a brief post-mortem from participants? Favorite/least favorite problems, any interesting workarounds, or something new you learned? I struggled...

    Confirmed, there is no day 26. Instead, how about a brief post-mortem from participants? Favorite/least favorite problems, any interesting workarounds, or something new you learned?

    I struggled immensely with day 15, and that threw my rhythm off completely for the rest of the event. I also didn't bother posting any of my solutions in the threads this year, but since my wife is now learning Python, I tried doing the problems in Python so she could follow along. I took much better advantage of list comprehension this time, to great effect too, since I liked the map() functionality of Javascript so much when I used that last year.

    My favorite problem this year was the CRT display one (day 10) just because I love the problems with a visual solution (see also: transparent origami, AoC 2021 Day 13)

    My repo of solution code: https://github.com/3d12/adventofcode2022-py

    I also admit I had to peek at the thread for day 13 to find the solution to part 2. My math skills were failing me and I tried a bunch of different modulo numbers but didn't even think of the lowest common multiple.

    2 votes
  5. Comment on The next (monthly, one-month-long) Linux Upskill Challenge starts this Monday in ~comp

    3d12
    Link Parent
    Thanks for bringing this up, Eric_the_Cerise :) I am also following along with this, but I don't feel like logging into reddit to participate. Will it be too noisy if we create daily threads to...

    Thanks for bringing this up, Eric_the_Cerise :) I am also following along with this, but I don't feel like logging into reddit to participate. Will it be too noisy if we create daily threads to share our progress on this event? Would weekly perhaps work better?

    As for my day 1, I actually went ahead and added the SSH key for login on day 0 (setup) since Digital Ocean offers that instead of a password-based login. So I ended up getting a little ahead and not having much to do today. But I'm looking forward to learning more sysadmin stuff! Specifically, I'm not so good with systemd yet or networking & sockets, so I'm hoping this event will touch on those topics.

    1 vote
  6. Comment on Day 13: Transparent Origami in ~comp.advent_of_code

    3d12
    Link
    Friggin' yeesh. With everyone saying how easy this year is compared to previous, it's no wonder I couldn't hang in this far in previous years. This did end up being a very fun (and visually...

    Friggin' yeesh. With everyone saying how easy this year is compared to previous, it's no wonder I couldn't hang in this far in previous years.

    This did end up being a very fun (and visually pleasing!) problem once I worked out the kinks. I knew I'd get in trouble for "standardizing" my test folds to a centralized axis, so that did come back to bite me. But I went ahead and coded for all the folds since the problem implied that was the next step, and ended up getting some fun map/filter practice to backwardly-derive my answer to part 1.

    Part 1
    const fs = require('fs');
    const readline = require('readline');
    
    let inputArr = [];
    
    async function openFileForReading(file) {
    	const fileStream = fs.createReadStream(file);
    
    	const rl = readline.createInterface({
    		input: fileStream,
    		crlfDelay: Infinity
    	});
    
    	for await (const line of rl) {
    		try {
    			inputArr.push(line);
    		} catch(e) {
    			console.error(e);
    		}
    	}
    }
    
    function parseGrid(input) {
    	let gridPoints = [];
    	for (const line of input) {
    		let regex = /(\d+),(\d+)/;
    		let found = line.match(regex);
    		if (found) {
    			let pointX = parseInt(found[1]);
    			let pointY = parseInt(found[2]);
    			gridPoints.push({ x: pointX, y: pointY });
    		}
    	}
    	let foldInstructions = [];
    	for (const line of input) {
    		let regex = /fold along ([x|y])=(\d+)/;
    		let found = line.match(regex);
    		if (found) {
    			let foldDirection = found[1];
    			let foldDistance = parseInt(found[2]);
    			foldInstructions.push({ direction: foldDirection, distance: foldDistance });
    		}
    	}
    	return { gridPoints: gridPoints, foldInstructions: foldInstructions };
    }
    
    function mapGrid(input) {
    	let output = [];
    	console.log("DEBUG: input.map(e => e.x) = " + input.map(e => e.x).sort((a,b) => b-a)[0]);
    	let length = input.map(e => e.x).sort((a,b) => b-a)[0];
    	let depth = input.map(e => e.y).sort((a,b) => b-a)[0];
    	console.log("DEBUG: length = " + length + ", depth = " + depth);
    	for (let y = 0; y <= depth; y++) {
    		let currentLine = [];
    		for (let x = 0; x <= length; x++) {
    			if (input.filter(e => e.x === x).filter(e => e.y === y).length > 0) {
    				currentLine.push('#');
    			} else {
    				currentLine.push('.');
    			}
    		}
    		output.push(currentLine);
    	}
    	return output;
    }
    
    function foldGrid(input,direction,distance) {
    	let output = [];
    	if (direction === 'x') {
    		let inputCopy = input.map(e => e);
    		for (let row of inputCopy) {
    			row[distance] = '|';
    		}
    		console.log(inputCopy.map(e => e.join('')).join('\n'));
    		for (let row of inputCopy) {
    			let newRow = [];
    			for (let i = 0; i < distance; i++) {
    				let char1 = row[i];
    				let char2 = row[i+((distance-i)*2)];
    				if (char1 === '#' || char2 === '#') {
    					newRow.push('#');
    				} else {
    					newRow.push('.');
    				}
    			}
    			output.push(newRow);
    		}
    	} else if (direction === 'y') {
    		let foldRow = [];
    		for (let i = 0; i<input[distance].length; i++) {
    			foldRow.push('-');
    		}
    		let inputCopy = input.map(e => e);
    		inputCopy[distance] = foldRow;
    		console.log(inputCopy.map(e => e.join('')).join('\n'));
    		for (let i = 0; i < distance; i++) {
    			let currentRow = inputCopy[i];
    			let compareRow = [];
    			let distanceOffset = i+((distance-i)*2);
    			if (distanceOffset < inputCopy.length) {
    				compareRow = inputCopy[i+((distance-i)*2)];
    			} else {
    				compareRow = currentRow;
    			}
    			let newRow = [];
    			for (let charIndex = 0; charIndex < currentRow.length; charIndex++) {
    				let currentChar = currentRow[charIndex];
    				let compareChar = compareRow[charIndex];
    				if (currentChar === '#' || compareChar === '#') {
    					newRow.push('#');
    				} else {
    					newRow.push('.');
    				}
    			}
    			output.push(newRow);
    		}
    	} else {
    		return new Exception("Invalid direction passed: " + direction);
    	}
    	return output;
    }
    
    (async function mainExecution() {
    	await openFileForReading('input.txt');
    	let parsedGrid = parseGrid(inputArr);
    	console.log(parsedGrid);
    	let fold = 0;
    	let foldedMap = mapGrid(parsedGrid.gridPoints);
    	console.log("DEBUG: fold = " + fold + ", direction = " + parsedGrid.foldInstructions[0].direction + ", distance = " + parsedGrid.foldInstructions[0].distance);
    	console.log(foldedMap.map(e => e.join('')).join('\n'));
    	console.log('');
    	foldedMap = foldGrid(
    	 			foldedMap,
    	 			parsedGrid.foldInstructions[0].direction,
    	 			parsedGrid.foldInstructions[0].distance
    	 		);
    	// for (const instruction of parsedGrid.foldInstructions) {
    	// 	fold++;
    	// 	console.log("DEBUG: fold = " + fold + ", direction = " + instruction.direction + ", distance = " + instruction.distance);
    	// 	foldedMap = foldGrid(
    	// 			foldedMap,
    	// 			instruction.direction,
    	// 			instruction.distance
    	// 		);
    	// 	console.log('');
    	// 	console.log(foldedMap.map(e => e.join('')).join('\n'));
    	// 	console.log('');
    	// }
    	let totalDots = foldedMap
    		.filter(e => e.includes('#'))
    		.map(e => e.filter(f => f === '#').length)
    		.reduce((a,b) => a + b);
    	console.log("Answer found! " + totalDots);
    })();
    
    Part 2
    const fs = require('fs');
    const readline = require('readline');
    
    let inputArr = [];
    
    async function openFileForReading(file) {
    	const fileStream = fs.createReadStream(file);
    
    	const rl = readline.createInterface({
    		input: fileStream,
    		crlfDelay: Infinity
    	});
    
    	for await (const line of rl) {
    		try {
    			inputArr.push(line);
    		} catch(e) {
    			console.error(e);
    		}
    	}
    }
    
    function parseGrid(input) {
    	let gridPoints = [];
    	for (const line of input) {
    		let regex = /(\d+),(\d+)/;
    		let found = line.match(regex);
    		if (found) {
    			let pointX = parseInt(found[1]);
    			let pointY = parseInt(found[2]);
    			gridPoints.push({ x: pointX, y: pointY });
    		}
    	}
    	let foldInstructions = [];
    	for (const line of input) {
    		let regex = /fold along ([x|y])=(\d+)/;
    		let found = line.match(regex);
    		if (found) {
    			let foldDirection = found[1];
    			let foldDistance = parseInt(found[2]);
    			foldInstructions.push({ direction: foldDirection, distance: foldDistance });
    		}
    	}
    	return { gridPoints: gridPoints, foldInstructions: foldInstructions };
    }
    
    function mapGrid(input) {
    	let output = [];
    	console.log("DEBUG: input.map(e => e.x) = " + input.map(e => e.x).sort((a,b) => b-a)[0]);
    	let length = input.map(e => e.x).sort((a,b) => b-a)[0];
    	let depth = input.map(e => e.y).sort((a,b) => b-a)[0];
    	console.log("DEBUG: length = " + length + ", depth = " + depth);
    	for (let y = 0; y <= depth; y++) {
    		let currentLine = [];
    		for (let x = 0; x <= length; x++) {
    			if (input.filter(e => e.x === x).filter(e => e.y === y).length > 0) {
    				currentLine.push('#');
    			} else {
    				currentLine.push('.');
    			}
    		}
    		output.push(currentLine);
    	}
    	return output;
    }
    
    function foldGrid(input,direction,distance) {
    	let output = [];
    	if (direction === 'x') {
    		let inputCopy = input.map(e => e);
    		for (let row of inputCopy) {
    			row[distance] = '|';
    		}
    		console.log(inputCopy.map(e => e.join('')).join('\n'));
    		for (let row of inputCopy) {
    			let newRow = [];
    			for (let i = 0; i < distance; i++) {
    				let char1 = row[i];
    				let char2 = row[i+((distance-i)*2)];
    				if (char1 === '#' || char2 === '#') {
    					newRow.push('#');
    				} else {
    					newRow.push('.');
    				}
    			}
    			output.push(newRow);
    		}
    	} else if (direction === 'y') {
    		let foldRow = [];
    		for (let i = 0; i<input[distance].length; i++) {
    			foldRow.push('-');
    		}
    		let inputCopy = input.map(e => e);
    		inputCopy[distance] = foldRow;
    		console.log(inputCopy.map(e => e.join('')).join('\n'));
    		for (let i = 0; i < distance; i++) {
    			let currentRow = inputCopy[i];
    			let compareRow = [];
    			let distanceOffset = i+((distance-i)*2);
    			if (distanceOffset < inputCopy.length) {
    				compareRow = inputCopy[i+((distance-i)*2)];
    			} else {
    				compareRow = currentRow;
    			}
    			let newRow = [];
    			for (let charIndex = 0; charIndex < currentRow.length; charIndex++) {
    				let currentChar = currentRow[charIndex];
    				let compareChar = compareRow[charIndex];
    				if (currentChar === '#' || compareChar === '#') {
    					newRow.push('#');
    				} else {
    					newRow.push('.');
    				}
    			}
    			output.push(newRow);
    		}
    	} else {
    		return new Exception("Invalid direction passed: " + direction);
    	}
    	return output;
    }
    
    (async function mainExecution() {
    	await openFileForReading('input.txt');
    	let parsedGrid = parseGrid(inputArr);
    	console.log(parsedGrid);
    	let fold = 0;
    	let foldedMap = mapGrid(parsedGrid.gridPoints);
    	console.log("DEBUG: fold = " + fold + ", direction = " + parsedGrid.foldInstructions[0].direction + ", distance = " + parsedGrid.foldInstructions[0].distance);
    	console.log(foldedMap.map(e => e.join('')).join('\n'));
    	for (const instruction of parsedGrid.foldInstructions) {
    		fold++;
    		console.log("DEBUG: fold = " + fold + ", direction = " + instruction.direction + ", distance = " + instruction.distance);
    		foldedMap = foldGrid(
    				foldedMap,
    				instruction.direction,
    				instruction.distance
    			);
    		console.log('');
    		console.log(foldedMap.map(e => e.join('')).join('\n'));
    		console.log('');
    	}
    })();
    
    3 votes
  7. Comment on Day 12: Passage Pathing in ~comp.advent_of_code

    3d12
    Link Parent
    Really bad. Like, over a minute? But, I didn't try it with all the console.log statements removed.

    Really bad. Like, over a minute? But, I didn't try it with all the console.log statements removed.

    3 votes
  8. Comment on Day 12: Passage Pathing in ~comp.advent_of_code

    3d12
    Link
    Like others, I also stared at this problem for many minutes before writing any code. In fact, I thought about it so long, I fell asleep and decided to tackle it today instead. I'm not great at...

    Like others, I also stared at this problem for many minutes before writing any code. In fact, I thought about it so long, I fell asleep and decided to tackle it today instead.

    I'm not great at recursive functions, so imagine my surprise when the problem circumvented my expectations (and the reason I parsed the upper-cased-ness of the letters into a boolean flag in part 1) which led to my business side coding kicking in, and implementing a horrible "exclusion rule" which is used both in the selection criteria, then again in the actual recursion step in part 2. Hey, at least it worked. ¯\_(ツ)_/¯

    Part 1
    const fs = require('fs');
    const readline = require('readline');
    
    let inputArr = [];
    
    async function openFileForReading(file) {
    	const fileStream = fs.createReadStream(file);
    
    	const rl = readline.createInterface({
    		input: fileStream,
    		crlfDelay: Infinity
    	});
    
    	for await (const line of rl) {
    		try {
    			inputArr.push(line);
    		} catch(e) {
    			console.error(e);
    		}
    	}
    }
    
    function parseCaves(input) {
    	let cavesArr = [];
    	for (const line of input) {
    		let lineRegex = /(\w+)-(\w+)/;
    		let found = line.match(lineRegex);
    		let dest1 = found[1];
    		let dest2 = found[2];
    		console.log("DEBUG: line parsed, dest1 = " + dest1 + ", dest2 = " + dest2);
    		let findDest1 = cavesArr.filter(e => e.name === dest1);
    		if (findDest1.length === 0) {
    			let multiplePassThrough = false;
    			if (dest1 === dest1.toUpperCase()) {
    				multiplePassThrough = true;
    			}
    			cavesArr.push({ name: dest1, leadsTo: [ dest2 ], multiplePassThrough: multiplePassThrough });
    		} else {
    			findDest1[0].leadsTo.push(dest2);
    		}
    		let findDest2 = cavesArr.filter(e => e.name === dest2);
    		if (findDest2.length === 0) {
    			let multiplePassThrough = false;
    			if (dest2 === dest2.toUpperCase()) {
    				multiplePassThrough = true;
    			}
    			cavesArr.push({ name: dest2, leadsTo: [ dest1 ], multiplePassThrough: multiplePassThrough});
    		} else {
    			findDest2[0].leadsTo.push(dest1);
    		}
    	}
    	return cavesArr;
    }
    
    function findPaths(mapArr, startRoom=mapArr.filter(e => e.name === 'start')[0], currentPath=[], pathsArr=[]) {
    	console.log("DEBUG: entering findPaths, startRoom is " + startRoom.name + " and currentPath is " + currentPath.map(e => e.name).join(','));
    	if (startRoom.name === 'end') {
    		console.log("DEBUG: ending findPaths, found end room");
    		let tempPath = currentPath.map(e => e);
    		tempPath.push(startRoom);
    		pathsArr.push(tempPath);
    		return pathsArr;
    	}
    	if (startRoom.name === 'start') {
    		console.log("DEBUG: starting findPaths, found start room");
    		currentPath.push(startRoom);
    	}
    	let dests = startRoom.leadsTo;
    	let destObjects = [];
    	for (const dest of dests) {
    		destObjects.push(mapArr.filter(e => e.name === dest)[0]);
    	}
    	let eligibleDests = destObjects.filter(e => (currentPath.filter(f => e.name === f.name).length === 0) || e.multiplePassThrough === true);
    	//console.log("DEBUG: eligible dests: " + eligibleDests.map(e => e.name).join(','));
    	for (const dest of eligibleDests) {
    		let tempPath = currentPath.map(e => e);
    		if (dest.name != 'end') {
    			tempPath.push(dest);
    		}
    		//console.log("DEBUG: about to recurse, startRoom = " + startRoom.name + ", dest = " + dest.name + ", currentPath = " + tempPath.map(e => e.name).join(',') + " and pathsArr = " + pathsArr.map(e => e.map(f => f.name).join(',')).join(';'))
    		findPaths(mapArr, dest, tempPath, pathsArr);
    	}
    	return pathsArr;
    }
    
    (async function mainExecution() {
    	await openFileForReading('input.txt');
    	let cavesArr = parseCaves(inputArr);
    	console.log(cavesArr);
    	let paths = findPaths(cavesArr);
    	console.log(paths);
    	console.log(paths.length);
    })();
    
    Part 2
    const fs = require('fs');
    const readline = require('readline');
    
    let inputArr = [];
    
    async function openFileForReading(file) {
    	const fileStream = fs.createReadStream(file);
    
    	const rl = readline.createInterface({
    		input: fileStream,
    		crlfDelay: Infinity
    	});
    
    	for await (const line of rl) {
    		try {
    			inputArr.push(line);
    		} catch(e) {
    			console.error(e);
    		}
    	}
    }
    
    function parseCaves(input) {
    	let cavesArr = [];
    	for (const line of input) {
    		let lineRegex = /(\w+)-(\w+)/;
    		let found = line.match(lineRegex);
    		let dest1 = found[1];
    		let dest2 = found[2];
    		console.log("DEBUG: line parsed, dest1 = " + dest1 + ", dest2 = " + dest2);
    		let findDest1 = cavesArr.filter(e => e.name === dest1);
    		if (findDest1.length === 0) {
    			let multiplePassThrough = false;
    			if (dest1 === dest1.toUpperCase()) {
    				multiplePassThrough = true;
    			}
    			cavesArr.push({ name: dest1, leadsTo: [ dest2 ], multiplePassThrough: multiplePassThrough });
    		} else {
    			findDest1[0].leadsTo.push(dest2);
    		}
    		let findDest2 = cavesArr.filter(e => e.name === dest2);
    		if (findDest2.length === 0) {
    			let multiplePassThrough = false;
    			if (dest2 === dest2.toUpperCase()) {
    				multiplePassThrough = true;
    			}
    			cavesArr.push({ name: dest2, leadsTo: [ dest1 ], multiplePassThrough: multiplePassThrough});
    		} else {
    			findDest2[0].leadsTo.push(dest1);
    		}
    	}
    	return cavesArr;
    }
    
    function findPaths(mapArr, startRoom=mapArr.filter(e => e.name === 'start')[0], currentPath=[], pathsArr=[], smallRoomDoubled=false) {
    	console.log("DEBUG: entering findPaths, startRoom is " + startRoom.name + ", smallRoomDoubled is " + smallRoomDoubled + ", and currentPath is " + currentPath.map(e => e.name).join(','));
    	if (startRoom.name === 'end') {
    		console.log("DEBUG: ending findPaths, found end room");
    		let tempPath = currentPath.map(e => e);
    		tempPath.push(startRoom);
    		pathsArr.push(tempPath);
    		return pathsArr;
    	}
    	if (startRoom.name === 'start') {
    		console.log("DEBUG: starting findPaths, found start room");
    		currentPath.push(startRoom);
    	}
    	let dests = startRoom.leadsTo;
    	let destObjects = [];
    	for (const dest of dests) {
    		destObjects.push(mapArr.filter(e => e.name === dest)[0]);
    	}
    	let eligibleDests = destObjects.filter(e =>
    		(
    		currentPath.filter(f => e.name === f.name).length === 0
    		||
    		e.multiplePassThrough === true
    		||
    		(
    			e.name === e.name.toLowerCase()
    			&& currentPath.filter(f => e.name === f.name).length === 1
    			&& smallRoomDoubled === false
    			&& e.name != 'start'
    			&& e.name != 'end'
    		)
    	));
    	//console.log("DEBUG: eligible dests: " + eligibleDests.map(e => e.name).join(','));
    	for (const dest of eligibleDests) {
    		let tempPath = currentPath.map(e => e);
    		let tempSmallRoomDoubled = smallRoomDoubled;
    		if (dest.name != 'end') {
    			tempPath.push(dest);
    		}
    		if (
    				dest.name === dest.name.toLowerCase()
    				&& currentPath.filter(f => dest.name === f.name).length === 1
    				&& tempSmallRoomDoubled === false
    				&& dest.name != 'start'
    				&& dest.name != 'end'
    			) {
    				findPaths(mapArr, dest, tempPath, pathsArr, true);
    		} else {
    			//console.log("DEBUG: about to recurse, startRoom = " + startRoom.name + ", dest = " + dest.name + ", currentPath = " + tempPath.map(e => e.name).join(',') + " and pathsArr = " + pathsArr.map(e => e.map(f => f.name).join(',')).join(';'))
    			findPaths(mapArr, dest, tempPath, pathsArr, smallRoomDoubled);
    		}
    	}
    	return pathsArr;
    }
    
    (async function mainExecution() {
    	await openFileForReading('input.txt');
    	let cavesArr = parseCaves(inputArr);
    	console.log(cavesArr);
    	let paths = findPaths(cavesArr);
    	console.log(paths);
    	console.log(paths.length);
    })();
    
    2 votes
  9. Comment on Day 11: Dumbo Octopus in ~comp.advent_of_code

    3d12
    Link
    Yay for reusable functions! Just had to add diagonals to my findNeighbors function from day9, and it was ready to be re-used! On a side note, part 2's output was extremely visually satisfying to...

    Yay for reusable functions! Just had to add diagonals to my findNeighbors function from day9, and it was ready to be re-used! On a side note, part 2's output was extremely visually satisfying to me. :)

    Oh! And I'm extremely proud of my solve time between the two parts. Part 2 only took +3m from part 1, because I was already returning the count of flashes from each iteration, and the comparison for that is a calculable constant!

    Part 1
    const fs = require('fs');
    const readline = require('readline');
    
    let inputArr = [];
    
    async function openFileForReading(file) {
    	const fileStream = fs.createReadStream(file);
    
    	const rl = readline.createInterface({
    		input: fileStream,
    		crlfDelay: Infinity
    	});
    
    	for await (const line of rl) {
    		try {
    			inputArr.push(line);
    		} catch(e) {
    			console.error(e);
    		}
    	}
    }
    
    function findNeighbors(x,y,octopusGrid) {
    	let neighbors = [];
    	let rowBoundary = octopusGrid.length-1;
    	let colBoundary = octopusGrid[0].length-1;
    	// left
    	if (x-1 >= 0) {
    		neighbors.push({ x: x-1, y: y });
    	}
    	// right
    	if (x+1 <= colBoundary) {
    		neighbors.push({ x: x+1, y: y });
    	}
    	// up
    	if (y-1 >= 0) {
    		neighbors.push({ x: x, y: y-1 });
    	}
    	// down
    	if (y+1 <= rowBoundary) {
    		neighbors.push({ x: x, y: y+1 });
    	}
    	// up-left
    	if (x-1 >= 0 && y-1 >= 0) {
    		neighbors.push({ x: x-1, y: y-1 });
    	}
    	// up-right
    	if (x+1 <= colBoundary && y-1 >= 0) {
    		neighbors.push({ x: x+1, y: y-1 });
    	}
    	// down-left
    	if (x-1 >= 0 && y+1 <= rowBoundary) {
    		neighbors.push({ x: x-1, y: y+1 });
    	}
    	// down-right
    	if (x+1 <= colBoundary && y+1 <= rowBoundary) {
    		neighbors.push({ x: x+1, y: y+1 });
    	}
    	return neighbors;
    }
    
    function simulateStep(octopusGrid) {
    	let flashedThisStep = [];
    	let newGrid = [];
    	// serialize into objects
    	for (let y = 0; y < octopusGrid.length; y++) {
    		let currentRow = octopusGrid[y];
    		let newRow = [];
    		for (let x = 0; x < currentRow.length; x++) {
    			newRow.push({ numericValue: octopusGrid[y][x] });
    		}
    		newGrid.push(newRow);
    	}
    	// increment every octopus' value by 1
    	for (let y = 0; y < newGrid.length; y++) {
    		let currentRow = newGrid[y];
    		for (let x = 0; x < currentRow.length; x++) {
    			newGrid[y][x].numericValue++;
    		}
    	}
    	// check for flashes
    	for (let y = 0; y < newGrid.length; y++) {
    		let currentRow = newGrid[y];
    		for (let x = 0; x < currentRow.length; x++) {
    			let currentOctopus = currentRow[x];
    			// on flash, if not already flashed this step
    			if (currentOctopus.numericValue > 9 && flashedThisStep.filter(e => e.x === x && e.y === y).length === 0) {
    				let flashesToResolve = [ { x: x, y: y } ];
    				while (flashesToResolve.length > 0) {
    					//console.log("DEBUG: flashesToResolve = " + flashesToResolve.map(e => e.x + ',' + e.y).join(';'));
    					let resolvingFlash = flashesToResolve.pop();
    					//console.log("DEBUG: " + resolvingFlash.x + "," + resolvingFlash.y + " (" + newGrid[resolvingFlash.y][resolvingFlash.x].numericValue + ") flashed");
    					// add to flashedThisStep
    					flashedThisStep.push({ x: resolvingFlash.x, y: resolvingFlash.y });
    					let neighbors = findNeighbors(resolvingFlash.x,resolvingFlash.y,newGrid);
    					//console.log("DEBUG: neighbors: " + neighbors.map(e => e.x + "," + e.y).join(';'));
    					// increase all neighbors
    					for (const neighbor of neighbors) {
    						//console.log("DEBUG: increasing neighbor " + neighbor.x + "," + neighbor.y + " (" + newGrid[neighbor.y][neighbor.x].numericValue + ") -> (" + (newGrid[neighbor.y][neighbor.x].numericValue + 1) + ")");
    						newGrid[neighbor.y][neighbor.x].numericValue++;
    						// check for flashes
    						if (newGrid[neighbor.y][neighbor.x].numericValue > 9
    								&& flashedThisStep.filter(e => e.x === neighbor.x && e.y === neighbor.y).length === 0
    								&& flashesToResolve.filter(e => e.x === neighbor.x && e.y === neighbor.y).length === 0) {
    							//console.log("DEBUG: adding " + neighbor.x + "," + neighbor.y + " to flashesToResolve");
    							// add to flashesToResolve
    							flashesToResolve.push(neighbor);
    						}
    					}
    				}
    			}
    		}
    	}
    	// all flashed octopi have their energy reset
    	for (const flashed of flashedThisStep) {
    		newGrid[flashed.y][flashed.x].numericValue = 0;
    	}
    	return { updatedGrid: newGrid.map(e => e.map(f => f.numericValue)), flashedThisStep: flashedThisStep };
    }
    
    (async function mainExecution() {
    	await openFileForReading('input.txt');
    	let octopusArr = [];
    	let totalFlashes = 0;
    	for (const line of inputArr) {
    		let tempLine = [];
    		for (const char of line) {
    			tempLine.push(parseInt(char));
    		}
    		octopusArr.push(tempLine);
    	}
    	//console.log(octopusArr.map(e => e.join('')).join('\n'));
    	console.log("DEBUG: start of step 1: ");
    	console.log(octopusArr.map(e => e.join('')).join('\n'));
    	console.log("DEBUG: totalFlashes = " + totalFlashes);
    	let updatedArr = simulateStep(octopusArr);
    	totalFlashes += updatedArr.flashedThisStep.length;
    	console.log("DEBUG: end of step 1: ");
    	console.log(updatedArr.updatedGrid.map(e => e.join('')).join('\n'));
    	console.log("DEBUG: totalFlashes = " + totalFlashes);
    	for (let i = 0; i < 99; i++) {
    		console.log("DEBUG: start of step " + (i+2) + ": ");
    		console.log(updatedArr.updatedGrid.map(e => e.join('')).join('\n'));
    		console.log("DEBUG: totalFlashes = " + totalFlashes);
    		updatedArr = simulateStep(updatedArr.updatedGrid);
    		totalFlashes += updatedArr.flashedThisStep.length;
    		console.log("DEBUG: end of step " + (i+2) + ": ");
    		console.log(updatedArr.updatedGrid.map(e => e.join('')).join('\n'));
    		console.log("DEBUG: totalFlashes = " + totalFlashes);
    	}
    })();
    
    Part 2
    const fs = require('fs');
    const readline = require('readline');
    
    let inputArr = [];
    
    async function openFileForReading(file) {
    	const fileStream = fs.createReadStream(file);
    
    	const rl = readline.createInterface({
    		input: fileStream,
    		crlfDelay: Infinity
    	});
    
    	for await (const line of rl) {
    		try {
    			inputArr.push(line);
    		} catch(e) {
    			console.error(e);
    		}
    	}
    }
    
    function findNeighbors(x,y,octopusGrid) {
    	let neighbors = [];
    	let rowBoundary = octopusGrid.length-1;
    	let colBoundary = octopusGrid[0].length-1;
    	// left
    	if (x-1 >= 0) {
    		neighbors.push({ x: x-1, y: y });
    	}
    	// right
    	if (x+1 <= colBoundary) {
    		neighbors.push({ x: x+1, y: y });
    	}
    	// up
    	if (y-1 >= 0) {
    		neighbors.push({ x: x, y: y-1 });
    	}
    	// down
    	if (y+1 <= rowBoundary) {
    		neighbors.push({ x: x, y: y+1 });
    	}
    	// up-left
    	if (x-1 >= 0 && y-1 >= 0) {
    		neighbors.push({ x: x-1, y: y-1 });
    	}
    	// up-right
    	if (x+1 <= colBoundary && y-1 >= 0) {
    		neighbors.push({ x: x+1, y: y-1 });
    	}
    	// down-left
    	if (x-1 >= 0 && y+1 <= rowBoundary) {
    		neighbors.push({ x: x-1, y: y+1 });
    	}
    	// down-right
    	if (x+1 <= colBoundary && y+1 <= rowBoundary) {
    		neighbors.push({ x: x+1, y: y+1 });
    	}
    	return neighbors;
    }
    
    function simulateStep(octopusGrid) {
    	let flashedThisStep = [];
    	let newGrid = [];
    	// serialize into objects
    	for (let y = 0; y < octopusGrid.length; y++) {
    		let currentRow = octopusGrid[y];
    		let newRow = [];
    		for (let x = 0; x < currentRow.length; x++) {
    			newRow.push({ numericValue: octopusGrid[y][x] });
    		}
    		newGrid.push(newRow);
    	}
    	// increment every octopus' value by 1
    	for (let y = 0; y < newGrid.length; y++) {
    		let currentRow = newGrid[y];
    		for (let x = 0; x < currentRow.length; x++) {
    			newGrid[y][x].numericValue++;
    		}
    	}
    	// check for flashes
    	for (let y = 0; y < newGrid.length; y++) {
    		let currentRow = newGrid[y];
    		for (let x = 0; x < currentRow.length; x++) {
    			let currentOctopus = currentRow[x];
    			// on flash, if not already flashed this step
    			if (currentOctopus.numericValue > 9 && flashedThisStep.filter(e => e.x === x && e.y === y).length === 0) {
    				let flashesToResolve = [ { x: x, y: y } ];
    				while (flashesToResolve.length > 0) {
    					//console.log("DEBUG: flashesToResolve = " + flashesToResolve.map(e => e.x + ',' + e.y).join(';'));
    					let resolvingFlash = flashesToResolve.pop();
    					//console.log("DEBUG: " + resolvingFlash.x + "," + resolvingFlash.y + " (" + newGrid[resolvingFlash.y][resolvingFlash.x].numericValue + ") flashed");
    					// add to flashedThisStep
    					flashedThisStep.push({ x: resolvingFlash.x, y: resolvingFlash.y });
    					let neighbors = findNeighbors(resolvingFlash.x,resolvingFlash.y,newGrid);
    					//console.log("DEBUG: neighbors: " + neighbors.map(e => e.x + "," + e.y).join(';'));
    					// increase all neighbors
    					for (const neighbor of neighbors) {
    						//console.log("DEBUG: increasing neighbor " + neighbor.x + "," + neighbor.y + " (" + newGrid[neighbor.y][neighbor.x].numericValue + ") -> (" + (newGrid[neighbor.y][neighbor.x].numericValue + 1) + ")");
    						newGrid[neighbor.y][neighbor.x].numericValue++;
    						// check for flashes
    						if (newGrid[neighbor.y][neighbor.x].numericValue > 9
    								&& flashedThisStep.filter(e => e.x === neighbor.x && e.y === neighbor.y).length === 0
    								&& flashesToResolve.filter(e => e.x === neighbor.x && e.y === neighbor.y).length === 0) {
    							//console.log("DEBUG: adding " + neighbor.x + "," + neighbor.y + " to flashesToResolve");
    							// add to flashesToResolve
    							flashesToResolve.push(neighbor);
    						}
    					}
    				}
    			}
    		}
    	}
    	// all flashed octopi have their energy reset
    	for (const flashed of flashedThisStep) {
    		newGrid[flashed.y][flashed.x].numericValue = 0;
    	}
    	return { updatedGrid: newGrid.map(e => e.map(f => f.numericValue)), flashedThisStep: flashedThisStep };
    }
    
    (async function mainExecution() {
    	await openFileForReading('input.txt');
    	let octopusArr = [];
    	let totalFlashes = 0;
    	for (const line of inputArr) {
    		let tempLine = [];
    		for (const char of line) {
    			tempLine.push(parseInt(char));
    		}
    		octopusArr.push(tempLine);
    	}
    	//console.log(octopusArr.map(e => e.join('')).join('\n'));
    	console.log("DEBUG: start of step 1: ");
    	console.log(octopusArr.map(e => e.join('')).join('\n'));
    	console.log("DEBUG: totalFlashes = " + totalFlashes);
    	let updatedArr = simulateStep(octopusArr);
    	totalFlashes += updatedArr.flashedThisStep.length;
    	console.log("DEBUG: end of step 1: ");
    	console.log(updatedArr.updatedGrid.map(e => e.join('')).join('\n'));
    	console.log("DEBUG: totalFlashes = " + totalFlashes);
    	let i = 1;
    	while (updatedArr.flashedThisStep.length < (updatedArr.updatedGrid.length * updatedArr.updatedGrid[0].length)) {
    		console.log("DEBUG: start of step " + (i+1) + ": ");
    		console.log(updatedArr.updatedGrid.map(e => e.join('')).join('\n'));
    		console.log("DEBUG: totalFlashes = " + totalFlashes);
    		updatedArr = simulateStep(updatedArr.updatedGrid);
    		totalFlashes += updatedArr.flashedThisStep.length;
    		console.log("DEBUG: end of step " + (i+1) + ": ");
    		console.log(updatedArr.updatedGrid.map(e => e.join('')).join('\n'));
    		console.log("DEBUG: totalFlashes = " + totalFlashes);
    		i++;
    	}
    	console.log("Answer found! They synchronize on step " + i);
    })();
    
    4 votes
  10. Comment on Day 10: Syntax Scoring in ~comp.advent_of_code

    3d12
    Link
    This one was kind of fun, and the most switch statements I've used so far. I thought for about 10 seconds at the start about building a regex pattern to look for these matches, but then shuddered...

    This one was kind of fun, and the most switch statements I've used so far. I thought for about 10 seconds at the start about building a regex pattern to look for these matches, but then shuddered and moved on to what I thought would be easier. And, to my great surprise, my code was in a pretty good spot for part 2 using only the most basic array functions!

    Part 1
    const fs = require('fs');
    const readline = require('readline');
    
    let inputArr = [];
    
    async function openFileForReading(file) {
    	const fileStream = fs.createReadStream(file);
    
    	const rl = readline.createInterface({
    		input: fileStream,
    		crlfDelay: Infinity
    	});
    
    	for await (const line of rl) {
    		try {
    			inputArr.push(line);
    		} catch(e) {
    			console.error(e);
    		}
    	}
    }
    
    function analyzeLine(line) {
    	console.log("DEBUG: analyzing line " + line);
    	let stack = [];
    	for (const char of line) {
    		let compare = undefined;
    		switch (char) {
    			case '(': stack.push(char); break;
    			case '[': stack.push(char); break;
    			case '{': stack.push(char); break;
    			case '<': stack.push(char); break;
    			case ')': compare = stack.pop();
    				if (compare != '(') {
    					return { corrupted: true, violationCharacter: char };
    				}
    				break;
    			case ']': compare = stack.pop();
    				if (compare != '[') {
    					return { corrupted: true, violationCharacter: char };
    				}
    				break;
    			case '}': compare = stack.pop();
    				if (compare != '{') {
    					return { corrupted: true, violationCharacter: char };
    				}
    				break;
    			case '>': compare = stack.pop();
    				if (compare != '<') {
    					return { corrupted: true, violationCharacter: char };
    				}
    				break;
    		}
    	}
    	return { corrupted: false, violationCharacter: undefined };
    }
    
    (async function mainExecution() {
    	await openFileForReading('input.txt');
    	let totalSum = 0;
    	for (const line of inputArr) {
    		let lineResult = analyzeLine(line);
    		console.log(lineResult);
    		if (lineResult.corrupted === true) {
    			let lineScore = 0;
    			console.log(lineResult.violationCharacter);
    			switch (lineResult.violationCharacter) {
    				case ')': lineScore = 3;
    					console.log("DEBUG: ) detected");
    					break;
    				case ']': lineScore = 57;
    					console.log("DEBUG: ] detected");
    					break;
    				case '}': lineScore = 1197;
    					console.log("DEBUG: } detected");
    					break;
    				case '>': lineScore = 25137;
    					console.log("DEBUG: > detected");
    					break;
    			}
    			console.log("DEBUG: Adding " + lineScore + " to " + totalSum);
    			totalSum += lineScore;
    		}
    	}
    	console.log("Answer found! " + totalSum);
    })();
    
    Part 2
    const fs = require('fs');
    const readline = require('readline');
    
    let inputArr = [];
    
    async function openFileForReading(file) {
    	const fileStream = fs.createReadStream(file);
    
    	const rl = readline.createInterface({
    		input: fileStream,
    		crlfDelay: Infinity
    	});
    
    	for await (const line of rl) {
    		try {
    			inputArr.push(line);
    		} catch(e) {
    			console.error(e);
    		}
    	}
    }
    
    function analyzeLine(line) {
    	console.log("DEBUG: analyzing line " + line);
    	let stack = [];
    	let completionSequence = [];
    	for (const char of line) {
    		let compare = undefined;
    		switch (char) {
    			case '(': stack.push(char); break;
    			case '[': stack.push(char); break;
    			case '{': stack.push(char); break;
    			case '<': stack.push(char); break;
    			case ')': compare = stack.pop();
    				if (compare != '(') {
    					return { corrupted: true, violationCharacter: char, completionSequence: undefined };
    				}
    				break;
    			case ']': compare = stack.pop();
    				if (compare != '[') {
    					return { corrupted: true, violationCharacter: char, completionSequence: undefined };
    				}
    				break;
    			case '}': compare = stack.pop();
    				if (compare != '{') {
    					return { corrupted: true, violationCharacter: char, completionSequence: undefined };
    				}
    				break;
    			case '>': compare = stack.pop();
    				if (compare != '<') {
    					return { corrupted: true, violationCharacter: char, completionSequence: undefined };
    				}
    				break;
    		}
    	}
    	if (stack.length > 0) {
    		while (stack.length > 0) {
    			let currentOpening = stack.pop();
    			switch (currentOpening) {
    				case '(': completionSequence.push(')'); break;
    				case '[': completionSequence.push(']'); break;
    				case '{': completionSequence.push('}'); break;
    				case '<': completionSequence.push('>'); break;
    			}
    		}
    		return { corrupted: false, violationCharacter: undefined, completionSequence: completionSequence };
    	} else {
    			return { corrupted: false, violationCharacter: undefined, completionSequence: undefined };
    	}
    }
    
    (async function mainExecution() {
    	await openFileForReading('input.txt');
    	let lineScores = [];
    	for (const line of inputArr) {
    		let lineResult = analyzeLine(line);
    		console.log(lineResult);
    		if (lineResult.corrupted === false) {
    			let lineScore = 0;
    			for (const char of lineResult.completionSequence) {
    				lineScore *= 5;
    				let charValue = 0;
    				switch (char) {
    					case ')': charValue = 1; break;
    					case ']': charValue = 2; break;
    					case '}': charValue = 3; break;
    					case '>': charValue = 4; break;
    				}
    				lineScore += charValue;
    			}
    			console.log("DEBUG: Line complete! lineScore = " + lineScore);
    			lineScores.push(lineScore);
    		}
    	}
    	console.log(lineScores);
    	console.log("Answer found! " + lineScores.sort((a,b) => { return a - b })[Math.floor((lineScores.length - 1) / 2)]);
    })();
    
    5 votes
  11. Comment on Day 9: Smoke Basin in ~comp.advent_of_code

    3d12
    Link
    This problem, in my opinion, has a simplistic elegance to it, in that it can be done in many different ways. Recursion, using a fill algorithm, or even just multi-pass scanning. All just a matter...

    This problem, in my opinion, has a simplistic elegance to it, in that it can be done in many different ways. Recursion, using a fill algorithm, or even just multi-pass scanning. All just a matter of optimization, making this problem accessible to all skill levels of programmer.

    Mine was probably not the best solution, but I had a pretty proud moment when I realized that this type of solution would have been pretty much completely out-of-reach for me two years ago.

    Part 1
    const fs = require('fs');
    const readline = require('readline');
    
    let inputArr = [];
    
    async function openFileForReading(file) {
    	const fileStream = fs.createReadStream(file);
    
    	const rl = readline.createInterface({
    		input: fileStream,
    		crlfDelay: Infinity
    	});
    
    	for await (const line of rl) {
    		try {
    			inputArr.push(line);
    		} catch(e) {
    			console.error(e);
    		}
    	}
    }
    
    function isLowPoint(x,y) {
    	let neighbors = [];
    	let rowBoundary = inputArr.length-1;
    	let colBoundary = inputArr[0].length-1;
    	if (x-1 >= 0) {
    		neighbors.push([x-1, y]);
    	}
    	if (x+1 <= colBoundary) {
    		neighbors.push([x+1, y]);
    	}
    	if (y-1 >= 0) {
    		neighbors.push([x, y-1]);
    	}
    	if (y+1 <= rowBoundary) {
    		neighbors.push([x, y+1]);
    	}
    	let myValue = inputArr[y][x];
    	let isLow = true;
    	for (const neighbor of neighbors) {
    		let theirValue = inputArr[neighbor[1]][neighbor[0]];
    		if (parseInt(theirValue) <= parseInt(myValue)) {
    			isLow = false;
    			break;
    		}
    	}
    	return isLow;
    }
    
    (async function mainExecution() {
    	await openFileForReading('input.txt');
    	let totalSum = 0;
    	for (let y = 0; y < inputArr.length; y++) {
    		let currentRow = inputArr[y];
    		for (let x = 0; x < currentRow.length; x++) {
    			if (isLowPoint(x,y)) {
    				console.log("DEBUG: Found a low point! " + x + "," + y + " -- value: " + currentRow[x]);
    				totalSum += (parseInt(currentRow[x]) + 1);
    			}
    		}
    	}
    	console.log("Answer found! " + totalSum);
    })();
    
    Part 2
    const fs = require('fs');
    const readline = require('readline');
    
    let inputArr = [];
    
    async function openFileForReading(file) {
    	const fileStream = fs.createReadStream(file);
    
    	const rl = readline.createInterface({
    		input: fileStream,
    		crlfDelay: Infinity
    	});
    
    	for await (const line of rl) {
    		try {
    			inputArr.push(line);
    		} catch(e) {
    			console.error(e);
    		}
    	}
    }
    
    function findNeighbors(x,y) {
    	let neighbors = [];
    	let rowBoundary = inputArr.length-1;
    	let colBoundary = inputArr[0].length-1;
    	if (x-1 >= 0) {
    		neighbors.push({ x: x-1, y: y });
    	}
    	if (x+1 <= colBoundary) {
    		neighbors.push({ x: x+1, y: y });
    	}
    	if (y-1 >= 0) {
    		neighbors.push({ x: x, y: y-1 });
    	}
    	if (y+1 <= rowBoundary) {
    		neighbors.push({ x: x, y: y+1 });
    	}
    	return neighbors;
    }
    
    function isLowPoint(x,y) {
    	let neighbors = findNeighbors(x,y);
    	let myValue = inputArr[y][x];
    	let isLow = true;
    	for (const neighbor of neighbors) {
    		let theirValue = inputArr[neighbor.y][neighbor.x];
    		if (parseInt(theirValue) <= parseInt(myValue)) {
    			isLow = false;
    			break;
    		}
    	}
    	return isLow;
    }
    
    function findBasin(startPoint){
    	let eligibleTiles = [ startPoint ];
    	let basin = [];
    	while (eligibleTiles.length > 0) {
    		let currentTile = eligibleTiles.pop();
    		basin.push(currentTile);
    		let currentNeighbors = findNeighbors(currentTile.x,currentTile.y);
    		for (const neighbor of currentNeighbors) {
    			let theirValue = parseInt(inputArr[neighbor.y][neighbor.x]);
    			if (basin.filter(e => (e.x === neighbor.x && e.y === neighbor.y)).length === 0
    					&& eligibleTiles.filter(e => (e.x === neighbor.x && e.y === neighbor.y)).length === 0
    					&& !(theirValue === 9)) {
    				eligibleTiles.push(neighbor);
    			}
    		}
    	}
    	console.log("DEBUG: returning basin = " + basin.map(e => e.x + "," + e.y).join(';'));
    	return basin;
    }
    
    (async function mainExecution() {
    	await openFileForReading('input.txt');
    	let lowPoints = [];
    	let basins = [];
    	for (let y = 0; y < inputArr.length; y++) {
    		let currentRow = inputArr[y];
    		for (let x = 0; x < currentRow.length; x++) {
    			if (isLowPoint(x,y)) {
    				console.log("DEBUG: Found a low point! " + x + "," + y + " -- value: " + currentRow[x]);
    				lowPoints.push({ x: x, y: y });
    			}
    		}
    	}
    	for (const lowPoint of lowPoints) {
    		basins.push(findBasin(lowPoint));
    	}
    	console.log(basins.map(e => e.length).sort((a,b) => { return b - a }));
    	console.log("Answer found! " + basins.map(e => e.length).sort((a,b) => { return b - a }).slice(0,3).reduce((a,b) => a * b));
    })();
    
    3 votes
  12. Comment on Day 8: Seven Segment Search in ~comp.advent_of_code

    3d12
    Link
    I'm so glad to see I'm not the only one who struggled through this one. I went through three different "mental models" of what the final code would look like, and at one point modeled out a...

    I'm so glad to see I'm not the only one who struggled through this one. I went through three different "mental models" of what the final code would look like, and at one point modeled out a SevenSegmentDisplay and SevenSegmentConsole object, and started implementing wire to display connections for each display to figure out what number it was... Before I realized that none of these numbers can figure it out themselves, they all need the information from each other to tell which number is which!

    My solution to part 2 is definitely not optimized, but I don't see anyone else using my same logic! I just implemented the exact steps I took as I was puzzling out the example on paper, with comments to keep my thoughts straight :)

    Part 1
    const fs = require('fs');
    const readline = require('readline');
    
    let inputArr = [];
    
    async function openFileForReading(file) {
    	const fileStream = fs.createReadStream(file);
    
    	const rl = readline.createInterface({
    		input: fileStream,
    		crlfDelay: Infinity
    	});
    
    	for await (const line of rl) {
    		try {
    			inputArr.push(line);
    		} catch(e) {
    			console.error(e);
    		}
    	}
    }
    
    function parseNumbers(line) {
    	let regex = /(\w+) (\w+) (\w+) (\w+) (\w+) (\w+) (\w+) (\w+) (\w+) (\w+) \| (\w+) (\w+) (\w+) (\w+)/;
    	let found = line.match(regex);
    	let signalPatterns = [];
    	let outputValues = [];
    	for (let i=1; i<11; i++) {
    		signalPatterns.push(found[i]);
    	}
    	for (let i=11; i<15; i++) {
    		outputValues.push(found[i]);
    	}
    	return { signalPatterns: signalPatterns, outputValues: outputValues };
    }
    
    (async function mainExecution() {
    	await openFileForReading('input.txt');
    	let totalAppearances = 0;
    	for (const line of inputArr) {
    		let parsed = parseNumbers(line);
    		totalAppearances += parsed.outputValues.filter(e =>
    				e.length === 2 || e.length === 4 || e.length === 3 || e.length === 7).length
    	}
    	console.log("Answer found! " + totalAppearances);
    })();
    
    Part 2
    const fs = require('fs');
    const readline = require('readline');
    
    let inputArr = [];
    
    async function openFileForReading(file) {
    	const fileStream = fs.createReadStream(file);
    
    	const rl = readline.createInterface({
    		input: fileStream,
    		crlfDelay: Infinity
    	});
    
    	for await (const line of rl) {
    		try {
    			inputArr.push(line);
    		} catch(e) {
    			console.error(e);
    		}
    	}
    }
    
    function parseNumbers(line) {
    	let regex = /(\w+) (\w+) (\w+) (\w+) (\w+) (\w+) (\w+) (\w+) (\w+) (\w+) \| (\w+) (\w+) (\w+) (\w+)/;
    	let found = line.match(regex);
    	let signalPatterns = [];
    	let outputValues = [];
    	for (let i=1; i<11; i++) {
    		signalPatterns.push(found[i]);
    	}
    	for (let i=11; i<15; i++) {
    		outputValues.push(found[i]);
    	}
    	return { signalPatterns: signalPatterns, outputValues: outputValues };
    }
    
    class SignalPatternConsole {
    	displays = [];
    
    	constructor(signalPatterns) {
    		// store signal patterns
    		for (const pattern of signalPatterns) {
    			this.displays.push({ wires: pattern, numericValue: undefined })
    		}
    
    		// compute
    		// step 1: identify 1, 4, 7, and 8
    		for (let display of this.displays) {
    			if (display.wires.length === 2) {
    				display.numericValue = 1;
    			}
    			if (display.wires.length === 3) {
    				display.numericValue = 7;
    			}
    			if (display.wires.length === 4) {
    				display.numericValue = 4;
    			}
    			if (display.wires.length === 7) {
    				display.numericValue = 8;
    			}
    		}
    
    		// step 2: identify the top segment
    		let one = this.displays.filter(e => e.numericValue === 1)[0];
    		let seven = this.displays.filter(e => e.numericValue === 7)[0];
    		let topSegment = 'x';
    		for (const segment of seven.wires) {
    			if (!one.wires.includes(segment)) {
    				topSegment = segment;
    			}
    		}
    
    		// step 3: determine which is zero based on the middle (found from
    		//		the difference between 4 and 1)
    		let four = this.displays.filter(e => e.numericValue === 4)[0];
    		let middleSegment = 'x';
    		let possibleMiddle = [];
    		for (const segment of four.wires) {
    			if (!one.wires.includes(segment)) {
    				possibleMiddle.push(segment);
    			}
    		}
    		let sixSegmentClub = this.displays.filter(e => e.wires.length === 6);
    		for (let member of sixSegmentClub) {
    			for (const possibility of possibleMiddle) {
    				if (!member.wires.includes(possibility)){
    					member.numericValue = 0;
    				}
    			}
    		}
    		let zero = this.displays.filter(e => e.numericValue === 0)[0];
    
    		// step 4: determining six based on missing one value from four
    		sixSegmentClub = this.displays.filter(e => e.numericValue === undefined && e.wires.length === 6);
    		for (let member of sixSegmentClub) {
    			let matches = 0;
    			for (const wire of four.wires) {
    				if (member.wires.includes(wire)) {
    					matches++;
    				}
    			}
    			if (matches === 3) {
    				member.numericValue = 6;
    			}
    		}
    		let six = this.displays.filter(e => e.numericValue === 6)[0];
    
    		// step 5: (freebie) nine is the last six-segment number
    		let nine = this.displays.filter(e => e.numericValue === undefined && e.wires.length === 6)[0];
    		nine.numericValue = 9;
    
    		// step 6: match 2 based on only having 2 segments from 4
    		let fiveSegmentClub = this.displays.filter(e => e.numericValue === undefined && e.wires.length === 5);
    		for (let member of fiveSegmentClub) {
    			let matches = 0;
    			for (const wire of four.wires) {
    				if (member.wires.includes(wire)) {
    					matches++;
    				}
    			}
    			if (matches === 2) {
    				member.numericValue = 2;
    			}
    		}
    		let two = this.displays.filter(e => e.numericValue === 2)[0];
    
    		// step 7: match 5 based on only having one segment from 1
    		fiveSegmentClub = this.displays.filter(e => e.numericValue === undefined && e.wires.length === 5);
    		for (let member of fiveSegmentClub) {
    			let matches = 0;
    			for (const wire of one.wires) {
    				if (member.wires.includes(wire)) {
    					matches++;
    				}
    			}
    			if (matches === 1) {
    				member.numericValue = 5;
    			}
    		}
    		let five = this.displays.filter(e => e.numericValue === 5)[0];
    
    		// step 8: last unassigned value is 3
    		let three = this.displays.filter(e => e.numericValue === undefined)[0];
    		three.numericValue = 3;
    
    	}
    
    	translationArray() {
    		let toReturn = [];
    		for (const display of this.displays) {
    			toReturn.push({ wires: display.wires, numericValue: display.numericValue });
    		}
    		return toReturn;
    	}
    }
    
    (async function mainExecution() {
    	await openFileForReading('input.txt');
    	let totalSum = 0;
    	for (const line of inputArr) {
    		let parsed = parseNumbers(line);
    		let cons = new SignalPatternConsole(parsed.signalPatterns);
    		let translation = cons.translationArray();
    		let values = parsed.outputValues;
    		let currentNumber = [];
    		for (const value of values) {
    			let searchList = translation.filter(e => (e.wires.length === value.length));
    			for (const wire of value) {
    				searchList = searchList.filter(e => (e.wires.includes(wire)));
    				if (searchList.length === 1) {
    					currentNumber.push(searchList[0].numericValue);
    					break;
    				}
    			}
    		}
    		console.log("DEBUG: Adding " + parseInt(currentNumber.join('')) + " to " + totalSum);
    		totalSum += parseInt(currentNumber.join(''));
    	}
    
    	console.log("Answer found! " + totalSum);
    })();
    
    2 votes
  13. Comment on Day 7: The Treachery of Whales in ~comp.advent_of_code

    3d12
    (edited )
    Link
    Hello, I'm back! Took a couple days away, solving problems without posting. This one was a good example of a problem where a little math knowledge can go a long way for optimization. Using...

    Hello, I'm back! Took a couple days away, solving problems without posting.

    This one was a good example of a problem where a little math knowledge can go a long way for optimization. Using absolute value instead of writing a loop to "step" each crab into place optimizes by a factor of O(n) -- a good lesson for beginning programmers :)

    Part 1
    const fs = require('fs');
    const readline = require('readline');
    
    let inputArr = [];
    
    async function openFileForReading(file) {
    	const fileStream = fs.createReadStream(file);
    
    	const rl = readline.createInterface({
    		input: fileStream,
    		crlfDelay: Infinity
    	});
    
    	for await (const line of rl) {
    		try {
    			inputArr.push(line);
    		} catch(e) {
    			console.error(e);
    		}
    	}
    }
    
    (async function mainExecution() {
    	await openFileForReading('input.txt');
    	let currentFuel = 0;
    	let bestFuel = 99999999;
    	let bestIndex = 0;
    	let crabPositionArr = inputArr[0].split(',');
    	let maxIndex = crabPositionArr.reduce((a,b) => { return Math.max(a,b) });
    	for (let i = 0; i<maxIndex; i++) {
    		currentFuel = 0;
    		// try aligning all the crabs to this index
    		for (crab of crabPositionArr) {
    			currentFuel += Math.abs(crab - i);
    		}
    		// if this uses less fuel than bestFuel, save this index to bestIndex
    		if (currentFuel < bestFuel) {
    			bestFuel = currentFuel;
    			bestIndex = i;
    		}
    	}
    	console.log("Answer found! Index " + bestIndex + " uses the least fuel at " + bestFuel);
    })();
    
    Part 2
    const fs = require('fs');
    const readline = require('readline');
    
    let inputArr = [];
    
    async function openFileForReading(file) {
    	const fileStream = fs.createReadStream(file);
    
    	const rl = readline.createInterface({
    		input: fileStream,
    		crlfDelay: Infinity
    	});
    
    	for await (const line of rl) {
    		try {
    			inputArr.push(line);
    		} catch(e) {
    			console.error(e);
    		}
    	}
    }
    
    function crabFuel(spaces) {
    	let totalFuel = 0;
    	for (let i = spaces; i > 0; i--) {
    		totalFuel += i;
    	}
    	return totalFuel;
    }
    
    (async function mainExecution() {
    	await openFileForReading('input.txt');
    	let currentFuel = 0;
    	let bestFuel = 99999999;
    	let bestIndex = 0;
    	let crabPositionArr = inputArr[0].split(',');
    	let maxIndex = crabPositionArr.reduce((a,b) => { return Math.max(a,b) });
    	for (let i = 0; i<maxIndex; i++) {
    		currentFuel = 0;
    		// try aligning all the crabs to this index
    		for (crab of crabPositionArr) {
    			currentFuel += crabFuel(Math.abs(crab - i));
    		}
    		// if this uses less fuel than bestFuel, save this index to bestIndex
    		if (currentFuel < bestFuel) {
    			bestFuel = currentFuel;
    			bestIndex = i;
    		}
    	}
    	console.log("Answer found! Index " + bestIndex + " uses the least fuel at " + bestFuel);
    })();
    
    3 votes
  14. Comment on Day 6: Lanternfish in ~comp.advent_of_code

    3d12
    Link
    I knew something was up with the way the problem was described, but to be honest, I was expecting a change in the reproduction mechanism instead of what we got. The part 2 twist seemed almost too...

    I knew something was up with the way the problem was described, but to be honest, I was expecting a change in the reproduction mechanism instead of what we got. The part 2 twist seemed almost too simple until I saw my code struggling to run the test data and eventually getting an "invalid size error" trying to fit 169 million values into an array. Definitely an interesting mislead. I feel pity for anyone who tried to model part 1 using objects.

    Part 1
    const fs = require('fs');
    const readline = require('readline');
    
    let inputArr = [];
    
    async function openFileForReading(file) {
    	const fileStream = fs.createReadStream(file);
    
    	const rl = readline.createInterface({
    		input: fileStream,
    		crlfDelay: Infinity
    	});
    
    	for await (const line of rl) {
    		try {
    			inputArr.push(line);
    		} catch(e) {
    			console.error(e);
    		}
    	}
    }
    
    function processDay(inputArray) {
    	let fishToBeBorn = 0;
    	let outputArray = [];
    	for (const fish of inputArray) {
    		if (fish === 0) {
    			fishToBeBorn++;
    			outputArray.push(6);
    		} else {
    			outputArray.push(fish - 1);
    		}
    	}
    	for (let i=0; i<fishToBeBorn; i++) {
    		outputArray.push(8);
    	}
    	return outputArray;
    }
    
    (async function mainExecution() {
    	await openFileForReading('input.txt');
    	let lanternFishArray = inputArr[0].split(',').map(e => parseInt(e));
    	let days = 0;
    	let totalFish = 0;
    	while (true) {
    		lanternFishArray = processDay(lanternFishArray);
    		days++;
    		if (days === 80) {
    			totalFish = lanternFishArray.length;
    			break;
    		}
    	}
    	console.log("Answer found! " + totalFish);
    })();
    
    Part 2
    const fs = require('fs');
    const readline = require('readline');
    
    let inputArr = [];
    
    async function openFileForReading(file) {
    	const fileStream = fs.createReadStream(file);
    
    	const rl = readline.createInterface({
    		input: fileStream,
    		crlfDelay: Infinity
    	});
    
    	for await (const line of rl) {
    		try {
    			inputArr.push(line);
    		} catch(e) {
    			console.error(e);
    		}
    	}
    }
    
    function processDay(inputSerializedArray) {
    	let fishToBeBorn = 0;
    	let outputObject = { zero: 0, one: 0, two: 0, three: 0, four: 0, five: 0, six: 0, seven: 0, eight: 0 };
    	if (inputSerializedArray.zero > 0) {
    		fishToBeBorn = inputSerializedArray.zero;
    	}
    	outputObject.zero = inputSerializedArray.one;
    	outputObject.one = inputSerializedArray.two;
    	outputObject.two = inputSerializedArray.three;
    	outputObject.three = inputSerializedArray.four;
    	outputObject.four = inputSerializedArray.five;
    	outputObject.five = inputSerializedArray.six;
    	outputObject.six = (inputSerializedArray.seven + fishToBeBorn);
    	outputObject.seven = inputSerializedArray.eight;
    	outputObject.eight = fishToBeBorn;
    	return outputObject;
    }
    
    function serializeArray(inputArray) {
    	let returnObject = { zero: 0, one: 0, two: 0, three: 0, four: 0, five: 0, six: 0, seven: 0, eight: 0 };
    	for (const item of inputArray) {
    		switch (item) {
    			case 0: returnObject.zero++;
    				break;
    			case 1: returnObject.one++;
    				break;
    			case 2: returnObject.two++;
    				break;
    			case 3: returnObject.three++;
    				break;
    			case 4: returnObject.four++;
    				break;
    			case 5: returnObject.five++;
    				break;
    			case 6: returnObject.six++;
    				break;
    			case 7: returnObject.seven++;
    				break;
    			case 8: returnObject.eight++;
    				break;
    			default: return new Error("Invalid number in serialization: " + item);
    		}
    	}
    	return returnObject;
    }
    
    (async function mainExecution() {
    	await openFileForReading('input.txt');
    	let lanternFishArray = serializeArray(inputArr[0].split(',').map(e => parseInt(e)));
    	console.log(lanternFishArray);
    	let days = 0;
    	let totalFish = 0;
    	while (true) {
    		console.log("DEBUG: Processing day " + (days+1) + "...");
    		lanternFishArray = processDay(lanternFishArray);
    		days++;
    		if (days === 256) {
    			totalFish = (lanternFishArray.zero + lanternFishArray.one
    				+ lanternFishArray.two + lanternFishArray.three
    				+ lanternFishArray.four + lanternFishArray.five
    				+ lanternFishArray.six + lanternFishArray.seven
    				+ lanternFishArray.eight);
    			break;
    		}
    	}
    	console.log("Answer found! " + totalFish);
    })();
    
    4 votes
  15. Comment on Day 5: Hydrothermal Venture in ~comp.advent_of_code

    3d12
    Link
    Wow, I was definitely expecting fewer people saying part 2 was difficult. The diff between my part 1 and part 2 is literally 2 lines, I just removed the validation check I put on the input step....

    Wow, I was definitely expecting fewer people saying part 2 was difficult. The diff between my part 1 and part 2 is literally 2 lines, I just removed the validation check I put on the input step. Though to be fair, I suspected the twist right away when the puzzle said to ignore certain inputs... ;)

    Part 1
    const fs = require('fs');
    const readline = require('readline');
    
    let inputArr = [];
    
    async function openFileForReading(file) {
    	const fileStream = fs.createReadStream(file);
    
    	const rl = readline.createInterface({
    		input: fileStream,
    		crlfDelay: Infinity
    	});
    
    	for await (const line of rl) {
    		try {
    			inputArr.push(line);
    		} catch(e) {
    			console.error(e);
    		}
    	}
    }
    
    function findMaxDimensions(vectorArray) {
    	let maxX = 0;
    	let maxY = 0;
    	for (const vectorPair of vectorArray) {
    		if (vectorPair.x1 > maxX) {
    			maxX = vectorPair.x1;
    		}
    		if (vectorPair.y1 > maxY) {
    			maxY = vectorPair.y1;
    		}
    		if (vectorPair.x2 > maxX) {
    			maxX = vectorPair.x2;
    		}
    		if (vectorPair.y2 > maxY) {
    			maxY = vectorPair.y2;
    		}
    	}
    	return { maxX: maxX, maxY: maxY };
    }
    
    function initGrid(x, y) {
    	let grid = [];
    	for (let i=0; i<=y; i++) {
    		let currentRow = [];
    		for (let j=0; j<=x; j++) {
    			currentRow.push('.');
    		}
    		grid.push(currentRow);
    	}
    	return grid;
    }
    
    function addLine(grid, vector) {
    	let startX = vector.x1;
    	let startY = vector.y1;
    	let endX = vector.x2;
    	let endY = vector.y2;
    	let cursorX = startX;
    	let cursorY = startY;
    	console.log("DEBUG: startX = " + startX + ", startY = " + startY);
    	console.log("DEBUG: endX = " + endX + ", endY = " + endY);
    	console.log("DEBUG: cursorX != endX is " + (cursorX != endX));
    	console.log("DEBUG: cursorY != endY is " + (cursorY != endY));
    	while (true) {
    		console.log("DEBUG: cursorX = " + cursorX + ", cursorY = " + cursorY);
    		let row = grid[cursorY];
    		let currentValue = row[cursorX];
    		if (currentValue === '.') {
    			grid[cursorY][cursorX] = 1;
    		} else {
    			grid[cursorY][cursorX]++;
    		}
    		if (cursorX === endX && cursorY === endY) {
    			break;
    		}
    		console.log("DEBUG: cursorX != endX is " + (cursorX != endX));
    		if (cursorX != endX && cursorX > endX) {
    			cursorX--;
    		} else if (cursorX != endX && cursorX < endX) {
    			cursorX++;
    		}
    		console.log("DEBUG: cursorY != endY is " + (cursorY != endY));
    		if (cursorY != endY && cursorY > endY) {
    			cursorY--;
    		} else if (cursorY != endY && cursorY < endY) {
    			cursorY++;
    		}
    	}
    }
    
    function getPoints(grid) {
    	let points = 0;
    	for (const row of grid) {
    		for (const value of row) {
    			if (value > 1) {
    				points++;
    			}
    		}
    	}
    	return points;
    }
    
    function isDiagonal(vector) {
    	return ((vector.x1 != vector.x2) && (vector.y1 != vector.y2));
    }
    
    (async function mainExecution() {
    	await openFileForReading('input.txt');
    	let vectorArray = inputArr.map(e => {
    		let regex = /(\d+),(\d+) -> (\d+),(\d+)/;
    		let found = e.match(regex);
    		return { x1: parseInt(found[1]), y1: parseInt(found[2]),
    			x2: parseInt(found[3]), y2: parseInt(found[4])
    		};
    	});
    	gridDimensions = findMaxDimensions(vectorArray);
    	let grid = initGrid(gridDimensions.maxX, gridDimensions.maxY);
    	console.log(grid.map(e => e.join('')).join('\n'));
    	for (const vector of vectorArray) {
    		if (!isDiagonal(vector)) {
    			console.log("DEBUG: Operating on vector " + vector.x1 + ","
    				+ vector.y1 + " -> " + vector.x2 + "," + vector.y2);
    			addLine(grid, vector);
    			console.log(grid.map(e => e.join('')).join('\n'));
    		}
    	}
    	console.log("Answer found! " + getPoints(grid));
    })();
    
    Part 2
    const fs = require('fs');
    const readline = require('readline');
    
    let inputArr = [];
    
    async function openFileForReading(file) {
    	const fileStream = fs.createReadStream(file);
    
    	const rl = readline.createInterface({
    		input: fileStream,
    		crlfDelay: Infinity
    	});
    
    	for await (const line of rl) {
    		try {
    			inputArr.push(line);
    		} catch(e) {
    			console.error(e);
    		}
    	}
    }
    
    function findMaxDimensions(vectorArray) {
    	let maxX = 0;
    	let maxY = 0;
    	for (const vectorPair of vectorArray) {
    		if (vectorPair.x1 > maxX) {
    			maxX = vectorPair.x1;
    		}
    		if (vectorPair.y1 > maxY) {
    			maxY = vectorPair.y1;
    		}
    		if (vectorPair.x2 > maxX) {
    			maxX = vectorPair.x2;
    		}
    		if (vectorPair.y2 > maxY) {
    			maxY = vectorPair.y2;
    		}
    	}
    	return { maxX: maxX, maxY: maxY };
    }
    
    function initGrid(x, y) {
    	let grid = [];
    	for (let i=0; i<=y; i++) {
    		let currentRow = [];
    		for (let j=0; j<=x; j++) {
    			currentRow.push('.');
    		}
    		grid.push(currentRow);
    	}
    	return grid;
    }
    
    function addLine(grid, vector) {
    	let startX = vector.x1;
    	let startY = vector.y1;
    	let endX = vector.x2;
    	let endY = vector.y2;
    	let cursorX = startX;
    	let cursorY = startY;
    	console.log("DEBUG: startX = " + startX + ", startY = " + startY);
    	console.log("DEBUG: endX = " + endX + ", endY = " + endY);
    	console.log("DEBUG: cursorX != endX is " + (cursorX != endX));
    	console.log("DEBUG: cursorY != endY is " + (cursorY != endY));
    	while (true) {
    		console.log("DEBUG: cursorX = " + cursorX + ", cursorY = " + cursorY);
    		let row = grid[cursorY];
    		let currentValue = row[cursorX];
    		if (currentValue === '.') {
    			grid[cursorY][cursorX] = 1;
    		} else {
    			grid[cursorY][cursorX]++;
    		}
    		if (cursorX === endX && cursorY === endY) {
    			break;
    		}
    		console.log("DEBUG: cursorX != endX is " + (cursorX != endX));
    		if (cursorX != endX && cursorX > endX) {
    			cursorX--;
    		} else if (cursorX != endX && cursorX < endX) {
    			cursorX++;
    		}
    		console.log("DEBUG: cursorY != endY is " + (cursorY != endY));
    		if (cursorY != endY && cursorY > endY) {
    			cursorY--;
    		} else if (cursorY != endY && cursorY < endY) {
    			cursorY++;
    		}
    	}
    }
    
    function getPoints(grid) {
    	let points = 0;
    	for (const row of grid) {
    		for (const value of row) {
    			if (value > 1) {
    				points++;
    			}
    		}
    	}
    	return points;
    }
    
    function isDiagonal(vector) {
    	return ((vector.x1 != vector.x2) && (vector.y1 != vector.y2));
    }
    
    (async function mainExecution() {
    	await openFileForReading('input.txt');
    	let vectorArray = inputArr.map(e => {
    		let regex = /(\d+),(\d+) -> (\d+),(\d+)/;
    		let found = e.match(regex);
    		return { x1: parseInt(found[1]), y1: parseInt(found[2]),
    			x2: parseInt(found[3]), y2: parseInt(found[4])
    		};
    	});
    	gridDimensions = findMaxDimensions(vectorArray);
    	let grid = initGrid(gridDimensions.maxX, gridDimensions.maxY);
    	console.log(grid.map(e => e.join('')).join('\n'));
    	for (const vector of vectorArray) {
    		console.log("DEBUG: Operating on vector " + vector.x1 + ","
    			+ vector.y1 + " -> " + vector.x2 + "," + vector.y2);
    		addLine(grid, vector);
    		console.log(grid.map(e => e.join('')).join('\n'));
    	}
    	console.log("Answer found! " + getPoints(grid));
    })();
    
    3 votes
  16. Comment on How a NYTimes reporter, Ian Urbina, collects royalties from hundreds of musicians via the Outlaw Ocean Music Project in ~music

    3d12
    Link
    Thanks for linking this, cfabbro. For anyone who's not familiar, Benn Jordan makes amazing electronic music under the name The Flashbulb, and his channel is packed full of awesome gear reviews and...

    Thanks for linking this, cfabbro. For anyone who's not familiar, Benn Jordan makes amazing electronic music under the name The Flashbulb, and his channel is packed full of awesome gear reviews and informational videos. Would highly recommend checking him out if you enjoyed this video.

    1 vote
  17. Comment on Day 4: Giant Squid in ~comp.advent_of_code

    3d12
    Link
    Compared to day 3, this one was easier and actually kind of fun to implement. I was quite happy with the change from part 1 to part 2. I was expecting a different twist, so my implementation only...

    Compared to day 3, this one was easier and actually kind of fun to implement. I was quite happy with the change from part 1 to part 2. I was expecting a different twist, so my implementation only required minimal changes to get the new answer.

    Part 1
    const fs = require('fs');
    const readline = require('readline');
    
    let inputArr = [];
    
    async function openFileForReading(file) {
    	const fileStream = fs.createReadStream(file);
    
    	const rl = readline.createInterface({
    		input: fileStream,
    		crlfDelay: Infinity
    	});
    
    	for await (const line of rl) {
    		try {
    			inputArr.push(line);
    		} catch(e) {
    			console.error(e);
    		}
    	}
    }
    
    function parseBingoCard(bingoCardText) {
    	let bingoCardArray = [];
    	let rows = bingoCardText.split('\n');
    	for (const row of rows) {
    		let regex = /(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)/;
    		let found = row.match(regex);
    		let rowArray = [found[1],found[2],found[3],found[4],found[5]];
    		bingoCardArray.push(rowArray);
    	}
    	return bingoCardArray;
    }
    
    function splitBingoCards() {
    	let splitArray = [];
    	let currentBingoCardArray = [];
    	// skip the first two lines, bingo cards start on line 3
    	let bingoCardArray = inputArr.slice(2);
    	for (const line of bingoCardArray) {
    		// on blank line, reset accumulated line and send for parsing
    		if (line.trim().length === 0) {
    			splitArray.push(parseBingoCard(currentBingoCardArray.join('\n')));
    			currentBingoCardArray = [];
    		} else {
    			currentBingoCardArray.push(line);
    		}
    	}
    	// flushing the buffer, in case the last line is not newline-terminated
    	if (currentBingoCardArray.length != 0) {
    		splitArray.push(parseBingoCard(currentBingoCardArray.join('\n')));
    	}
    	return splitArray;
    }
    
    function findBingo(bingoCard, numbersCalled) {
    	// look for horizontal bingos
    	for (const row of bingoCard) {
    		let horizontalBingo = true;
    		for (const number of row) {
    			if (!numbersCalled.includes(parseInt(number))) {
    				horizontalBingo = false;
    				break;
    			}
    		}
    		if (horizontalBingo === true) {
    			return true;
    		}
    	}
    	// look for vertical bingos
    	for (let colIndex = 0; colIndex < bingoCard[0].length; colIndex++) {
    		let verticalBingo = true;
    		for (const row of bingoCard) {
    			if (!numbersCalled.includes(parseInt(row[colIndex]))) {
    				verticalBingo = false;
    				break;
    			}
    		}
    		if (verticalBingo === true) {
    			return true;
    		}
    	}
    	return false;
    }
    
    function findBingoScore(bingoCard, numbersCalled) {
    	let pointSpaces = [];
    	for (const row of bingoCard) {
    		for (const num of row) {
    			if (!numbersCalled.includes(parseInt(num))) {
    				pointSpaces.push(parseInt(num));
    			}
    		}
    	}
    	return (pointSpaces.reduce((a,b) => a+b) * numbersCalled[numbersCalled.length-1]);
    }
    
    (async function mainExecution() {
    	await openFileForReading('input.txt');
    	let numbersToCall = inputArr[0].split(',').map(e => parseInt(e));
    	console.log("DEBUG: numbersToCall = " + numbersToCall);
    	let bingoCardArray = splitBingoCards();
    	let numberCalledIndex = 0;
    	let numbersCalled = [];
    	let winningBoard = [];
    	while (winningBoard.length === 0) {
    		// call new number
    		numberCalledIndex++;
    		numbersCalled = numbersToCall.slice(0,numberCalledIndex);
    
    		// check for win
    		for (bingoCard of bingoCardArray) {
    			if (findBingo(bingoCard,numbersCalled)) {
    				winningBoard = bingoCard;
    				break;
    			}
    		}
    	}
    	console.log("DEBUG: winningBoard =\n" + winningBoard.join('\n'));
    	console.log("DEBUG: numbersCalled = " + numbersCalled);
    	console.log("Answer found! " + findBingoScore(winningBoard,numbersCalled));
    })();
    
    Part 2
    const fs = require('fs');
    const readline = require('readline');
    
    let inputArr = [];
    
    async function openFileForReading(file) {
    	const fileStream = fs.createReadStream(file);
    
    	const rl = readline.createInterface({
    		input: fileStream,
    		crlfDelay: Infinity
    	});
    
    	for await (const line of rl) {
    		try {
    			inputArr.push(line);
    		} catch(e) {
    			console.error(e);
    		}
    	}
    }
    
    function parseBingoCard(bingoCardText) {
    	let bingoCardArray = [];
    	let rows = bingoCardText.split('\n');
    	for (const row of rows) {
    		let regex = /(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)/;
    		let found = row.match(regex);
    		let rowArray = [found[1],found[2],found[3],found[4],found[5]];
    		bingoCardArray.push(rowArray);
    	}
    	return bingoCardArray;
    }
    
    function splitBingoCards() {
    	let splitArray = [];
    	let currentBingoCardArray = [];
    	// skip the first two lines, bingo cards start on line 3
    	let bingoCardArray = inputArr.slice(2);
    	for (const line of bingoCardArray) {
    		// on blank line, reset accumulated line and send for parsing
    		if (line.trim().length === 0) {
    			splitArray.push(parseBingoCard(currentBingoCardArray.join('\n')));
    			currentBingoCardArray = [];
    		} else {
    			currentBingoCardArray.push(line);
    		}
    	}
    	// flushing the buffer, in case the last line is not newline-terminated
    	if (currentBingoCardArray.length != 0) {
    		splitArray.push(parseBingoCard(currentBingoCardArray.join('\n')));
    	}
    	return splitArray;
    }
    
    function findBingo(bingoCard, numbersCalled) {
    	// look for horizontal bingos
    	for (const row of bingoCard) {
    		let horizontalBingo = true;
    		for (const number of row) {
    			if (!numbersCalled.includes(parseInt(number))) {
    				horizontalBingo = false;
    				break;
    			}
    		}
    		if (horizontalBingo === true) {
    			return true;
    		}
    	}
    	// look for vertical bingos
    	for (let colIndex = 0; colIndex < bingoCard[0].length; colIndex++) {
    		let verticalBingo = true;
    		for (const row of bingoCard) {
    			if (!numbersCalled.includes(parseInt(row[colIndex]))) {
    				verticalBingo = false;
    				break;
    			}
    		}
    		if (verticalBingo === true) {
    			return true;
    		}
    	}
    	return false;
    }
    
    function findBingoScore(bingoCard, numbersCalled) {
    	let pointSpaces = [];
    	for (const row of bingoCard) {
    		for (const num of row) {
    			if (!numbersCalled.includes(parseInt(num))) {
    				pointSpaces.push(parseInt(num));
    			}
    		}
    	}
    	return (pointSpaces.reduce((a,b) => a+b) * numbersCalled[numbersCalled.length-1]);
    }
    
    (async function mainExecution() {
    	await openFileForReading('input.txt');
    	let numbersToCall = inputArr[0].split(',').map(e => parseInt(e));
    	console.log("DEBUG: numbersToCall = " + numbersToCall);
    	let bingoCardArray = splitBingoCards();
    	let numberCalledIndex = 0;
    	let numbersCalled = [];
    	let winningBoards = [];
    	while (winningBoards.length < bingoCardArray.length) {
    		// call new number
    		numberCalledIndex++;
    		numbersCalled = numbersToCall.slice(0,numberCalledIndex);
    
    		// check for wins
    		for (let i=0; i<bingoCardArray.length; i++) {
    			if (!winningBoards.includes(i)) {
    				if (findBingo(bingoCardArray[i], numbersCalled)) {
    					winningBoards.push(i);
    				}
    			}
    		}
    	}
    	console.log("DEBUG: last winningBoard =\n" + bingoCardArray[winningBoards[winningBoards.length-1]].join('\n'));
    	console.log("DEBUG: numbersCalled = " + numbersCalled);
    	console.log("Answer found! " + findBingoScore(bingoCardArray[winningBoards[winningBoards.length-1]],numbersCalled));
    })();
    
    3 votes
  18. Comment on Day 3: Binary Diagnostic in ~comp.advent_of_code

    3d12
    Link
    Haha, this one absolutely killed me. While I defeated my own purpose here in my haste to get caught up on the problems I was behind on, I did manage to get a functional solution regardless of its...

    Haha, this one absolutely killed me. While I defeated my own purpose here in my haste to get caught up on the problems I was behind on, I did manage to get a functional solution regardless of its readability. I've already promised myself no more of this sloppy type of implementation, since my goal here is to get familiar with the more convenient parts of Node/JS and not just implement everything with indices and for loops. :)

    Part 1
    const fs = require('fs');
    const readline = require('readline');
    
    let binaryInputArr = [];
    
    async function openFileForReading(file) {
    	const fileStream = fs.createReadStream(file);
    
    	const rl = readline.createInterface({
    		input: fileStream,
    		crlfDelay: Infinity
    	});
    
    	for await (const line of rl) {
    		try {
    			//directionArr.push(parseInt(line));
    			binaryInputArr.push(line);
    		} catch(e) {
    			console.error(e);
    		}
    	}
    }
    
    (async function mainExecution() {
    	await openFileForReading('input.txt');
    	let positionalCounts = [];
    	const lengthCheckString = binaryInputArr[0];
    	for (let i=0; i<lengthCheckString.length; i++) {
    		positionalCounts.push({ zeroes: 0, ones: 0 });
    	}
    	for (const binaryInput of binaryInputArr) {
    		for (let i=0; i<binaryInput.length; i++) {
    			if (binaryInput[i] === '0') {
    				positionalCounts[i].zeroes++;
    			} else if (binaryInput[i] === '1') {
    				positionalCounts[i].ones++;
    			}
    		}
    	}
    	let gammaRate = [];
    	let epsilonRate = [];
    	for (let i=0; i<positionalCounts.length; i++) {
    		if (positionalCounts[i].zeroes > positionalCounts[i].ones) {
    			gammaRate.push('0');
    			epsilonRate.push('1');
    		} else if (positionalCounts[i].ones > positionalCounts[i].zeroes) {
    			gammaRate.push('1');
    			epsilonRate.push('0');
    		}
    	}
    	let gammaRateString = gammaRate.join('');
    	let gammaRateInt = parseInt(gammaRateString, 2);
    	let epsilonRateString = epsilonRate.join('');
    	let epsilonRateInt = parseInt(epsilonRateString, 2);
    	console.log("Answer found! " + (gammaRateInt * epsilonRateInt));
    })();
    
    Part 2
    const fs = require('fs');
    const readline = require('readline');
    
    let binaryInputArr = [];
    
    async function openFileForReading(file) {
    	const fileStream = fs.createReadStream(file);
    
    	const rl = readline.createInterface({
    		input: fileStream,
    		crlfDelay: Infinity
    	});
    
    	for await (const line of rl) {
    		try {
    			//directionArr.push(parseInt(line));
    			binaryInputArr.push(line);
    		} catch(e) {
    			console.error(e);
    		}
    	}
    }
    
    (async function mainExecution() {
    	await openFileForReading('input.txt');
    	let oxygenGenRating = '';
    	let filteredArray = binaryInputArr;
    	let positionalCounts = [];
    	let binaryInputIndex = 0;
    	while (oxygenGenRating === '') {
    		if (filteredArray.length === 1) {
    			oxygenGenRating = filteredArray[0];
    			break;
    		}
    		const lengthCheckString = filteredArray[0];
    		positionalCounts = [];
    		for (let i=0; i<lengthCheckString.length; i++) {
    			positionalCounts.push({ zeroes: 0, ones: 0 });
    		}
    		for (let i=0; i<filteredArray.length; i++) {
    			let currentString = filteredArray[i];
    			for (let j=0; j<positionalCounts.length; j++) {
    				if (currentString[j] === '0') {
    					positionalCounts[j].zeroes++;
    				} else if (currentString[j] === '1') {
    					positionalCounts[j].ones++;
    				}
    			}
    		}
    		let filterChoice = '';
    		if (positionalCounts[binaryInputIndex].zeroes > positionalCounts[binaryInputIndex].ones) {
    			filterChoice = '0';
    		} else if (positionalCounts[binaryInputIndex].ones >= positionalCounts[binaryInputIndex].zeroes) {
    			filterChoice = '1';
    		}
    		filteredArray = filteredArray.filter(binaryNumber => binaryNumber[binaryInputIndex] === filterChoice);
    		binaryInputIndex++;
    	}
    	let co2ScrubRating = '';
    	let filteredArray2 = binaryInputArr;
    	positionalCounts = [];
    	binaryInputIndex = 0;
    	while (co2ScrubRating === '') {
    		if (filteredArray2.length === 1) {
    			co2ScrubRating = filteredArray2[0];
    			break;
    		}
    		const lengthCheckString = filteredArray2[0];
    		positionalCounts = [];
    		for (let i=0; i<lengthCheckString.length; i++) {
    			positionalCounts.push({ zeroes: 0, ones: 0 });
    		}
    		for (let i=0; i<filteredArray2.length; i++) {
    			let currentString = filteredArray2[i];
    			for (let j=0; j<positionalCounts.length; j++) {
    				if (currentString[j] === '0') {
    					positionalCounts[j].zeroes++;
    				} else if (currentString[j] === '1') {
    					positionalCounts[j].ones++;
    				}
    			}
    		}
    		let filterChoice = '';
    		if (positionalCounts[binaryInputIndex].zeroes <= positionalCounts[binaryInputIndex].ones) {
    			filterChoice = '0';
    		} else if (positionalCounts[binaryInputIndex].ones < positionalCounts[binaryInputIndex].zeroes) {
    			filterChoice = '1';
    		}
    		filteredArray2 = filteredArray2.filter(binaryNumber => binaryNumber[binaryInputIndex] === filterChoice);
    		binaryInputIndex++;
    	}
    	let oxygenGenRatingDecimal = parseInt(oxygenGenRating,2);
    	let co2ScrubRatingDecimal = parseInt(co2ScrubRating,2);
    	console.log("Answer found! \nOxygen Generator Rating: " + oxygenGenRatingDecimal
    		+ "\nCO2 Scrubber Rating: " + co2ScrubRatingDecimal
    		+ "\n" + oxygenGenRatingDecimal + " * " + co2ScrubRatingDecimal + " = " + (oxygenGenRatingDecimal * co2ScrubRatingDecimal));
    })();
    
    2 votes
  19. Comment on Day 2: Dive! in ~comp.advent_of_code

    3d12
    Link
    I agree with everyone else, this one felt a little easy. Still, no compaints, I'm sure it will get more difficult quite quickly! Part 1 const fs = require('fs'); const readline =...

    I agree with everyone else, this one felt a little easy. Still, no compaints, I'm sure it will get more difficult quite quickly!

    Part 1
    const fs = require('fs');
    const readline = require('readline');
    
    let directionArr = [];
    
    async function openFileForReading(file) {
    	const fileStream = fs.createReadStream(file);
    
    	const rl = readline.createInterface({
    		input: fileStream,
    		crlfDelay: Infinity
    	});
    
    	for await (const line of rl) {
    		try {
    			//directionArr.push(parseInt(line));
    			directionArr.push(line);
    		} catch(e) {
    			console.error(e);
    		}
    	}
    }
    
    function interpretDirection(inputDirection) {
    	let hmodifier = 0;
    	let vmodifier = 0;
    	const regex = /(\w+) (\d+)/;
    	const found = inputDirection.match(regex);
    	const direction = found[1];
    	const distance = parseInt(found[2]);
    	switch (direction) {
    		case 'forward': hmodifier += distance;
    			break;
    		case 'down': vmodifier += distance;
    			break;
    		case 'up': vmodifier -= distance
    			break;
    	}
    	return { hmodifier: hmodifier, vmodifier: vmodifier };
    }
    
    (async function mainExecution() {
    	await openFileForReading('input.txt');
    	let hposition = 0;
    	let vposition = 0;
    	for (const direction of directionArr) {
    		let outcome = interpretDirection(direction);
    		console.log("hmodifier: " + outcome.hmodifier + ", vmodifier: " + outcome.vmodifier)
    		hposition += outcome.hmodifier;
    		if (vposition + outcome.vmodifier < 0) {
    			vposition = 0;
    		} else {
    			vposition += outcome.vmodifier;
    		}
    		console.log("Current position: " + hposition + "," + vposition);
    	}
    	console.log("Answer found! " + (hposition * vposition));
    })();
    
    Part 2
    const fs = require('fs');
    const readline = require('readline');
    
    let directionArr = [];
    
    async function openFileForReading(file) {
    	const fileStream = fs.createReadStream(file);
    
    	const rl = readline.createInterface({
    		input: fileStream,
    		crlfDelay: Infinity
    	});
    
    	for await (const line of rl) {
    		try {
    			//directionArr.push(parseInt(line));
    			directionArr.push(line);
    		} catch(e) {
    			console.error(e);
    		}
    	}
    }
    
    function interpretDirection(inputDirection) {
    	let command = 'null';
    	let value = 0;
    	const regex = /(\w+) (\d+)/;
    	const found = inputDirection.match(regex);
    	command = found[1];
    	value = parseInt(found[2]);
    	return { command: command, value: value };
    }
    
    (async function mainExecution() {
    	await openFileForReading('input.txt');
    	let hposition = 0;
    	let vposition = 0;
    	let aim = 0;
    	for (const direction of directionArr) {
    		let outcome = interpretDirection(direction);
    		console.log("command: " + outcome.command + ", value: " + outcome.value)
    		switch (outcome.command) {
    			case 'up': if (aim - outcome.value < 0) {
    					aim = 0;
    				} else {
    					aim -= outcome.value;
    				}
    				break;
    			case 'down': aim += outcome.value;
    				break;
    			case 'forward': hposition += outcome.value;
    				vposition += (aim * outcome.value);
    				break;
    		}
    	}
    	console.log("Answer found! " + (hposition * vposition));
    })();
    
    1 vote
  20. Comment on Day 1: Sonar Sweep in ~comp.advent_of_code

    3d12
    Link
    Late entry, just catching up this weekend! I'll be doing this in Javascript (Node) this year again, since I'm getting better at using the language, and would like to potentially start using it...

    Late entry, just catching up this weekend! I'll be doing this in Javascript (Node) this year again, since I'm getting better at using the language, and would like to potentially start using it professionally in 2022.

    Repo is here

    Part 1
    const fs = require('fs');
    const readline = require('readline');
    
    let depthArr = [];
    
    async function openFileForReading(file) {
    	const fileStream = fs.createReadStream(file);
    
    	const rl = readline.createInterface({
    		input: fileStream,
    		crlfDelay: Infinity
    	});
    
    	for await (const line of rl) {
    		try {
    			depthArr.push(parseInt(line));
    		} catch(e) {
    			console.error(e);
    		}
    	}
    }
    
    (async function mainExecution() {
    	await openFileForReading('input.txt');
    	let currentDepth = 0;
    	let firstDepth = true;
    	let numIncreases = 0;
    	for (const depth of depthArr) {
    		if (firstDepth != true) {
    			diff = depth - currentDepth;
    			if (diff > 0) {
    				console.log("Depth increased from " + currentDepth + " to " + depth);
    				numIncreases++;
    			}
    		}
    		currentDepth = depth;
    		firstDepth = false;
    	}
    	console.log("Answer found! " + numIncreases);
    })();
    
    Part 2
    const fs = require('fs');
    const readline = require('readline');
    
    let depthArr = [];
    
    async function openFileForReading(file) {
    	const fileStream = fs.createReadStream(file);
    
    	const rl = readline.createInterface({
    		input: fileStream,
    		crlfDelay: Infinity
    	});
    
    	for await (const line of rl) {
    		try {
    			depthArr.push(parseInt(line));
    		} catch(e) {
    			console.error(e);
    		}
    	}
    }
    
    (async function mainExecution() {
    	await openFileForReading('input.txt');
    	let currentDepth = 0;
    	let currentWindowIndex = 0;
    	let firstDepth = true;
    	let numIncreases = 0;
    	for (let currentWindowIndex = 0; currentWindowIndex < depthArr.length-2; currentWindowIndex++) {
    		if (firstDepth != true) {
    			depthSum = depthArr[currentWindowIndex] + depthArr[currentWindowIndex+1] + depthArr[currentWindowIndex+2];
    			diff = depthSum - currentDepth;
    			if (diff > 0) {
    				console.log("Depth increased from " + currentDepth + " to " + depthSum);
    				numIncreases++;
    			}
    		}
    		currentDepth = depthArr[currentWindowIndex] + depthArr[currentWindowIndex+1] + depthArr[currentWindowIndex+2];
    		firstDepth = false;
    	}
    	console.log("Answer found! " + numIncreases);
    })();
    
    3 votes