/// <summary> /// Finds and marks all sequences hittable using a roll. /// </summary> /// <param name="patternLength">The length of a single repeating pattern to consider (triplets/quadruplets).</param> private void findRolls(int patternLength) { var history = new LimitedCapacityQueue <TaikoDifficultyHitObject>(2 * patternLength); // for convenience, we're tracking the index of the item *before* our suspected repeat's start, // as that index can be simply subtracted from the current index to get the number of elements in between // without off-by-one errors int indexBeforeLastRepeat = -1; for (int i = 0; i < hitObjects.Count; i++) { history.Enqueue(hitObjects[i]); if (!history.Full) { continue; } if (!containsPatternRepeat(history, patternLength)) { // we're setting this up for the next iteration, hence the +1. // right here this index will point at the queue's front (oldest item), // but that item is about to be popped next loop with an enqueue. indexBeforeLastRepeat = i - history.Count + 1; continue; } int repeatedLength = i - indexBeforeLastRepeat; if (repeatedLength < roll_min_repetitions) { continue; } markObjectsAsCheese(i, repeatedLength); } }
protected override double StrainValueOf(DifficultyHitObject current) { if (!(current.BaseObject is Hit)) { return(0.0); } TaikoDifficultyHitObject hitObject = (TaikoDifficultyHitObject)current; if (hitObject.ObjectIndex % 2 == hand) { double objectStrain = 1; if (hitObject.ObjectIndex == 1) { return(1); } notePairDurationHistory.Enqueue(hitObject.DeltaTime + offhandObjectDuration); double shortestRecentNote = notePairDurationHistory.Min(); objectStrain += speedBonus(shortestRecentNote); if (hitObject.StaminaCheese) { objectStrain *= cheesePenalty(hitObject.DeltaTime + offhandObjectDuration); } return(objectStrain); } offhandObjectDuration = hitObject.DeltaTime; return(0); }
public void TestBelowCapacity(int count) { for (int i = 0; i < count; ++i) { queue.Enqueue(i); } Assert.AreEqual(count, queue.Count); for (int i = 0; i < count; ++i) { Assert.AreEqual(i, queue[i]); } int j = 0; foreach (int item in queue) { Assert.AreEqual(j++, item); } for (int i = queue.Count; i < queue.Count + capacity; i++) { Assert.Throws <ArgumentOutOfRangeException>(() => _ = queue[i]); } }
/// <summary> /// Returns a penalty to apply to the current hit object caused by repeating rhythm changes. /// </summary> /// <remarks> /// Repetitions of more recent patterns are associated with a higher penalty. /// </remarks> /// <param name="hitObject">The current hit object being considered.</param> private double repetitionPenalties(TaikoDifficultyHitObject hitObject) { double penalty = 1; rhythmHistory.Enqueue(hitObject); for (int mostRecentPatternsToCompare = 2; mostRecentPatternsToCompare <= rhythm_history_max_length / 2; mostRecentPatternsToCompare++) { for (int start = rhythmHistory.Count - mostRecentPatternsToCompare - 1; start >= 0; start--) { if (!samePattern(start, mostRecentPatternsToCompare)) { continue; } int notesSince = hitObject.ObjectIndex - rhythmHistory[start].ObjectIndex; penalty *= repetitionPenalty(notesSince); break; } } return(penalty); }