using Cryville.Common; using Cryville.Common.Collections.Generic; using Cryville.Common.Pdt; using Cryville.Crtr.Extension; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Text.RegularExpressions; namespace Cryville.Crtr.Ruleset { public class RulesetDefinition : MetaInfo { public const long CURRENT_FORMAT = 2; [JsonRequired] public long format; public string @base; [JsonIgnore] public PdtRuleset Root { get; private set; } public void LoadPdt(DirectoryInfo dir) { using StreamReader pdtreader = new(Path.Combine(dir.FullName, data + ".pdt"), Encoding.UTF8); var src = pdtreader.ReadToEnd(); Root = (PdtRuleset)new RulesetInterpreter(src, null).Interpret(typeof(PdtRuleset)); } } [Binder(typeof(PdtBinder))] public class PdtRuleset { public Dictionary configs; public Dictionary motions; public Dictionary inputs; public Dictionary areas; public Dictionary judges; public Dictionary scores; public Constraint constraints; public void Optimize(PdtEvaluatorBase etor) { foreach (var i in inputs) { var input = i.Value; if (input.pass != null) foreach (var e in input.pass) { etor.Optimize(e.Value); } } if (areas != null) foreach (var a in areas) { etor.Optimize(a.Value); } foreach (var j in judges) { var judge = j.Value; if (judge.hit != null) etor.Optimize(judge.hit); if (judge.on_hit != null) OptimizeJudgeActions(judge.on_hit, etor); if (judge.on_miss != null) OptimizeJudgeActions(judge.on_miss, etor); } foreach (var s in scores) { var score = s.Value; if (score.value != null) etor.Optimize(score.value); } constraints.Optimize(etor); } void OptimizeJudgeActions(PairList actions, PdtEvaluatorBase etor) { foreach (var a in actions) a.Key.Optimize(etor, a.Value); } public void PrePatch(Chart chart) { constraints.PrePatch(chart); } } public class ConfigDefinition { public string category; public ConfigType type; public PdtExpression @default; public PdtExpression range; public PdtExpression value; } public enum ConfigType { unknown, number, number_stepped, } public class MotionDefinition { // TODO } public class InputDefinition { public int dim; public string pdim; public bool notnull; public PairList pass; } public class JudgeDefinition { public int stack; public int prop; public PdtExpression clip; public PdtExpression input; public PdtExpression hit; public PdtExpression persist; public PairList on_hit; public PairList on_miss; #pragma warning disable IDE1006 public PairList scores { set { on_hit ??= new PairList(); int i = 0; foreach (var s in value) { on_hit.Insert(i++, new JudgeAction.Score(s.Key), s.Value); } } } public Identifier[] pass { set { on_hit ??= new PairList(); on_hit.Add(new JudgeAction.Pass(Enumerable.Empty(), value), PdtExpression.Empty); } } public Identifier[] miss { set { on_miss ??= new PairList(); on_miss.Add(new JudgeAction.Pass(Enumerable.Empty(), value), PdtExpression.Empty); } } #pragma warning restore IDE1006 } public class ScoreOperation { public Identifier name; public Identifier op; public ScoreOperation(Identifier name, Identifier op) { this.name = name; this.op = op; } public ScoreOperation(string str) { var m = Regex.Match(str, @"^(\S+)\s*?(\S+)?$"); name = new Identifier(m.Groups[1].Value); if (!m.Groups[2].Success) return; op = new Identifier(m.Groups[2].Value); } public override string ToString() { if (op == default) return name.ToString(); else return string.Format("{0} {1}", name, op); } } public class ScoreDefinition { public PdtExpression value; public float init = 0; public string format = ""; } public class Constraint { static readonly PropOp.Arbitrary _arbop = new(); [ElementList] public PairList Elements = new(); [PropertyList] public PairList Properties = new(); public void Optimize(PdtEvaluatorBase etor) { foreach (var e in Properties) { etor.Optimize(e.Value); } foreach (var e in Elements) { e.Key.Optimize(etor); e.Value.Optimize(etor); } } public void PrePatch(ChartEvent ev) { var etor = PdtEvaluator.Instance; etor.ContextCascadeInsert(); etor.ContextEvent = ev; foreach (var prop in Properties) { var name = prop.Key.Name; switch (prop.Key.Type) { case ConstraintType.Property: if (ev.PropSrcs.TryGetValue(name, out PropSrc src)) etor.ContextSelfValue = src; etor.Evaluate(ev.PropOps[name], prop.Value); etor.ContextSelfValue = null; break; case ConstraintType.Variable: _arbop.Name = name; etor.Evaluate(_arbop, prop.Value); break; default: throw new NotSupportedException("Unknown property key type"); } } etor.ContextEvent = null; foreach (var el in Elements) { var targets = el.Key.Match(ev); if (targets == null) continue; foreach (var target in targets) el.Value.PrePatch(target); } etor.ContextCascadeDiscard(); } } public class ConstraintKey { public ConstraintType Type { get; private set; } public int Name { get; private set; } public ConstraintKey(ConstraintType type, string name) { Type = type; Name = IdentifierManager.Shared.Request(name); } public override string ToString() => Type switch { ConstraintType.Property => (string)IdentifierManager.Shared.Retrieve(Name), ConstraintType.Variable => string.Format("@var {0}", IdentifierManager.Shared.Retrieve(Name)), _ => string.Format("<{0}> {1}", Type, IdentifierManager.Shared.Retrieve(Name)), }; } public enum ConstraintType { Property, Variable, } public class RulesetViolationException : Exception { public RulesetViolationException() { } public RulesetViolationException(string message) : base(message) { } public RulesetViolationException(string message, Exception innerException) : base(message, innerException) { } } }