AdventOfCode/AdventOfCode.Solutions/2023/Day 07/Day07.cs
2023-12-08 15:41:10 +01:00

122 lines
4.4 KiB
C#

using AdventOfCode.Core;
namespace AdventOfCode.Solutions._2023
{
public class Day07(InputReader reader) : IChallange
{
private readonly InputReader _inputReader = reader;
private static readonly List<char> CardValues = ['1', '2', '3', '4', '5', '6', '7', '8', '9', 'T', 'J', 'Q', 'K', 'A'];
private static readonly List<char> CardValuesJoker = ['J', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'T', 'Q', 'K', 'A'];
private enum SetRanks { High, OnePair, TwoPair, ThreeKind, FullHouse, FourKind, FiveKind }
public async Task<string> GetSolutionPart1()
{
return (await _inputReader.ReadAsArrayString())
.Select(l => new Hand(l))
.Order()
.Select((h, i) => h.Bid * (i + 1))
.Sum()
.ToString();
}
public async Task<string> GetSolutionPart2()
{
return (await _inputReader.ReadAsArrayString())
.Select(l => new Hand(l, true))
.Order()
.Select((h, i) => h.Bid * (i + 1))
.Sum()
.ToString();
}
private record Hand : IComparable<Hand>
{
public int Bid { get; set; }
public SetRanks Rank { get; set; }
public string Source { get; set; }
public string JokerSource { get; set; } = string.Empty;
public List<char> CharCompairList => string.IsNullOrEmpty(JokerSource) ? CardValues : CardValuesJoker;
public Hand(string line, bool jokerMode = false)
{
string[] splitted = line.Split(' ');
Source = splitted[0];
Bid = int.Parse(splitted[1]);
string finalTestLine = Source;
if (jokerMode)
{
JokerSource = Source;
if (finalTestLine.Contains('J') && finalTestLine.Any(c => c != 'J'))
{
// fun time
char toReplace = finalTestLine.Where(c => c != 'J').GroupBy(c => c).OrderByDescending(g => g.Count()).First().Key;
finalTestLine = finalTestLine.Replace('J', toReplace);
JokerSource = finalTestLine;
}
}
var grouped = finalTestLine.GroupBy(c => c).OrderByDescending(g => g.Count());
switch(grouped.Count())
{
case 1:
Rank = SetRanks.FiveKind;
break;
case 4:
Rank = SetRanks.OnePair;
break;
case 5:
Rank = SetRanks.High;
break;
case 3:
if (grouped.Skip(1).First().Count() == 2)
Rank = SetRanks.TwoPair;
else
Rank = SetRanks.ThreeKind;
break;
case 2:
if (grouped.First().Count() == 4)
Rank = SetRanks.FourKind;
else
Rank = SetRanks.FullHouse;
break;
}
}
public override string ToString()
{
return $"{JokerSource} [{Source}] {Rank} {Bid}";
}
public int CompareTo(Hand? other)
{
if (other == null)
return 1;
if (this.Rank == other.Rank && this.Source == other.Source)
return 0;
if (this.Rank > other.Rank)
return 1;
if (this.Rank < other.Rank)
return -1;
for (int i = 0; i < Source.Length; i++)
{
if (this.Source[i] == other.Source[i])
continue;
if (CharCompairList.IndexOf(this.Source[i]) > CharCompairList.IndexOf(other.Source[i]))
return 1;
if (CharCompairList.IndexOf(this.Source[i]) < CharCompairList.IndexOf(other.Source[i]))
return -1;
}
return 0;
}
}
}
}