mirror of
https://github.com/ppy/osu.git
synced 2025-03-28 01:37:46 +08:00
Fix random and add tests
Also exposes SelectedBeatmapSet.
This commit is contained in:
parent
8646d5d1e0
commit
5cbb9b9b18
@ -10,6 +10,7 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Framework.Extensions;
|
using osu.Framework.Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Screens.Select;
|
using osu.Game.Screens.Select;
|
||||||
using osu.Game.Screens.Select.Carousel;
|
using osu.Game.Screens.Select.Carousel;
|
||||||
|
|
||||||
@ -44,7 +45,7 @@ namespace osu.Game.Tests.Visual
|
|||||||
|
|
||||||
AddStep("Load Beatmaps", () =>
|
AddStep("Load Beatmaps", () =>
|
||||||
{
|
{
|
||||||
carousel.Beatmaps = new[]
|
carousel.BeatmapSets = new[]
|
||||||
{
|
{
|
||||||
createTestBeatmapSet(1),
|
createTestBeatmapSet(1),
|
||||||
createTestBeatmapSet(2),
|
createTestBeatmapSet(2),
|
||||||
@ -55,11 +56,11 @@ namespace osu.Game.Tests.Visual
|
|||||||
|
|
||||||
void checkSelected(int set, int diff) =>
|
void checkSelected(int set, int diff) =>
|
||||||
AddAssert($"selected is set{set} diff{diff}", () =>
|
AddAssert($"selected is set{set} diff{diff}", () =>
|
||||||
carousel.SelectedBeatmap == carousel.Beatmaps.Skip(set - 1).First().Beatmaps.Skip(diff - 1).First());
|
carousel.SelectedBeatmap == carousel.BeatmapSets.Skip(set - 1).First().Beatmaps.Skip(diff - 1).First());
|
||||||
|
|
||||||
void setSelected(int set, int diff) =>
|
void setSelected(int set, int diff) =>
|
||||||
AddStep($"select set{set} diff{diff}", () =>
|
AddStep($"select set{set} diff{diff}", () =>
|
||||||
carousel.SelectBeatmap(carousel.Beatmaps.Skip(set - 1).First().Beatmaps.Skip(diff - 1).First()));
|
carousel.SelectBeatmap(carousel.BeatmapSets.Skip(set - 1).First().Beatmaps.Skip(diff - 1).First()));
|
||||||
|
|
||||||
void advanceSelection(bool diff, int direction = 1, int count = 1)
|
void advanceSelection(bool diff, int direction = 1, int count = 1)
|
||||||
{
|
{
|
||||||
@ -77,7 +78,7 @@ namespace osu.Game.Tests.Visual
|
|||||||
AddAssert($"{count} {(diff ? "diff" : "set")} visible", () =>
|
AddAssert($"{count} {(diff ? "diff" : "set")} visible", () =>
|
||||||
carousel.Items.Count(s => (diff ? s.Item is CarouselBeatmap : s.Item is CarouselBeatmapSet) && s.Item.Visible) == count);
|
carousel.Items.Count(s => (diff ? s.Item is CarouselBeatmap : s.Item is CarouselBeatmapSet) && s.Item.Visible) == count);
|
||||||
|
|
||||||
AddUntilStep(() => carousel.Beatmaps.Any(), "Wait for load");
|
AddUntilStep(() => carousel.BeatmapSets.Any(), "Wait for load");
|
||||||
|
|
||||||
// test traversal
|
// test traversal
|
||||||
|
|
||||||
@ -122,6 +123,55 @@ namespace osu.Game.Tests.Visual
|
|||||||
checkSelected(1, 1);
|
checkSelected(1, 1);
|
||||||
AddStep("Un-filter", () => carousel.Filter(new FilterCriteria(), false));
|
AddStep("Un-filter", () => carousel.Filter(new FilterCriteria(), false));
|
||||||
checkSelected(1, 1);
|
checkSelected(1, 1);
|
||||||
|
|
||||||
|
// test random non-repeating algorithm
|
||||||
|
|
||||||
|
Stack<BeatmapSetInfo> selectedSets = new Stack<BeatmapSetInfo>();
|
||||||
|
|
||||||
|
void nextRandom() =>
|
||||||
|
AddStep("select random next", () =>
|
||||||
|
{
|
||||||
|
carousel.RandomAlgorithm.Value = RandomSelectAlgorithm.RandomPermutation;
|
||||||
|
|
||||||
|
if (!selectedSets.Any() && carousel.SelectedBeatmap != null)
|
||||||
|
selectedSets.Push(carousel.SelectedBeatmapSet);
|
||||||
|
|
||||||
|
carousel.SelectNextRandom();
|
||||||
|
selectedSets.Push(carousel.SelectedBeatmapSet);
|
||||||
|
});
|
||||||
|
|
||||||
|
void ensureRandomDidntRepeat() =>
|
||||||
|
AddAssert("ensure no repeats", () => selectedSets.Distinct().Count() == selectedSets.Count());
|
||||||
|
|
||||||
|
void prevRandom() => AddStep("select random last", () =>
|
||||||
|
{
|
||||||
|
carousel.SelectPreviousRandom();
|
||||||
|
selectedSets.Pop();
|
||||||
|
});
|
||||||
|
|
||||||
|
void ensureRandomFetchSuccess() =>
|
||||||
|
AddAssert("ensure prev random fetch worked", () => selectedSets.Peek() == carousel.SelectedBeatmapSet);
|
||||||
|
|
||||||
|
setSelected(1, 1);
|
||||||
|
nextRandom();
|
||||||
|
ensureRandomDidntRepeat();
|
||||||
|
nextRandom();
|
||||||
|
ensureRandomDidntRepeat();
|
||||||
|
nextRandom();
|
||||||
|
ensureRandomDidntRepeat();
|
||||||
|
|
||||||
|
prevRandom();
|
||||||
|
ensureRandomFetchSuccess();
|
||||||
|
prevRandom();
|
||||||
|
ensureRandomFetchSuccess();
|
||||||
|
|
||||||
|
nextRandom();
|
||||||
|
ensureRandomDidntRepeat();
|
||||||
|
nextRandom();
|
||||||
|
ensureRandomDidntRepeat();
|
||||||
|
|
||||||
|
nextRandom();
|
||||||
|
AddAssert("ensure repeat", () => selectedSets.Contains(carousel.SelectedBeatmapSet));
|
||||||
}
|
}
|
||||||
|
|
||||||
private BeatmapSetInfo createTestBeatmapSet(int i)
|
private BeatmapSetInfo createTestBeatmapSet(int i)
|
||||||
|
@ -27,15 +27,24 @@ namespace osu.Game.Screens.Select
|
|||||||
public class BeatmapCarousel : OsuScrollContainer
|
public class BeatmapCarousel : OsuScrollContainer
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Triggered when the <see cref="Beatmaps"/> loaded change and are completely loaded.
|
/// Triggered when the <see cref="BeatmapSets"/> loaded change and are completely loaded.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Action BeatmapsChanged;
|
public Action BeatmapSetsChanged;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The currently selected beatmap.
|
/// The currently selected beatmap.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public BeatmapInfo SelectedBeatmap => selectedBeatmap?.Beatmap;
|
public BeatmapInfo SelectedBeatmap => selectedBeatmap?.Beatmap;
|
||||||
|
|
||||||
|
private CarouselBeatmap selectedBeatmap => selectedBeatmapSet?.Beatmaps.FirstOrDefault(s => s.State == CarouselItemState.Selected);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The currently selected beatmap set.
|
||||||
|
/// </summary>
|
||||||
|
public BeatmapSetInfo SelectedBeatmapSet => selectedBeatmapSet?.BeatmapSet;
|
||||||
|
|
||||||
|
private CarouselBeatmapSet selectedBeatmapSet => carouselSets.FirstOrDefault(s => s.State == CarouselItemState.Selected);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Raised when the <see cref="SelectedBeatmap"/> is changed.
|
/// Raised when the <see cref="SelectedBeatmap"/> is changed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -43,7 +52,7 @@ namespace osu.Game.Screens.Select
|
|||||||
|
|
||||||
public override bool HandleInput => AllowSelection;
|
public override bool HandleInput => AllowSelection;
|
||||||
|
|
||||||
public IEnumerable<BeatmapSetInfo> Beatmaps
|
public IEnumerable<BeatmapSetInfo> BeatmapSets
|
||||||
{
|
{
|
||||||
get { return carouselSets.Select(g => g.BeatmapSet); }
|
get { return carouselSets.Select(g => g.BeatmapSet); }
|
||||||
set
|
set
|
||||||
@ -72,7 +81,7 @@ namespace osu.Game.Screens.Select
|
|||||||
Items = root.Drawables.Value.ToList();
|
Items = root.Drawables.Value.ToList();
|
||||||
|
|
||||||
yPositionsCache.Invalidate();
|
yPositionsCache.Invalidate();
|
||||||
BeatmapsChanged?.Invoke();
|
BeatmapSetsChanged?.Invoke();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -85,17 +94,14 @@ namespace osu.Game.Screens.Select
|
|||||||
|
|
||||||
private readonly List<CarouselBeatmapSet> carouselSets = new List<CarouselBeatmapSet>();
|
private readonly List<CarouselBeatmapSet> carouselSets = new List<CarouselBeatmapSet>();
|
||||||
|
|
||||||
private Bindable<RandomSelectAlgorithm> randomSelectAlgorithm;
|
public Bindable<RandomSelectAlgorithm> RandomAlgorithm = new Bindable<RandomSelectAlgorithm>();
|
||||||
private readonly List<CarouselBeatmapSet> seenSets = new List<CarouselBeatmapSet>();
|
private readonly List<CarouselBeatmapSet> previouslyVisitedRandomSets = new List<CarouselBeatmapSet>();
|
||||||
|
|
||||||
protected List<DrawableCarouselItem> Items = new List<DrawableCarouselItem>();
|
protected List<DrawableCarouselItem> Items = new List<DrawableCarouselItem>();
|
||||||
private CarouselGroup root = new CarouselGroup();
|
private CarouselGroup root = new CarouselGroup();
|
||||||
|
|
||||||
private readonly Stack<CarouselBeatmap> randomSelectedBeatmaps = new Stack<CarouselBeatmap>();
|
private readonly Stack<CarouselBeatmap> randomSelectedBeatmaps = new Stack<CarouselBeatmap>();
|
||||||
|
|
||||||
private CarouselBeatmap selectedBeatmap;
|
|
||||||
private CarouselBeatmapSet selectedBeatmapSet => carouselSets.FirstOrDefault(s => s.State == CarouselItemState.Selected);
|
|
||||||
|
|
||||||
public BeatmapCarousel()
|
public BeatmapCarousel()
|
||||||
{
|
{
|
||||||
Add(new OsuContextMenuContainer
|
Add(new OsuContextMenuContainer
|
||||||
@ -173,12 +179,6 @@ namespace osu.Game.Screens.Select
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void selectNullBeatmap()
|
|
||||||
{
|
|
||||||
selectedBeatmap = null;
|
|
||||||
SelectionChanged?.Invoke(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Increment selection in the carousel in a chosen direction.
|
/// Increment selection in the carousel in a chosen direction.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -187,9 +187,9 @@ namespace osu.Game.Screens.Select
|
|||||||
public void SelectNext(int direction = 1, bool skipDifficulties = true)
|
public void SelectNext(int direction = 1, bool skipDifficulties = true)
|
||||||
{
|
{
|
||||||
// todo: we may want to refactor and remove this as an optimisation in the future.
|
// todo: we may want to refactor and remove this as an optimisation in the future.
|
||||||
if (carouselSets.All(g => g.State == CarouselItemState.Hidden))
|
if (carouselSets.All(g => !g.Visible))
|
||||||
{
|
{
|
||||||
selectNullBeatmap();
|
SelectionChanged?.Invoke(null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -218,53 +218,57 @@ namespace osu.Game.Screens.Select
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<CarouselBeatmapSet> getVisibleGroups() => carouselSets.Where(select => select.State != CarouselItemState.NotSelected);
|
private IEnumerable<CarouselBeatmapSet> getVisibleSets() => carouselSets.Where(select => select.Visible);
|
||||||
|
|
||||||
public void SelectNextRandom()
|
public void SelectNextRandom()
|
||||||
{
|
{
|
||||||
if (carouselSets.Count == 0)
|
if (carouselSets.Count == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var visibleGroups = getVisibleGroups();
|
var visible = getVisibleSets().ToList();
|
||||||
if (!visibleGroups.Any())
|
if (!visible.Any())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (selectedBeatmap != null)
|
if (selectedBeatmap != null)
|
||||||
|
{
|
||||||
randomSelectedBeatmaps.Push(selectedBeatmap);
|
randomSelectedBeatmaps.Push(selectedBeatmap);
|
||||||
|
|
||||||
CarouselBeatmapSet group;
|
// when performing a random, we want to add the current set to the previously visited list
|
||||||
|
// else the user may be "randomised" to the existing selection.
|
||||||
|
if (previouslyVisitedRandomSets.LastOrDefault() != selectedBeatmapSet)
|
||||||
|
previouslyVisitedRandomSets.Add(selectedBeatmapSet);
|
||||||
|
}
|
||||||
|
|
||||||
if (randomSelectAlgorithm == RandomSelectAlgorithm.RandomPermutation)
|
CarouselBeatmapSet set;
|
||||||
|
|
||||||
|
if (RandomAlgorithm == RandomSelectAlgorithm.RandomPermutation)
|
||||||
{
|
{
|
||||||
var notSeenGroups = visibleGroups.Except(seenSets);
|
var notYetVisitedSets = visible.Except(previouslyVisitedRandomSets).ToList();
|
||||||
if (!notSeenGroups.Any())
|
if (!notYetVisitedSets.Any())
|
||||||
{
|
{
|
||||||
seenSets.Clear();
|
previouslyVisitedRandomSets.Clear();
|
||||||
notSeenGroups = visibleGroups;
|
notYetVisitedSets = visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
group = notSeenGroups.ElementAt(RNG.Next(notSeenGroups.Count()));
|
set = notYetVisitedSets.ElementAt(RNG.Next(notYetVisitedSets.Count()));
|
||||||
seenSets.Add(group);
|
previouslyVisitedRandomSets.Add(set);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
group = visibleGroups.ElementAt(RNG.Next(visibleGroups.Count()));
|
set = visible.ElementAt(RNG.Next(visible.Count()));
|
||||||
|
|
||||||
CarouselBeatmap item = group.Beatmaps[RNG.Next(group.Beatmaps.Count)];
|
select(set.Beatmaps[RNG.Next(set.Beatmaps.Count)]);
|
||||||
|
|
||||||
select(item);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SelectPreviousRandom()
|
public void SelectPreviousRandom()
|
||||||
{
|
{
|
||||||
if (!randomSelectedBeatmaps.Any())
|
|
||||||
return;
|
|
||||||
|
|
||||||
while (randomSelectedBeatmaps.Any())
|
while (randomSelectedBeatmaps.Any())
|
||||||
{
|
{
|
||||||
var beatmap = randomSelectedBeatmaps.Pop();
|
var beatmap = randomSelectedBeatmaps.Pop();
|
||||||
|
|
||||||
if (beatmap.Visible)
|
if (!beatmap.Filtered)
|
||||||
{
|
{
|
||||||
|
if (RandomAlgorithm == RandomSelectAlgorithm.RandomPermutation)
|
||||||
|
previouslyVisitedRandomSets.Remove(selectedBeatmapSet);
|
||||||
select(beatmap);
|
select(beatmap);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -351,7 +355,6 @@ namespace osu.Game.Screens.Select
|
|||||||
{
|
{
|
||||||
if (v == CarouselItemState.Selected)
|
if (v == CarouselItemState.Selected)
|
||||||
{
|
{
|
||||||
selectedBeatmap = c;
|
|
||||||
SelectionChanged?.Invoke(c.Beatmap);
|
SelectionChanged?.Invoke(c.Beatmap);
|
||||||
yPositionsCache.Invalidate();
|
yPositionsCache.Invalidate();
|
||||||
Schedule(() => ScrollToSelected());
|
Schedule(() => ScrollToSelected());
|
||||||
@ -365,7 +368,7 @@ namespace osu.Game.Screens.Select
|
|||||||
[BackgroundDependencyLoader(permitNulls: true)]
|
[BackgroundDependencyLoader(permitNulls: true)]
|
||||||
private void load(OsuConfigManager config)
|
private void load(OsuConfigManager config)
|
||||||
{
|
{
|
||||||
randomSelectAlgorithm = config.GetBindable<RandomSelectAlgorithm>(OsuSetting.RandomSelectAlgorithm);
|
config.BindWith(OsuSetting.RandomSelectAlgorithm, RandomAlgorithm);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeBeatmapSet(CarouselBeatmapSet set)
|
private void removeBeatmapSet(CarouselBeatmapSet set)
|
||||||
|
@ -113,7 +113,7 @@ namespace osu.Game.Screens.Select
|
|||||||
Anchor = Anchor.CentreRight,
|
Anchor = Anchor.CentreRight,
|
||||||
Origin = Anchor.CentreRight,
|
Origin = Anchor.CentreRight,
|
||||||
SelectionChanged = carouselSelectionChanged,
|
SelectionChanged = carouselSelectionChanged,
|
||||||
BeatmapsChanged = carouselBeatmapsLoaded,
|
BeatmapSetsChanged = carouselBeatmapsLoaded,
|
||||||
},
|
},
|
||||||
FilterControl = new FilterControl
|
FilterControl = new FilterControl
|
||||||
{
|
{
|
||||||
@ -193,7 +193,7 @@ namespace osu.Game.Screens.Select
|
|||||||
|
|
||||||
initialAddSetsTask = new CancellationTokenSource();
|
initialAddSetsTask = new CancellationTokenSource();
|
||||||
|
|
||||||
carousel.Beatmaps = this.beatmaps.GetAllUsableBeatmapSets();
|
carousel.BeatmapSets = this.beatmaps.GetAllUsableBeatmapSets();
|
||||||
|
|
||||||
Beatmap.ValueChanged += beatmap_ValueChanged;
|
Beatmap.ValueChanged += beatmap_ValueChanged;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user