using System.Collections.Immutable;
namespace _2021___Day_15
{
record Point(int x, int y);
class Program
{
static void Main()
{
string inp = File.ReadAllText(@"../../../../Input.in");
var map = inp.Split("\n");
var chitonMap = new Dictionary<Point, int>(
from y in Enumerable.Range(0, map.Length)
from x in Enumerable.Range(0, map[0].Length - 1)
select new KeyValuePair<Point, int>(new Point(x, y), map[y][x] - '0')
);
Console.WriteLine(FindPath(chitonMap));
Console.WriteLine(FindPath(MakeBig(chitonMap)));
}
static int FindPath(Dictionary<Point, int> map)
{
var topLeft = new Point(0, 0);
var bottomRight = new Point(map.Keys.MaxBy(p => p.x).x, map.Keys.MaxBy(p => p.y).y);
var q = new PriorityQueue<Point, int>();
var totalRiskMap = new Dictionary<Point, int>();
totalRiskMap[topLeft] = 0;
q.Enqueue(topLeft, 0);
while (true)
{
var p = q.Dequeue();
if (p == bottomRight)
{
break;
}
foreach (var n in Neighbors(p))
{
if (map.ContainsKey(n))
{
var totalRiskWhen = totalRiskMap[p] + map[n];
if (totalRiskWhen < totalRiskMap.GetValueOrDefault(n, int.MaxValue))
{
totalRiskMap[n] = totalRiskWhen;
q.Enqueue(n, totalRiskWhen);
}
}
}
}
return totalRiskMap[bottomRight];
}
static Dictionary<Point, int> MakeBig(Dictionary<Point, int> map)
{
var (ccol, crow) = (map.Keys.MaxBy(p => p.x).x + 1, map.Keys.MaxBy(p => p.y).y + 1);
var res = new Dictionary<Point, int>(
from y in Enumerable.Range(0, crow * 5)
from x in Enumerable.Range(0, ccol * 5)
let tileY = y % crow
let tileX = x % ccol
let tileRiskLevel = map[new Point(tileX, tileY)]
let tileDistance = (y / crow) + (x / ccol)
let riskLevel = (tileRiskLevel + tileDistance - 1) % 9 + 1
select new KeyValuePair<Point, int>(new Point(x, y), riskLevel)
);
return res;
}
static IEnumerable<Point> Neighbors(Point point) =>
new[] {
point with {y = point.y + 1},
point with {y = point.y - 1},
point with {x = point.x + 1},
point with {x = point.x - 1},
};
}
}