Files
crtr/Assets/Cryville/Crtr/Judge.cs
2022-11-14 13:55:10 +08:00

154 lines
4.8 KiB
C#

using Cryville.Common;
using Cryville.Common.Pdt;
using Cryville.Crtr.Event;
using System.Collections.Generic;
namespace Cryville.Crtr {
public class Judge {
readonly PdtEvaluator _etor;
readonly PdtRuleset _rs;
readonly Dictionary<Identifier, float> ct
= new Dictionary<Identifier, float>();
readonly Dictionary<Identifier, List<JudgeEvent>> evs
= new Dictionary<Identifier, List<JudgeEvent>>();
readonly Dictionary<Identifier, List<JudgeEvent>> activeEvs
= new Dictionary<Identifier, List<JudgeEvent>>();
struct JudgeEvent {
public float StartTime { get; set; }
public float EndTime { get; set; }
public float StartClip { get; set; }
public float EndClip { get; set; }
public JudgeDefinition Definition { get; set; }
public ContainerState State { get; set; }
}
static readonly IComparer<JudgeEvent> _stcmp = new JudgeEventStartTimeComparer();
class JudgeEventStartTimeComparer : IComparer<JudgeEvent> {
public int Compare(JudgeEvent x, JudgeEvent y) {
return x.StartClip.CompareTo(y.StartClip);
}
}
public Judge(PdtRuleset rs) {
_etor = ChartPlayer.etor;
_rs = rs;
foreach (var s in rs.scores) {
var name = s.Key.Key;
scoreDefs.Add(name, s.Value);
scores.Add(name, s.Value.init);
}
}
public void Prepare(float st, float et, Identifier input, JudgeDefinition def, ContainerState container) {
List<JudgeEvent> list;
if (!evs.TryGetValue(input, out list)) {
ct.Add(input, 0);
evs.Add(input, list = new List<JudgeEvent>());
activeEvs.Add(input, new List<JudgeEvent>());
}
var ev = new JudgeEvent {
StartTime = st,
EndTime = et,
StartClip = st + def.clip[0],
EndClip = et + def.clip[1],
Definition = def,
State = container,
};
var index = list.BinarySearch(ev, _stcmp);
if (index < 0) index = ~index;
list.Insert(index, ev);
}
// Adopted from System.Collections.Generic.ArraySortHelper<T>.InternalBinarySearch(T[] array, int index, int length, T value, IComparer<T> comparer)
int BinarySearch(List<JudgeEvent> list, float time, int stack) {
int num = 0;
int num2 = list.Count - 1;
while (num <= num2) {
int num3 = num + (num2 - num >> 1);
int num4 = -list[num3].Definition.stack.CompareTo(stack);
if (num4 == 0) num4 = list[num3].StartClip.CompareTo(time);
if (num4 == 0) return num3;
else if (num4 < 0) num = num3 + 1;
else num2 = num3 - 1;
}
return ~num;
}
public void Feed(Identifier target, float ft, float tt) {
Forward(target, tt);
var actlist = activeEvs[target];
foreach (var ev in actlist) {
// TODO judge ev
}
}
public void Cleanup(Identifier target, float ft, float tt) {
Forward(target, tt);
var actlist = activeEvs[target];
for (int i = actlist.Count - 1; i >= 0; i--) {
JudgeEvent ev = actlist[i];
if (tt > ev.EndClip) {
actlist.RemoveAt(i);
// TODO miss ev
}
}
}
void Forward(Identifier target, float tt) {
var list = evs[target];
var actlist = activeEvs[target];
JudgeEvent ev;
while (list.Count > 0 && (ev = list[0]).StartClip <= tt) {
list.RemoveAt(0);
var index = BinarySearch(actlist, ev.StartClip, ev.Definition.stack);
if (index < 0) index = ~index;
actlist.Insert(index, ev);
// TODO priority?
}
}
public readonly Dictionary<int, ScoreDefinition> scoreDefs = new Dictionary<int, ScoreDefinition>();
public readonly Dictionary<int, float> scores = new Dictionary<int, float>();
readonly Dictionary<int, string> ScoreCache = new Dictionary<int, string>();
readonly object _lock = new object();
public Dictionary<int, string> GetFormattedScoreStrings() {
lock (_lock) {
if (ScoreCache.Count == 0) {
foreach (var s in scores)
ScoreCache.Add(s.Key, s.Value.ToString(scoreDefs[s.Key].format));
}
return ScoreCache;
}
}
public string GetFullFormattedScoreString() {
bool flag = false;
string result = "";
foreach (var s in GetFormattedScoreStrings()) {
result += string.Format(flag ? "\n{0}: {1}" : "{0}: {1}", IdentifierManager.SharedInstance.Retrieve(s.Key), s.Value);
flag = true;
}
return result;
}
}
public class InputDefinition {
public int dim;
public bool notnull;
public Dictionary<Identifier, PdtExpression> pass;
}
public class JudgeDefinition {
public float[] clip;
public PdtExpression input;
public PdtExpression hit;
public Identifier[] pass;
public Identifier miss;
public Dictionary<ScoreOperation, PdtExpression> scores;
public int stack;
public int prop = -1;
}
public class ScoreOperation {
public Identifier name;
public Identifier op;
public override string ToString() {
if (op == default(Identifier)) return name.ToString();
else return string.Format("{0} {1}", name, op);
}
}
public class ScoreDefinition {
public PdtExpression value;
public float init = 0;
public string format = "";
}
}