-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path19.linq
144 lines (131 loc) · 3.93 KB
/
19.linq
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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
<Query Kind="Program">
<RuntimeVersion>5.0</RuntimeVersion>
</Query>
#load ".\shared"
public static Dictionary<int, Rule> Rules;
void Main()
{
var inputStrings = Utils.ParseStrings("19.txt", true);
var ruleStrings = inputStrings.Where(s => char.IsDigit(s[0])).ToList();
var messages = inputStrings.Where(s => !char.IsDigit(s[0])).ToList();
Rules = ParseRules(ruleStrings);
int p1 = messages.Where(m => TestString(m)).Count();
Rules[8] = new PointerRule
{
SubRules = new List<int[]>
{
new int[] { 42 },
new int[] { 42, 8 }
}
};
Rules[11] = new PointerRule
{
SubRules = new List<int[]>
{
new int[] { 42, 31 },
new int[] { 42, 11, 31 }
}
};
int p2 = messages.Where(m => TestString(m)).Count();
$"P1: {p1}".Dump();
$"P2: {p2}".Dump();
}
public bool TestString(string s)
{
Stack<(int StringIndex, List<int[]> Stack)> stack = new();
List<int[]> prevStack = new List<int[]>();
prevStack.Add(new int[] { 0 });
stack.Push((0, prevStack));
while (stack.Count > 0)
{
var check = stack.Pop();
var currentRules = check.Stack.Last();
check.Stack = check.Stack.GetRange(0, check.Stack.Count - 1);
var ruleId = currentRules.First();
var nextRules = currentRules[1..];
var rule = Rules[currentRules.First()];
if (rule is LetterRule)
{
if (check.StringIndex >= s.Length || s[check.StringIndex] != ((LetterRule)rule).C) continue;
int newIndex = check.StringIndex+1;
while (nextRules.Length == 0)
{
if (check.Stack.Count == 0)
{
if (newIndex == s.Length) return true;
break;
}
currentRules = check.Stack.Last();
check.Stack = check.Stack.GetRange(0, check.Stack.Count - 1);
nextRules = currentRules;
}
if (check.Stack.Count > 0)
{
var next = new List<int[]>(check.Stack);
if (nextRules.Length > 0)
{
next.Add(nextRules);
stack.Push((newIndex, next));
}
}
}
else
{
var pointerRule = (PointerRule)rule;
foreach (var sr in pointerRule.SubRules)
{
var newStack = new List<int[]>(check.Stack);
newStack.Add(nextRules);
newStack.Add(sr);
stack.Push((check.StringIndex, newStack));
}
}
}
return false;
}
public Dictionary<int, Rule> ParseRules(List<string> ruleStrings)
{
Dictionary<int, Rule> rules = new();
foreach (var s in ruleStrings)
{
var split = s.Split(new[] { ": ", " " }, StringSplitOptions.RemoveEmptyEntries);
var ruleId = int.Parse(split[0]);
int secondRuleId = 0;
bool isInt = int.TryParse(split[1], out secondRuleId);
if (!isInt)
{
rules.Add(ruleId, new LetterRule { C = split[1][1] });
}
else
{
List<int[]> subRules = new();
List<int> currentRules = new();
for (int i = 1; i < split.Length; i++)
{
if (split[i] == "|")
{
subRules.Add(currentRules.ToArray());
currentRules = new();
}
else
{
currentRules.Add(int.Parse(split[i]));
}
}
subRules.Add(currentRules.ToArray());
rules.Add(ruleId, new PointerRule { SubRules = subRules });
}
}
return rules;
}
public class LetterRule : Rule
{
public char C { get; init; }
}
public class PointerRule : Rule
{
public List<int[]> SubRules { get; init; }
}
public abstract class Rule
{
}