mirror of
https://github.com/jcreek/advent-of-code.git
synced 2026-07-13 03:03:46 +00:00
2019 Day 03 solution
This commit is contained in:
@@ -0,0 +1,197 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Day_03
|
||||
{
|
||||
class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
//Part1();
|
||||
Part2();
|
||||
}
|
||||
|
||||
public class WireTouchPoint
|
||||
{
|
||||
public int x { get; set; }
|
||||
public int y { get; set; }
|
||||
}
|
||||
|
||||
static List<WireTouchPoint> FindAllWireTouchPoints(List<string> wireCommands)
|
||||
{
|
||||
List<WireTouchPoint> touchPoints = new List<WireTouchPoint>(){};
|
||||
int currentX = 0;
|
||||
int currentY = 0;
|
||||
WireTouchPoint initialWTP = new WireTouchPoint();
|
||||
initialWTP.x = currentX;
|
||||
initialWTP.y = currentY;
|
||||
touchPoints.Add(initialWTP);
|
||||
|
||||
// For each command, record every co-ordinate the wire touches
|
||||
foreach(string wireCommand in wireCommands)
|
||||
{
|
||||
// Not bothering with error catching for converting strings to ints as the data cannot be wrongly typed in the input file
|
||||
int distance = System.Convert.ToInt32(wireCommand.Substring(1));
|
||||
|
||||
// Handle the different commands in the first letter of each command string
|
||||
switch (wireCommand[0])
|
||||
{
|
||||
case 'U':
|
||||
// Up
|
||||
for(int i = 0; i < distance; i++)
|
||||
{
|
||||
currentY += 1;
|
||||
|
||||
WireTouchPoint wtp = new WireTouchPoint();
|
||||
wtp.x = currentX;
|
||||
wtp.y = currentY;
|
||||
touchPoints.Add(wtp);
|
||||
}
|
||||
break;
|
||||
case 'D':
|
||||
// Down
|
||||
for(int i = 0; i < distance; i++)
|
||||
{
|
||||
currentY -= 1;
|
||||
|
||||
WireTouchPoint wtp = new WireTouchPoint();
|
||||
wtp.x = currentX;
|
||||
wtp.y = currentY;
|
||||
touchPoints.Add(wtp);
|
||||
}
|
||||
break;
|
||||
case 'L':
|
||||
// Left
|
||||
for(int i = 0; i < distance; i++)
|
||||
{
|
||||
currentX -= 1;
|
||||
|
||||
WireTouchPoint wtp = new WireTouchPoint();
|
||||
wtp.x = currentX;
|
||||
wtp.y = currentY;
|
||||
touchPoints.Add(wtp);
|
||||
}
|
||||
break;
|
||||
case 'R':
|
||||
// Right
|
||||
for(int i = 0; i < distance; i++)
|
||||
{
|
||||
currentX += 1;
|
||||
|
||||
WireTouchPoint wtp = new WireTouchPoint();
|
||||
wtp.x = currentX;
|
||||
wtp.y = currentY;
|
||||
touchPoints.Add(wtp);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return touchPoints;
|
||||
}
|
||||
|
||||
internal class WireTouchPointComparer : IEqualityComparer<WireTouchPoint>
|
||||
{
|
||||
public bool Equals(WireTouchPoint wtp1, WireTouchPoint wtp2)
|
||||
{
|
||||
if(wtp1.x == wtp2.x && wtp1.y == wtp2.y)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// public int GetHashCode(WireTouchPoint obj)
|
||||
// {
|
||||
// return obj.x.GetHashCode();
|
||||
// }
|
||||
|
||||
public int GetHashCode(WireTouchPoint obj)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
int hash = 17;
|
||||
hash = hash * 23 + obj.x.GetHashCode();
|
||||
hash = hash * 23 + obj.y.GetHashCode();
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void Part1()
|
||||
{
|
||||
// Each line is one wire's path trace
|
||||
var wire1 = File.ReadAllLines("input.txt")[0];
|
||||
var wire2 = File.ReadAllLines("input.txt")[1];
|
||||
|
||||
List<string> wire1Commands = wire1.Split(',').ToList();
|
||||
List<string> wire2Commands = wire2.Split(',').ToList();
|
||||
|
||||
// Find all points each wire touches
|
||||
List<WireTouchPoint> wire1TouchPoints = FindAllWireTouchPoints(wire1Commands);
|
||||
List<WireTouchPoint> wire2TouchPoints = FindAllWireTouchPoints(wire2Commands);
|
||||
|
||||
// Find all points where the two wires cross
|
||||
var crossingPoints = wire1TouchPoints.Intersect(wire2TouchPoints, new WireTouchPointComparer()).Where(cp => cp.x != 0 && cp.y != 0);
|
||||
|
||||
// Declare a large default shortest distance, probably should be setting as null and null-checking later but multitasking while writing this so cba
|
||||
int shortestManhattanDistance = 9999999;
|
||||
// For each crossing point, work out the Manhattan distance to the central port
|
||||
foreach(WireTouchPoint crossingPoint in crossingPoints)
|
||||
{
|
||||
// Convert co-ordinates to be positive numbers for calculating distance
|
||||
int xVal = crossingPoint.x > 0 ? crossingPoint.x : crossingPoint.x * -1;
|
||||
int yVal = crossingPoint.y > 0 ? crossingPoint.y : crossingPoint.y * -1;
|
||||
|
||||
int manhattanDistance = (xVal - 0) + (yVal - 0);
|
||||
// Work out if it is shorter than the previously found one
|
||||
if(manhattanDistance < shortestManhattanDistance)
|
||||
{
|
||||
shortestManhattanDistance = manhattanDistance;
|
||||
}
|
||||
}
|
||||
Console.WriteLine("Part 1: The Manhattan distance from the central port to the closest intersection is " + shortestManhattanDistance);
|
||||
}
|
||||
|
||||
static void Part2()
|
||||
{
|
||||
// Each line is one wire's path trace
|
||||
var wire1 = File.ReadAllLines("input.txt")[0];
|
||||
var wire2 = File.ReadAllLines("input.txt")[1];
|
||||
|
||||
List<string> wire1Commands = wire1.Split(',').ToList();
|
||||
List<string> wire2Commands = wire2.Split(',').ToList();
|
||||
|
||||
// Find all points each wire touches
|
||||
List<WireTouchPoint> wire1TouchPoints = FindAllWireTouchPoints(wire1Commands);
|
||||
List<WireTouchPoint> wire2TouchPoints = FindAllWireTouchPoints(wire2Commands);
|
||||
|
||||
// Find all points where the two wires cross
|
||||
var crossingPoints = wire1TouchPoints.Intersect(wire2TouchPoints, new WireTouchPointComparer()).Where(cp => cp.x != 0 && cp.y != 0);
|
||||
|
||||
// Declare a large default minimum steps, probably should be setting as null and null-checking later but multitasking while writing this so cba
|
||||
int minimumSteps = 9999999;
|
||||
foreach(WireTouchPoint crossingPoint in crossingPoints)
|
||||
{
|
||||
// Calculate the number of steps each wire takes to reach each the intersection
|
||||
// If a wire visits a position on the grid multiple times, use the steps value from the first time it visits that position when calculating the total value of a specific intersection.
|
||||
// The number of steps a wire takes is the total number of grid squares the wire has entered to get to that location, including the intersection being considered.
|
||||
|
||||
// Calculate the minimum number of steps each wire takes to reach the crossing point (using the index rather than index + 1 as the lists are zero-indexed ordered by the route taken but we want to ignore the start co-ordinates) - this will always return the first (i.e. closest) index
|
||||
int steps1 = wire1TouchPoints.FindIndex(tp => tp.x == crossingPoint.x && tp.y == crossingPoint.y);
|
||||
int steps2 = wire2TouchPoints.FindIndex(tp => tp.x == crossingPoint.x && tp.y == crossingPoint.y);
|
||||
|
||||
int totalSteps = steps1 + steps2;
|
||||
// Work out if it is fewer steps than the previously found one
|
||||
if(totalSteps < minimumSteps)
|
||||
{
|
||||
minimumSteps = totalSteps;
|
||||
}
|
||||
}
|
||||
Console.WriteLine("Part 2: The fewest combined steps the wires must take to reach an intersection is " + minimumSteps);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user