2022-10-27 15:42:05 +00:00
|
|
|
namespace AOC2020;
|
|
|
|
|
|
|
|
/// <summary>
|
2022-12-03 05:41:38 +00:00
|
|
|
/// Day 22: <a href="https://adventofcode.com/2020/day/22" />
|
2022-10-27 15:42:05 +00:00
|
|
|
/// </summary>
|
2023-09-20 18:38:58 +00:00
|
|
|
public sealed class Day22() : Day(2020, 22, "Crab Combat")
|
2022-10-27 15:42:05 +00:00
|
|
|
{
|
|
|
|
private readonly Queue<int> _deck1 = new();
|
|
|
|
private readonly Queue<int> _deck2 = new();
|
|
|
|
|
2022-12-08 19:40:40 +00:00
|
|
|
public override void ProcessInput()
|
2022-10-27 15:42:05 +00:00
|
|
|
{
|
|
|
|
Reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
private void Reset()
|
|
|
|
{
|
|
|
|
_deck1.Clear();
|
|
|
|
_deck2.Clear();
|
|
|
|
|
2022-10-27 16:55:01 +00:00
|
|
|
var player = 0;
|
2022-10-27 15:42:05 +00:00
|
|
|
foreach (var line in Input)
|
|
|
|
{
|
|
|
|
if (line == "") continue;
|
|
|
|
if (line.StartsWith("Player"))
|
|
|
|
{
|
|
|
|
player++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
(player == 1 ? _deck1 : _deck2).Enqueue(int.Parse(line));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private (Queue<int> deck1, Queue<int> deck2) Play(Queue<int> deck1, Queue<int> deck2, bool recursive = false)
|
|
|
|
{
|
|
|
|
var seen1 = new HashSet<string>();
|
|
|
|
var seen2 = new HashSet<string>();
|
|
|
|
|
2023-11-26 05:50:28 +00:00
|
|
|
while (deck1.Count != 0 && deck2.Count != 0)
|
2022-10-27 15:42:05 +00:00
|
|
|
{
|
|
|
|
if (recursive)
|
|
|
|
{
|
|
|
|
var deck1Hash = string.Join(',', deck1);
|
|
|
|
var deck2Hash = string.Join(',', deck2);
|
|
|
|
|
|
|
|
if (seen1.Contains(deck1Hash) || seen2.Contains(deck2Hash))
|
|
|
|
{
|
|
|
|
// player1 wins
|
2022-10-27 16:36:21 +00:00
|
|
|
return (deck1, new());
|
2022-10-27 15:42:05 +00:00
|
|
|
}
|
2022-10-27 16:55:01 +00:00
|
|
|
|
|
|
|
seen1.Add(deck1Hash);
|
|
|
|
seen2.Add(deck2Hash);
|
2022-10-27 15:42:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
var play1 = deck1.Dequeue();
|
|
|
|
var play2 = deck2.Dequeue();
|
|
|
|
int winner;
|
|
|
|
|
|
|
|
if (recursive && deck1.Count >= play1 && deck2.Count >= play2)
|
|
|
|
{
|
|
|
|
// play again
|
|
|
|
var (r1, r2) = Play(deck1.Take(play1), deck2.Take(play2), recursive);
|
|
|
|
winner = r1.Count > r2.Count ? 1 : 2;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
winner = play1 > play2 ? 1 : 2;
|
|
|
|
|
|
|
|
if (winner == 1)
|
|
|
|
{
|
|
|
|
deck1.Enqueue(play1);
|
|
|
|
deck1.Enqueue(play2);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
deck2.Enqueue(play2);
|
|
|
|
deck2.Enqueue(play1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return (deck1, deck2);
|
|
|
|
}
|
|
|
|
|
2022-12-08 19:40:40 +00:00
|
|
|
private (Queue<int> deck1, Queue<int> deck2) Play(IEnumerable<int> enumerable1, IEnumerable<int> enumerable2,
|
|
|
|
bool recursive) =>
|
2022-10-27 16:36:21 +00:00
|
|
|
Play(new(enumerable1), new(enumerable2), recursive);
|
2022-10-27 15:42:05 +00:00
|
|
|
|
2022-10-27 16:55:01 +00:00
|
|
|
private static int CalculateScore(IReadOnlyCollection<int> deck) =>
|
2022-10-27 15:42:05 +00:00
|
|
|
deck.Reverse().Zip(Enumerable.Range(1, deck.Count), (a, b) => a * b).Sum();
|
|
|
|
|
2022-12-04 05:39:07 +00:00
|
|
|
public override object Part1()
|
2022-10-27 15:42:05 +00:00
|
|
|
{
|
|
|
|
var (deck1, deck2) = Play(_deck1, _deck2);
|
2023-11-26 05:50:28 +00:00
|
|
|
return CalculateScore(deck1.Count == 0 ? deck2 : deck1);
|
2022-10-27 15:42:05 +00:00
|
|
|
}
|
|
|
|
|
2022-12-04 05:39:07 +00:00
|
|
|
public override object Part2()
|
2022-10-27 15:42:05 +00:00
|
|
|
{
|
|
|
|
Reset();
|
|
|
|
var (deck1, deck2) = Play(_deck1, _deck2, recursive: true);
|
2023-11-26 05:50:28 +00:00
|
|
|
return CalculateScore(deck1.Count == 0 ? deck2 : deck1);
|
2022-10-27 15:42:05 +00:00
|
|
|
}
|
|
|
|
}
|