| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150 |
- using System.Text.RegularExpressions;
- namespace Day19;
- public partial class Rule
- {
- [GeneratedRegex(@"(\w)([<>])(\d+):(\w+)|(\w+)")]
- private partial Regex ItemMatch();
- private readonly IList<IRuleItem> _items;
- public Rule(string ruleText)
- {
- _items = ItemMatch().Matches(ruleText).Select<Match, IRuleItem>(m =>
- {
- if (m.Groups[5].Length > 0)
- {
- return new Terminal(m.Groups[5].Value);
- }
-
- return new Item(m.Groups[1].Value, m.Groups[2].Value, int.Parse(m.Groups[3].Value), m.Groups[4].Value);
- }).ToList();
- }
- public string Apply(Part p)
- {
- foreach (var item in _items)
- {
- //Console.WriteLine(item);
- var next = item.Apply(p);
- //Console.WriteLine($"=> {next}");
- if (next != null)
- {
- return next;
- }
- }
- throw new Exception("Rule should always match");
- }
-
- public IEnumerable<RuleResultRange> Apply(PartRange p)
- {
- var range = p;
- foreach (var item in _items)
- {
- var result = item.Apply(range).ToList();
- yield return result.First();
- if (result.Count > 1)
- {
- range = result.Last().Part;
- }
- }
- }
- private interface IRuleItem
- {
- string? Apply(Part p);
- IEnumerable<RuleResultRange> Apply(PartRange p);
- }
- private class Item : IRuleItem
- {
- private readonly string _property;
- private readonly string _op;
- private readonly int _value;
- private readonly string _next;
- public Item(string property, string op, int value, string next)
- {
- _property = property;
- _op = op;
- _value = value;
- _next = next;
- }
- public string? Apply(Part p)
- {
- if (_op == "<")
- {
- return p.Get(_property) < _value ? _next : null;
- }
- if (_op == ">")
- {
- return p.Get(_property) > _value ? _next : null;
- }
- return null;
- }
-
- public IEnumerable<RuleResultRange> Apply(PartRange p)
- {
- var range = p.Get(_property);
-
- if (_op == "<")
- {
- yield return new RuleResultRange(
- p.Update(_property, range.LessThan(_value)),
- _next
- );
- yield return new RuleResultRange(
- p.Update(_property, range.GreaterThan(_value - 1)),
- null
- );
- }
- if (_op == ">")
- {
- yield return new RuleResultRange(
- p.Update(_property, range.GreaterThan(_value)),
- _next
- );
- yield return new RuleResultRange(
- p.Update(_property, range.LessThan(_value + 1)),
- null
- );
- }
- }
- public override string ToString()
- {
- return $"{_property} {_op} {_value} : {_next}";
- }
- }
-
- private class Terminal : IRuleItem
- {
- private readonly string _next;
- public Terminal(string next)
- {
- _next = next;
- }
- public string? Apply(Part p)
- {
- return _next;
- }
- public IEnumerable<RuleResultRange> Apply(PartRange p)
- {
- yield return new RuleResultRange(p, _next);
- }
- public override string ToString()
- {
- return $"Terminal<{_next}>";
- }
- }
- }
|