213 lines
6.4 KiB
C#
213 lines
6.4 KiB
C#
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<Identifier, ConfigDefinition> configs;
|
|
public Dictionary<Identifier, MotionDefinition> motions;
|
|
public Dictionary<Identifier, InputDefinition> inputs;
|
|
public Dictionary<Identifier, PdtExpression> areas;
|
|
public Dictionary<Identifier, JudgeDefinition> judges;
|
|
public Dictionary<Identifier, ScoreDefinition> 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<JudgeAction, PdtExpression> 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<Identifier, PdtExpression> pass;
|
|
}
|
|
public class JudgeDefinition {
|
|
public int stack;
|
|
public int prop;
|
|
public PdtExpression clip;
|
|
public PdtExpression input;
|
|
public PdtExpression hit;
|
|
public PdtExpression persist;
|
|
public PairList<JudgeAction, PdtExpression> on_hit;
|
|
public PairList<JudgeAction, PdtExpression> on_miss;
|
|
#pragma warning disable IDE1006
|
|
public PairList<ScoreOperation, PdtExpression> scores {
|
|
set {
|
|
on_hit ??= new PairList<JudgeAction, PdtExpression>();
|
|
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<JudgeAction, PdtExpression>();
|
|
on_hit.Add(new JudgeAction.Pass(Enumerable.Empty<string>(), value), PdtExpression.Empty);
|
|
}
|
|
}
|
|
public Identifier[] miss {
|
|
set {
|
|
on_miss ??= new PairList<JudgeAction, PdtExpression>();
|
|
on_miss.Add(new JudgeAction.Pass(Enumerable.Empty<string>(), 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<RulesetSelectors, Constraint> Elements = new();
|
|
[PropertyList]
|
|
public PairList<ConstraintKey, PdtExpression> 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) { }
|
|
}
|
|
}
|