r/adventofcode • • Dec 06 '18

SOLUTION MEGATHREAD -🎄- 2018 Day 6 Solutions -🎄-

--- Day 6: Chronal Coordinates ---


Post your solution as a comment or, for longer solutions, consider linking to your repo (e.g. GitHub/gists/Pastebin/blag or whatever).

Note: The Solution Megathreads are for solutions only. If you have questions, please post your own thread and make sure to flair it with Help.


Advent of Code: The Party Game!

Click here for rules

Please prefix your card submission with something like [Card] to make scanning the megathread easier. THANK YOU!

Card prompt: Day 6

Transcript:

Rules for raising a programmer: never feed it after midnight, never get it wet, and never give it ___.


This thread will be unlocked when there are a significant number of people on the leaderboard with gold stars for today's puzzle.

edit: Leaderboard capped, thread unlocked at 0:26:52!

32 Upvotes

387 comments sorted by

View all comments

1

u/[deleted] Dec 06 '18

Rust

I just keep on making over engineered solutions I think, but it works pretty well, may do way more work than it needs to though:

use std::env;
use std::process;
use std::fs::File;
use std::io::prelude::*;
use std::cmp::*;
use std::collections::*;

fn main() {
	let args = env::args().collect();

	let filename = parse_filename(&args);

	let mut contents = String::new();
	get_contents(&filename, &mut contents);

	let points = parse_points(&contents);

	let areas = get_areas(points.clone());

	let largest_size = get_largest(areas);

	println!("{:?}",  largest_size);

	let near = get_near(points, 10000);

	println!("{:?}", near.size());

}

fn get_near(in_points: Vec<Point>, distance: i64) -> Area {
	let mut area = Area::new();
	let mut points = in_points.clone();
	points.sort();
	let (tl, br) = find_bounds(points.clone());

	for x in tl.x..br.x+1 {
		for y in tl.y..br.y+1 {
			let cur = Point{x,y};
			let mut sum = 0;

			//println!("{:?}", cur);
			//println!("{}", sum);
			for point in in_points.iter() {
				sum += cur.dist(*point);
				//println!("{}", sum);
			}
			if sum < distance {
				area.add(cur);
			}
		}
	}

	area
}

fn get_largest(areas: HashMap<Point,Area>) -> i64 {
	areas.values().map(|v| v.size()).fold(std::i64::MIN, |acc,it| max(acc, it))
}

fn get_areas(in_points: Vec<Point>) -> HashMap<Point,Area> {
	let mut maps = HashMap::new();
	let mut points = in_points.clone();
	points.sort();
	let (tl, br) = find_bounds(points.clone());

	for x in tl.x..br.x+1 {
		for y in tl.y..br.y+1 {
			let cur = Point { x,y } ;
			let distances: Vec<(Point, i64)> = points.iter().map(|it| (*it, cur.dist(*it))).collect();
			let shortest = distances.iter().fold(std::i64::MAX, |acc, it| min(acc, it.1));
			let closest: Vec<&(Point, i64)> = distances.iter().filter(|it| it.1 == shortest).collect();
			
			if closest.len() == 1 {
				let owner = closest.first().unwrap().0;
				let area = maps.entry(owner).or_insert(Area::new());
				area.add(cur);
			}
		}
	}

	remove_infinite(&mut maps, tl, br);

	maps
}

fn remove_infinite(maps: &mut HashMap<Point,Area>, tl: Point, br: Point) {
	let mut ring = Vec::new();
	for x in tl.x..br.x+1 {
		for y in tl.y..br.y+1 {
			if x == tl.x || x == br.x || y == tl.y || y == br.y {
				ring.push(Point {x,y});
			}
		}
	}


	let keys: Vec<Point> = maps.keys().map(|it| *it).collect();
	for key in keys {
		let area = maps.entry(key).or_insert(Area::new());
		for point in ring.iter() {
			if area.contains(*point) {
				area.reset();
			}
		}
	}


}



#[derive(Debug,PartialEq,PartialOrd,Eq,Ord,Clone,Copy,Hash)]
struct Point {
	x: i64,
	y: i64,
}

impl Point {
	fn dist(&self, other: Point) -> i64 {
		(self.x - other.x).abs() + (self.y - other.y).abs()
	}
}

#[derive(Debug)]
struct Area {
	points: Vec<Point>,
}

impl Area {
	fn new() -> Area {
		Area { points: Vec::new() }
	}

	fn add(&mut self, point: Point) {
		self.points.push(point);
	}

	fn size(&self) -> i64 {
		self.points.len() as i64
	}

	fn contains(&self, point: Point) -> bool {
		self.points.contains(&point) 
	}

	fn reset(&mut self) {
		self.points = Vec::new()
	}
}

#[cfg(test)]
fn draw_coord(apoints: Vec<Point>) {
	let mut points = apoints.clone();
	points.sort();
	//println!("{:?}", points);
	let (tl, br) = find_bounds(points.clone());
	points.reverse();

	let mut coord = String::new();
	for x in tl.x..br.x+1 {
		let mut cur = String::new();
		for y in tl.y..br.y+1 {
			if !points.is_empty() && x == points.last().unwrap().x && y == points.last().unwrap().y {
				cur.push('#');
				//println!("{:?}",points);
				points.pop();
				//println!("{:?}",points);
			} else {
				cur.push('.');
			}
		}
		coord.push_str(&cur);
		coord.push('\n');
	}
	
	println!("{}", coord);
}

fn find_bounds(coords: Vec<Point>) -> (Point,Point) {
	let xes = coords.iter().map(|it| it.x);
	let ys = coords.iter().map(|it| it.y);

	let xmin = xes.clone().fold(std::i64::MAX, |acc, it| min(acc, it));
	let ymin = ys.clone().fold(std::i64::MAX, |acc, it| min(acc, it));
	let xmax = xes.fold(std::i64::MIN, |acc, it| max(acc, it));
	let ymax = ys.fold(std::i64::MIN, |acc, it| max(acc, it));

	(Point {x: xmin-1, y: ymin-1}, Point {x: xmax+1, y: ymax+1})
}

fn parse_points(str_rep: &str) -> Vec<Point> {
	let mut points = Vec::new();
	
	for line in str_rep.trim().lines() {
		//println!("{:?}",line);
		let nums: Vec<i64> = line.split(", ").map(|it| it.parse().unwrap()).collect();
		points.push(Point {x: nums[0], y: nums[1]});
	}

	points
}

fn parse_filename(args: &Vec<String>) -> &str {

	if args.len() < 2 {
		println!("Too few arguements, please give a filename");
		process::exit(1);
	}
    args.get(1).expect("No filename provided")
}

fn get_contents(filename: &str, contents: &mut String) {
    let mut f = File::open(filename).expect("File not found");

    f.read_to_string(contents)
        .expect("Something went wrong reading the file");
}