-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDay04.cs
89 lines (76 loc) · 3.52 KB
/
Day04.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
using LanguageExt;
using MoreLinq;
using System.Reflection;
using WinstonPuckett.PipeExtensions;
public static class Day04
{
static async Task<List<string>> GetInput() =>
await Inputs
.Read(MethodBase.GetCurrentMethod()?.DeclaringType?.FullName?.Split("+").First() ?? "")
.Select(text => text)
.ToListAsync();
static (int[] Numbers, int[][][] Boards) GetGame(List<string> input) => (
input[0].Split(",").Select(x => int.Parse(x)).ToArray(),
input
.Skip(2)
.Batch(6)
.Select(board =>
board
.Take(5)
.Select(boardRow =>
boardRow
.Split(" ")
.Where(s => !string.IsNullOrWhiteSpace(s))
.Select(x => int.Parse(x))
.ToArray()).ToArray()).ToArray());
static int[][] Flip(int[][] board) =>
Enumerable.Range(0, board.First().Count())
.Select(i => board.Select(o => o[i]).ToArray()).ToArray();
static IEnumerable<IEnumerable<int>> GetDrawnNumbersRecur(IEnumerable<int> numbers, IEnumerable<IEnumerable<int>> sequence) =>
numbers.Any() ?
numbers
.Pipe(n => (remaining: n.Skip(1), toAdd: numbers.Take(1)))
.Pipe((remaining, toAdd) =>
(
remaining,
MoreEnumerable.Append(sequence, (sequence.LastOrDefault() ?? Array.Empty<int>()).Append(toAdd))
))
.Pipe((remaining, sequence) => GetDrawnNumbersRecur(remaining, sequence))
:
sequence;
static bool IsWinner(int[][] board, IEnumerable<int> drawnNumbers) =>
board.Any(row => row.All(n => drawnNumbers.Contains(n)));
static int GetUnmarkedNumbersSum(int[][] board, IEnumerable<int> drawnNumbers) =>
board.SelectMany(b => b.Where(n => !drawnNumbers.Contains(n))).Sum();
static Option<int> MaybeComputeScore(int[][] board, IEnumerable<int> drawnNumbers) =>
IsWinner(board, drawnNumbers) ? drawnNumbers.Last() * GetUnmarkedNumbersSum(board, drawnNumbers) : Option<int>.None;
static Option<int> MaybeGetScore(int[][] board, IEnumerable<int> drawnNumbers) =>
MaybeComputeScore(board, drawnNumbers)
.Match(
scoreForBoardIfAnyRowIsWinner => scoreForBoardIfAnyRowIsWinner,
() => MaybeComputeScore(Flip(board), drawnNumbers)
.Match(
scoreForBoardIfAnyColumnIsWinner => scoreForBoardIfAnyColumnIsWinner,
() => Option<int>.None)); //NOT A WINNER!
static IEnumerable<int[][]> GetRemainingBoards(IEnumerable<int[][]> boards, IEnumerable<(int[][] board, int score)> winners) =>
boards.Where(b => !winners.Any(w => w.board == b));
static List<(int[][] board, int score)> GetWinners(int[] numbers, int[][][] boards)
{
var winners = new List<(int[][] board, int score)>();
foreach (var drawnNumbers in GetDrawnNumbersRecur(numbers, Array.Empty<int[]>()))
{
foreach (var board in GetRemainingBoards(boards, winners))
{
var score = MaybeGetScore(board, drawnNumbers);
score.IfSome(s => { winners.Add((board, s)); });
}
}
return winners;
}
static async Task<List<(int[][] board, int score)>> GetWinners() =>
(await GetInput())
.Pipe(GetGame)
.Pipe((n, b) => GetWinners(n, b));
public static async Task<object> One() => (await GetWinners()).First().score;
public static async Task<object> Two() => (await GetWinners()).Last().score;
}