Files
crtr/Assets/Cryville/Crtr/Ruleset.cs
2022-11-14 16:05:21 +08:00

229 lines
7.3 KiB
C#

using Cryville.Common;
using Cryville.Common.Pdt;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using SIdentifier = Cryville.Common.Identifier;
namespace Cryville.Crtr {
public class Ruleset {
[JsonRequired]
public long format;
[JsonRequired]
public string @base;
[JsonRequired]
public string pdt;
[JsonIgnore]
public PdtRuleset Root { get; private set; }
public void LoadPdt(DirectoryInfo dir) {
using (StreamReader pdtreader = new StreamReader(dir.FullName + "/" + pdt + ".pdt", Encoding.UTF8)) {
var src = pdtreader.ReadToEnd();
Root = new RulesetInterpreter(src, null).Interpret();
}
}
}
[Binder(typeof(PdtRulesetBinder))]
public class PdtRuleset {
public Dictionary<Identifier, InputDefinition> inputs;
public Dictionary<Identifier, JudgeDefinition> judges;
public Dictionary<Identifier, ScoreDefinition> scores;
public Constraint constraints;
public void Optimize(PdtEvaluatorBase etor) {
foreach (var i in inputs.Values) {
if (i.pass != null) foreach (var e in i.pass.Values) {
etor.Optimize(e);
}
}
foreach (var j in judges.Values) {
if (j.hit != null) etor.Optimize(j.hit);
if (j.scores != null) {
foreach (var s in j.scores) {
if (s.Key.op != default(Identifier))
etor.PatchCompound(s.Key.name.Key, s.Key.op.Key, s.Value);
etor.Optimize(s.Value);
}
}
}
foreach (var s in scores.Values) {
if (s.value != null) etor.Optimize(s.value);
}
constraints.Optimize(etor);
}
public void PrePatch(Chart chart) {
constraints.PrePatch(chart);
}
}
public class Constraint {
static readonly PropOp.Arbitrary _arbop = new PropOp.Arbitrary();
[ElementList]
public Dictionary<RulesetSelectors, Constraint> Elements = new Dictionary<RulesetSelectors, Constraint>();
[PropertyList]
public Dictionary<PropertyKey, PdtExpression> Properties = new Dictionary<PropertyKey, PdtExpression>();
public void Optimize(PdtEvaluatorBase etor) {
foreach (var e in Properties.Values) {
etor.Optimize(e);
}
foreach (var e in Elements) {
e.Key.Optimize(etor);
e.Value.Optimize(etor);
}
}
public void PrePatch(ChartEvent ev) {
var etor = ChartPlayer.etor;
PropSrc src;
etor.ContextCascadeInsert();
etor.ContextEvent = ev;
foreach (var prop in Properties) {
var name = prop.Key.Name;
switch (prop.Key.Type) {
case PropertyType.Property:
if (ev.PropSrcs.TryGetValue(name, out src))
etor.ContextSelfValue = src;
etor.Evaluate(ev.PropOps[name], prop.Value);
etor.ContextSelfValue = null;
break;
case PropertyType.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 PropertyKey {
public PropertyType Type { get; private set; }
public int Name { get; private set; }
public PropertyKey(PropertyType type, string name) {
Type = type;
Name = IdentifierManager.SharedInstance.Request(name);
}
public override string ToString() {
switch (Type) {
case PropertyType.Property: return (string)IdentifierManager.SharedInstance.Retrieve(Name);
case PropertyType.Variable: return string.Format("@var {0}", IdentifierManager.SharedInstance.Retrieve(Name));
default: return string.Format("<{0}> {1}", Type, IdentifierManager.SharedInstance.Retrieve(Name));
}
}
}
public enum PropertyType {
Property,
Variable,
}
public class PdtRulesetBinder : EmptyBinder {
public override object ChangeType(object value, Type type, CultureInfo culture) {
if (value is PdtExpression) {
var exp = (PdtExpression)value;
if (type.Equals(typeof(bool))) {
bool result = false;
ChartPlayer.etor.Evaluate(new PropOp.Boolean(r => result = r), exp);
return result;
}
else if (type.Equals(typeof(int))) {
int result = 0;
ChartPlayer.etor.Evaluate(new PropOp.Integer(r => result = r), exp);
return result;
}
else if (type.Equals(typeof(float))) {
float result = 0;
ChartPlayer.etor.Evaluate(new PropOp.Float(r => result = r), exp);
return result;
}
else if (type.Equals(typeof(string))) {
string result = default(string);
ChartPlayer.etor.Evaluate(new PropOp.String(r => result = r), exp);
return result;
}
else if (type.Equals(typeof(float[]))) {
float[] result = null;
ChartPlayer.etor.Evaluate(new pop_numarr(r => result = r), exp);
return result;
}
else if (type.Equals(typeof(Identifier))) {
Identifier result = default(Identifier);
ChartPlayer.etor.Evaluate(new pop_identstr(r => result = r), exp);
return result;
}
else if (type.Equals(typeof(Identifier[]))) {
Identifier[] result = null;
ChartPlayer.etor.Evaluate(new pop_identstrarr(r => result = r), exp);
return result;
}
}
else if (value is string) {
var exp = (string)value;
if (type.Equals(typeof(Identifier))) {
return (Identifier)exp;
}
else if (type == typeof(ScoreOperation)) {
var m = Regex.Match(exp, @"^(\S+)\s*?(\S+)?$");
var name = new Identifier(m.Groups[1].Value);
if (!m.Groups[2].Success) return new ScoreOperation { name = name };
var op = new Identifier(m.Groups[2].Value);
return new ScoreOperation { name = name, op = op };
}
}
return base.ChangeType(value, type, culture);
}
#pragma warning disable IDE1006
class pop_numarr : PdtOperator {
readonly Action<float[]> _cb;
public pop_numarr(Action<float[]> cb) : base(16) { _cb = cb; }
protected override void Execute() {
var result = new float[LoadedOperandCount];
for (int i = 0; i < LoadedOperandCount; i++) {
result[i] = GetOperand(i).AsNumber();
}
_cb(result);
}
}
class pop_identstr : PropOp {
readonly Action<SIdentifier> _cb;
public pop_identstr(Action<SIdentifier> cb) { _cb = cb; }
protected override void Execute() {
var op = GetOperand(0);
if (op.Type == PdtInternalType.Undefined) _cb(new SIdentifier(op.AsIdentifier()));
else if (op.Type == PdtInternalType.String) _cb(new SIdentifier(op.AsString()));
else throw new InvalidCastException("Not an identifier or string");
}
}
class pop_identstrarr : PdtOperator {
readonly Action<SIdentifier[]> _cb;
public pop_identstrarr(Action<SIdentifier[]> cb) : base(16) { _cb = cb; }
protected override void Execute() {
var result = new SIdentifier[LoadedOperandCount];
for (int i = 0; i < LoadedOperandCount; i++) {
var op = GetOperand(i);
if (op.Type != PdtInternalType.Undefined)
throw new InvalidCastException("Not an identifier");
result[i] = new SIdentifier(op.AsIdentifier());
}
_cb(result);
}
}
#pragma warning restore IDE1006
}
public class RulesetViolationException : Exception {
public RulesetViolationException() { }
public RulesetViolationException(string message) : base(message) { }
public RulesetViolationException(string message, Exception innerException) : base(message, innerException) { }
}
}