## DEV Community is a community of 756,027 amazing developers

We're a place where coders share, stay up-to-date and grow their careers.

# Discussion on: Advent of Code 2020 Solution Megathread - Day 12: Rain Risk

Mike Gasparelli

Warning, lots of code today! I've been making an effort to model my solutions in ways that do not require special branching, or separate solutions for the 2 parts. Today was a fun one, and I think I came up with a good design, even if it's a little verbose!

At this point I think my enterprise development roots are showing. I've got inheritance, interfaces, strategies, factories, and even a DI container in my overall 2020 codebase 🤣

### Part1

``````    public class Part1 : Puzzle<IEnumerable<NavInstruction>, int>
{
public override int SampleAnswer => 25;

public override IEnumerable<NavInstruction> ParseInput(string rawInput)
=> rawInput
.Split(Environment.NewLine)
.Where(line => line.Length > 0)
.Select(line =>
new NavInstruction(
Action: line[0],
Value: int.Parse(line[1..])
));

public override int Solve(IEnumerable<NavInstruction> input)
{
var origin = new Point(0, 0);
var ferry = new Ferry(origin);
ferry.Sail(input);
return ManhattanDistance(origin, ferry.Location);
}

protected static int ManhattanDistance(Point a, Point b)
=> Math.Abs(a.X - b.X) + Math.Abs(a.Y - b.Y);
}
``````

### Part 2

``````    public class Part2 : Part1
{
public override int SampleAnswer => 286;

public override int Solve(IEnumerable<NavInstruction> input)
{
var origin = new Point(0, 0);
var ferry = new WaypointFerry(origin, new Point(10, 1));
ferry.Sail(input);
return ManhattanDistance(origin, ferry.Location);
}
}
``````

### FerryBase

``````public abstract class FerryBase
{
public Point Location { get; protected set; }

public Direction Bearing { get; protected set; }

protected FerryBase(Point origin)
{
Location = origin;
Bearing = Direction.Right;
}

public void Sail(IEnumerable<NavInstruction> instructions)
{
foreach (NavInstruction instruction in instructions)
{
Move(instruction);
}
}

protected Direction GetDirection(NavInstruction instruction)
=> instruction.Action switch {
'N' => Direction.Up,
'S' => Direction.Down,
'E' => Direction.Right,
'W' => Direction.Left,
_ => Bearing
};

protected static Point Move(Point p, Direction direction, int value)
=> direction switch {
Direction.Up => new Point(p.X, p.Y + value),
Direction.Down => new Point(p.X, p.Y - value),
Direction.Left => new Point(p.X - value, p.Y),
Direction.Right => new Point(p.X + value, p.Y),
_ => p
};

protected void Rotate(char turnDirection, int angle)
{
for (int i = 0; i < angle / 90; i++)
{
Rotate(turnDirection);
}
}

protected abstract void Rotate(char turnDirection);

protected abstract void Move(NavInstruction instruction);
}
``````

### Ferry (Part1's Implementation)

``````public class Ferry : FerryBase
{
public Ferry(Point origin)
: base(origin)
{
}

protected override void Rotate(char turnDirection)
{
int iBearing = (int)Bearing;
Bearing = turnDirection switch {
'L' => (Direction)((iBearing + 3) % 4),
'R' => (Direction)((iBearing + 1) % 4),
_ => Bearing
};
}

protected override void Move(NavInstruction instruction)
{
if (instruction.Action is 'L' or 'R')
{
Rotate(instruction.Action, instruction.Value);
return;
}

Move(GetDirection(instruction), instruction.Value);
}

void Move(Direction direction, int value)
=> Location = Move(Location, direction, value);
}
``````

### WaypointFerry (Part2's Implementation)

``````public class WaypointFerry : FerryBase
{
Point Waypoint = new Point(0, 0);

public WaypointFerry(Point origin, Point waypoint)
: base(origin)
{
Waypoint = waypoint;
}

protected override void Move(NavInstruction instruction)
{
if (instruction.Action is 'L' or 'R')
{
Rotate(instruction.Action, instruction.Value);
return;
}

if (instruction.Action is 'F')
{
for (int i = 0; i < instruction.Value; i++)
{
Location = new Point(Location.X + Waypoint.X, Location.Y + Waypoint.Y);
}

return;
}

Waypoint = Move(Waypoint, GetDirection(instruction), instruction.Value);
}

protected override void Rotate(char turnDirection)
=> Waypoint = turnDirection switch {
'L' => new Point(-1 * Waypoint.Y, Waypoint.X),
'R' => new Point(Waypoint.Y, -1 * Waypoint.X),
_ => throw new Exception(\$"turnDirection not supported: {turnDirection}")
};
}
``````