/// <summary> /// Generates random hold notes that start at an span the same amount of rows. /// </summary> /// <param name="startTime">Start time of each hold note.</param> /// <param name="noteCount">Number of hold notes.</param> /// <returns>The <see cref="Pattern"/> containing the hit objects.</returns> private Pattern generateRandomHoldNotes(double startTime, int noteCount) { // - - - - // ■ - ■ ■ // □ - □ □ // ■ - ■ ■ var pattern = new Pattern(); int usableColumns = TotalColumns - RandomStart - PreviousPattern.ColumnWithObjects; int nextColumn = Random.Next(RandomStart, TotalColumns); for (int i = 0; i < Math.Min(usableColumns, noteCount); i++) { while (pattern.ColumnHasObject(nextColumn) || PreviousPattern.ColumnHasObject(nextColumn)) //find available column { nextColumn = Random.Next(RandomStart, TotalColumns); } addToPattern(pattern, nextColumn, startTime, endTime); } // This is can't be combined with the above loop due to RNG for (int i = 0; i < noteCount - usableColumns; i++) { while (pattern.ColumnHasObject(nextColumn)) { nextColumn = Random.Next(RandomStart, TotalColumns); } addToPattern(pattern, nextColumn, startTime, endTime); } return(pattern); }
/// <summary> /// Picks a random column after a column. /// </summary> /// <param name="start">The starting column.</param> /// <returns>A random column after <paramref name="start"/>.</returns> private int getNextRandomColumn(int start) { int nextColumn = Random.Next(start, TotalColumns); while (PreviousPattern.ColumnHasObject(nextColumn)) { nextColumn = Random.Next(start, TotalColumns); } return(nextColumn); }
/// <summary> /// Picks a random column after a column. /// </summary> /// <param name="start">The starting column.</param> /// <returns>A random column after <paramref name="start"/>.</returns> private int getNextRandomColumn(int start) { int nextColumn = Random.Next(start, TotalColumns); RunWhile(() => PreviousPattern.ColumnHasObject(nextColumn), () => { nextColumn = Random.Next(start, TotalColumns); }); return(nextColumn); }
/// <summary> /// Generates tiled hold notes. You can think of this as a stair of hold notes. /// </summary> /// <param name="startTime">The first hold note start time.</param> /// <returns>The <see cref="Pattern"/> containing the hit objects.</returns> private Pattern generateTiledHoldNotes(double startTime) { // - - - - // ■ ■ ■ ■ // □ □ □ □ // □ □ □ □ // □ □ □ ■ // □ □ ■ - // □ ■ - - // ■ - - - var pattern = new Pattern(); int columnRepeat = Math.Min(spanCount, TotalColumns); int nextColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true); if ((convertType & PatternType.ForceNotStack) > 0 && PreviousPattern.ColumnWithObjects < TotalColumns) { while (PreviousPattern.ColumnHasObject(nextColumn)) { nextColumn = Random.Next(RandomStart, TotalColumns); } } for (int i = 0; i < columnRepeat; i++) { while (pattern.ColumnHasObject(nextColumn)) { nextColumn = Random.Next(RandomStart, TotalColumns); } addToPattern(pattern, nextColumn, startTime, endTime); startTime += segmentDuration; } return(pattern); }
/// <summary> /// Generates random notes, with one note per row and no stacking. /// </summary> /// <param name="startTime">The start time.</param> /// <param name="noteCount">The number of notes.</param> /// <returns>The <see cref="Pattern"/> containing the hit objects.</returns> private Pattern generateRandomNotes(double startTime, int noteCount) { // - - - - // x - - - // - - x - // - - - x // x - - - var pattern = new Pattern(); int nextColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true); if (convertType.HasFlag(PatternType.ForceNotStack) && PreviousPattern.ColumnWithObjects < TotalColumns) { RunWhile(() => PreviousPattern.ColumnHasObject(nextColumn), () => { nextColumn = Random.Next(RandomStart, TotalColumns); }); } int lastColumn = nextColumn; for (int i = 0; i < noteCount; i++) { addToPattern(pattern, nextColumn, startTime, startTime); RunWhile(() => nextColumn == lastColumn, () => { nextColumn = Random.Next(RandomStart, TotalColumns); }); lastColumn = nextColumn; startTime += SegmentDuration; } return(pattern); }
/// <summary> /// Generates random notes, with one note per row and no stacking. /// </summary> /// <param name="startTime">The start time.</param> /// <param name="noteCount">The number of notes.</param> /// <returns>The <see cref="Pattern"/> containing the hit objects.</returns> private Pattern generateRandomNotes(double startTime, int noteCount) { // - - - - // x - - - // - - x - // - - - x // x - - - var pattern = new Pattern(); int nextColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true); if ((convertType & PatternType.ForceNotStack) > 0 && PreviousPattern.ColumnWithObjects < AvailableColumns) { while (PreviousPattern.ColumnHasObject(nextColumn)) { nextColumn = Random.Next(RandomStart, AvailableColumns); } } int lastColumn = nextColumn; for (int i = 0; i < noteCount; i++) { addToPattern(pattern, nextColumn, startTime, startTime); while (nextColumn == lastColumn) { nextColumn = Random.Next(RandomStart, AvailableColumns); } lastColumn = nextColumn; startTime += segmentDuration; } return(pattern); }
/// <summary> /// Generates random notes. /// <para> /// This will generate as many as it can up to <paramref name="noteCount"/>, accounting for /// any stacks if <see cref="convertType"/> is forcing no stacks. /// </para> /// </summary> /// <param name="noteCount">The amount of notes to generate.</param> /// <returns>The <see cref="Pattern"/> containing the hit objects.</returns> private Pattern generateRandomNotes(int noteCount) { var pattern = new Pattern(); bool allowStacking = !convertType.HasFlag(PatternType.ForceNotStack); if (!allowStacking) { noteCount = Math.Min(noteCount, TotalColumns - RandomStart - PreviousPattern.ColumnWithObjects); } int nextColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true); for (int i = 0; i < noteCount; i++) { while (pattern.ColumnHasObject(nextColumn) || PreviousPattern.ColumnHasObject(nextColumn) && !allowStacking) { if (convertType.HasFlag(PatternType.Gathered)) { nextColumn++; if (nextColumn == TotalColumns) { nextColumn = RandomStart; } } else { nextColumn = Random.Next(RandomStart, TotalColumns); } } addToPattern(pattern, nextColumn); } return(pattern); }
public override IEnumerable <Pattern> Generate() { Pattern generateCore() { var pattern = new Pattern(); if (TotalColumns == 1) { addToPattern(pattern, 0); return(pattern); } int lastColumn = PreviousPattern.HitObjects.FirstOrDefault()?.Column ?? 0; if (convertType.HasFlagFast(PatternType.Reverse) && PreviousPattern.HitObjects.Any()) { // Generate a new pattern by copying the last hit objects in reverse-column order for (int i = RandomStart; i < TotalColumns; i++) { if (PreviousPattern.ColumnHasObject(i)) { addToPattern(pattern, RandomStart + TotalColumns - i - 1); } } return(pattern); } if (convertType.HasFlagFast(PatternType.Cycle) && PreviousPattern.HitObjects.Count() == 1 // If we convert to 7K + 1, let's not overload the special key && (TotalColumns != 8 || lastColumn != 0) // Make sure the last column was not the centre column && (TotalColumns % 2 == 0 || lastColumn != TotalColumns / 2)) { // Generate a new pattern by cycling backwards (similar to Reverse but for only one hit object) int column = RandomStart + TotalColumns - lastColumn - 1; addToPattern(pattern, column); return(pattern); } if (convertType.HasFlagFast(PatternType.ForceStack) && PreviousPattern.HitObjects.Any()) { // Generate a new pattern by placing on the already filled columns for (int i = RandomStart; i < TotalColumns; i++) { if (PreviousPattern.ColumnHasObject(i)) { addToPattern(pattern, i); } } return(pattern); } if (PreviousPattern.HitObjects.Count() == 1) { if (convertType.HasFlagFast(PatternType.Stair)) { // Generate a new pattern by placing on the next column, cycling back to the start if there is no "next" int targetColumn = lastColumn + 1; if (targetColumn == TotalColumns) { targetColumn = RandomStart; } addToPattern(pattern, targetColumn); return(pattern); } if (convertType.HasFlagFast(PatternType.ReverseStair)) { // Generate a new pattern by placing on the previous column, cycling back to the end if there is no "previous" int targetColumn = lastColumn - 1; if (targetColumn == RandomStart - 1) { targetColumn = TotalColumns - 1; } addToPattern(pattern, targetColumn); return(pattern); } } if (convertType.HasFlagFast(PatternType.KeepSingle)) { return(generateRandomNotes(1)); } if (convertType.HasFlagFast(PatternType.Mirror)) { if (ConversionDifficulty > 6.5) { return(generateRandomPatternWithMirrored(0.12, 0.38, 0.12)); } if (ConversionDifficulty > 4) { return(generateRandomPatternWithMirrored(0.12, 0.17, 0)); } return(generateRandomPatternWithMirrored(0.12, 0, 0)); } if (ConversionDifficulty > 6.5) { if (convertType.HasFlagFast(PatternType.LowProbability)) { return(generateRandomPattern(0.78, 0.42, 0, 0)); } return(generateRandomPattern(1, 0.62, 0, 0)); } if (ConversionDifficulty > 4) { if (convertType.HasFlagFast(PatternType.LowProbability)) { return(generateRandomPattern(0.35, 0.08, 0, 0)); } return(generateRandomPattern(0.52, 0.15, 0, 0)); } if (ConversionDifficulty > 2) { if (convertType.HasFlagFast(PatternType.LowProbability)) { return(generateRandomPattern(0.18, 0, 0, 0)); } return(generateRandomPattern(0.45, 0, 0, 0)); } return(generateRandomPattern(0, 0, 0, 0)); } var p = generateCore(); foreach (var obj in p.HitObjects) { if (convertType.HasFlagFast(PatternType.Stair) && obj.Column == TotalColumns - 1) { StairType = PatternType.ReverseStair; } if (convertType.HasFlagFast(PatternType.ReverseStair) && obj.Column == RandomStart) { StairType = PatternType.Stair; } } return(p.Yield()); }
/// <summary> /// Generates a hold note alongside normal notes. /// </summary> /// <param name="startTime">The start time of notes.</param> /// <returns>The <see cref="Pattern"/> containing the hit objects.</returns> private Pattern generateHoldAndNormalNotes(double startTime) { // - - - - // ■ x x - // ■ - x x // ■ x - x // ■ - x x var pattern = new Pattern(); int holdColumn = GetColumn((HitObject as IHasXPosition)?.X ?? 0, true); if ((convertType & PatternType.ForceNotStack) > 0 && PreviousPattern.ColumnWithObjects < TotalColumns) { while (PreviousPattern.ColumnHasObject(holdColumn)) { holdColumn = Random.Next(RandomStart, TotalColumns); } } // Create the hold note addToPattern(pattern, holdColumn, startTime, endTime); int nextColumn = Random.Next(RandomStart, TotalColumns); int noteCount; if (ConversionDifficulty > 6.5) { noteCount = GetRandomNoteCount(0.63, 0); } else if (ConversionDifficulty > 4) { noteCount = GetRandomNoteCount(TotalColumns < 6 ? 0.12 : 0.45, 0); } else if (ConversionDifficulty > 2.5) { noteCount = GetRandomNoteCount(TotalColumns < 6 ? 0 : 0.24, 0); } else { noteCount = 0; } noteCount = Math.Min(TotalColumns - 1, noteCount); bool ignoreHead = !sampleInfoListAt(startTime).Any(s => s.Name == SampleInfo.HIT_WHISTLE || s.Name == SampleInfo.HIT_FINISH || s.Name == SampleInfo.HIT_CLAP); var rowPattern = new Pattern(); for (int i = 0; i <= spanCount; i++) { if (!(ignoreHead && startTime == HitObject.StartTime)) { for (int j = 0; j < noteCount; j++) { while (rowPattern.ColumnHasObject(nextColumn) || nextColumn == holdColumn) { nextColumn = Random.Next(RandomStart, TotalColumns); } addToPattern(rowPattern, nextColumn, startTime, startTime); } } pattern.Add(rowPattern); rowPattern.Clear(); startTime += segmentDuration; } return(pattern); }