AdventOfCode/AdventOfCode.Solutions/2023/Day 12/Day12.cs
2023-12-15 17:24:50 +01:00

162 lines
6.1 KiB
C#

using AdventOfCode.Core;
using System.Linq;
using System.Text.RegularExpressions;
namespace AdventOfCode.Solutions._2023
{
public partial class Day12(InputReader reader) : IChallange
{
private InputReader _inputReader = reader;
public async Task<string> GetSolutionPart1()
{
long total = 0;
await foreach(string line in _inputReader.ReadAsStringLine())
{
string[] splitted = line.Split(' ');
int[] groups = splitted[1].Split(',').Select(int.Parse).ToArray();
Console.Write(splitted[0]);
long possiblies = Possibilities2(splitted[0], groups, 0, 0);
Console.WriteLine($": {possiblies}");
total += possiblies;
//total += Possibilities(splitted[0], groups);
}
return total.ToString();
}
public async Task<string> GetSolutionPart2()
{
long total = 0;
await foreach (string line in _inputReader.ReadAsStringLine())
{
string[] splitted = line.Split(' ');
var joinedLine = string.Join("?", new[] { splitted[0], splitted[0], splitted[0], splitted[0], splitted[0] });
int[] groups = splitted[1].Split(',').Select(int.Parse).ToArray();
int[] groupsTotal = groups.Concat(groups).Concat(groups).Concat(groups).Concat(groups).ToArray();
//total += Possibilities(splitted[0], groups);
Console.Write(joinedLine + " " + string.Join(",", new[] { splitted[1], splitted[1], splitted[1], splitted[1], splitted[1] }));
long possiblies = Possibilities2(joinedLine, groupsTotal, 0, 0);
Console.WriteLine($": {possiblies}");
total += possiblies;
}
return total.ToString();
}
private long Possibilities(string lineToValidate, int[] groups)
{
long total = 0;
if (lineToValidate.Contains('?'))
{
var regex = new Regex(Regex.Escape("?"));
total += Possibilities(regex.Replace(lineToValidate, ".", 1), groups);
total += Possibilities(regex.Replace(lineToValidate, "#", 1), groups);
return total;
}
MatchCollection matches = GroupMatch().Matches(lineToValidate);
if (matches.Count == groups.Length &&
groups.Where((g, i) => matches[i].Length == g).Count() == groups.Length)
{
//Console.WriteLine($"{lineToValidate} is valid");
return 1;
}
else
return 0;
}
private long Possibilities2(string lineToValidate, int[] groups, int readIndex, int captureSize)
{
// if group index is 0 there are no captures and not captures running
if (readIndex < lineToValidate.Length)
{
int[] splitGroups = lineToValidate[..readIndex].Split('.', StringSplitOptions.RemoveEmptyEntries).Select(s => s.Length).ToArray();
if (groups.Length < splitGroups.Length)
{
// we have more groups than expected
return 0;
}
if (lineToValidate.Length - readIndex < groups.Skip(splitGroups.Length).Sum() + groups.Length - splitGroups.Length - 1)
{
// there is not enough space to even fit the groups so reject
return 0;
}
// validate everything, including fixed groups
for (int i = 0; i < splitGroups.Length - 1; i++)
{
// all except the last must match
if (splitGroups[i] != groups[i])
{
return 0; // group lengths do not match, reject
}
}
// the last one is allowed to be smaller than the expected groups size
if (splitGroups.Any() && splitGroups[^1] > groups[splitGroups.Length - 1])
{
// if the last group is larger than allowed the line is invalid
return 0;
}
}
if (!lineToValidate.Contains('?')) // no more variations
{
int[] splitGroups = lineToValidate.Split('.', StringSplitOptions.RemoveEmptyEntries).Select(s => s.Length).ToArray();
if (splitGroups.Length != groups.Length)
{
// group amount does not match
return 0;
}
for (int i = 0; i < groups.Length; i++)
{
if (splitGroups[i] != groups[i])
{
return 0; // group lengths do not match, reject
}
}
// valid combos so valid
return 1;
}
long total = 0;
//go search for # or ?
for (int charIndex = readIndex; charIndex < lineToValidate.Length; charIndex++)
{
if (lineToValidate[charIndex] == '.')
{
captureSize = 0;
readIndex++;
continue;
}
if (lineToValidate[charIndex] == '#')
{
captureSize++;
readIndex++;
continue;
}
if (lineToValidate[charIndex] == '?')
{
var regex = new Regex(Regex.Escape("?"));
total += Possibilities2(regex.Replace(lineToValidate, "#", 1), groups, readIndex + 1, captureSize + 1);
total += Possibilities2(regex.Replace(lineToValidate, ".", 1), groups, readIndex + 1, captureSize);
return total;
}
}
return Possibilities2(lineToValidate, groups, readIndex + 1, captureSize);
}
[GeneratedRegex("#+")]
private static partial Regex GroupMatch();
}
}