/*
* opsu! - an open-source osu! client
* Copyright (C) 2014, 2015 Jeffrey Han
*
* opsu! is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* opsu! is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with opsu!. If not, see .
*/
package itdelatrisu.opsu.beatmap;
import itdelatrisu.opsu.GameMod;
import java.util.ArrayList;
import java.util.concurrent.TimeUnit;
/**
* Data type containing all beatmaps in a beatmap set.
*/
public class BeatmapSet {
/** List of associated beatmaps. */
private ArrayList beatmaps;
/**
* Constructor.
* @param beatmaps the beatmaps in this set
*/
public BeatmapSet(ArrayList beatmaps) {
this.beatmaps = beatmaps;
}
/**
* Returns the number of elements.
*/
public int size() { return beatmaps.size(); }
/**
* Returns the beatmap at the given index.
* @param index the beatmap index
* @throws IndexOutOfBoundsException
*/
public Beatmap get(int index) { return beatmaps.get(index); }
/**
* Removes the beatmap at the given index.
* @param index the beatmap index
* @return the removed beatmap
* @throws IndexOutOfBoundsException
*/
public Beatmap remove(int index) { return beatmaps.remove(index); }
/**
* Returns an array of strings containing beatmap information.
*
* - 0: {Artist} - {Title} [{Version}]
*
- 1: Mapped by {Creator}
*
- 2: Length: {} BPM: {} Objects: {}
*
- 3: Circles: {} Sliders: {} Spinners: {}
*
- 4: CS:{} HP:{} AR:{} OD:{}
*
* @param index the beatmap index
* @throws IndexOutOfBoundsException
*/
public String[] getInfo(int index) {
Beatmap beatmap = beatmaps.get(index);
float speedModifier = GameMod.getSpeedMultiplier();
long endTime = (long) (beatmap.endTime / speedModifier);
int bpmMin = (int) (beatmap.bpmMin * speedModifier);
int bpmMax = (int) (beatmap.bpmMax * speedModifier);
float multiplier = GameMod.getDifficultyMultiplier();
String[] info = new String[5];
info[0] = beatmap.toString();
info[1] = String.format("Mapped by %s", beatmap.creator);
info[2] = String.format("Length: %d:%02d BPM: %s Objects: %d",
TimeUnit.MILLISECONDS.toMinutes(endTime),
TimeUnit.MILLISECONDS.toSeconds(endTime) -
TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(endTime)),
(bpmMax <= 0) ? "--" : ((bpmMin == bpmMax) ? bpmMin : String.format("%d-%d", bpmMin, bpmMax)),
(beatmap.hitObjectCircle + beatmap.hitObjectSlider + beatmap.hitObjectSpinner));
info[3] = String.format("Circles: %d Sliders: %d Spinners: %d",
beatmap.hitObjectCircle, beatmap.hitObjectSlider, beatmap.hitObjectSpinner);
info[4] = String.format("CS:%.1f HP:%.1f AR:%.1f OD:%.1f%s",
Math.min(beatmap.circleSize * multiplier, 10f),
Math.min(beatmap.HPDrainRate * multiplier, 10f),
Math.min(beatmap.approachRate * multiplier, 10f),
Math.min(beatmap.overallDifficulty * multiplier, 10f),
(beatmap.starRating >= 0) ? String.format(" Stars: %.2f", beatmap.starRating) : "");
return info;
}
/**
* Returns a formatted string for the beatmap set:
* "Artist - Title"
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
Beatmap beatmap = beatmaps.get(0);
return String.format("%s - %s", beatmap.getArtist(), beatmap.getTitle());
}
/**
* Checks whether the beatmap set matches a given search query.
* @param query the search term
* @return true if title, artist, creator, source, version, or tag matches query
*/
public boolean matches(String query) {
// search: title, artist, creator, source, version, tags (first beatmap)
Beatmap beatmap = beatmaps.get(0);
if (beatmap.title.toLowerCase().contains(query) ||
beatmap.titleUnicode.toLowerCase().contains(query) ||
beatmap.artist.toLowerCase().contains(query) ||
beatmap.artistUnicode.toLowerCase().contains(query) ||
beatmap.creator.toLowerCase().contains(query) ||
beatmap.source.toLowerCase().contains(query) ||
beatmap.version.toLowerCase().contains(query) ||
beatmap.tags.contains(query))
return true;
// search: version, tags (remaining beatmaps)
for (int i = 1; i < beatmaps.size(); i++) {
beatmap = beatmaps.get(i);
if (beatmap.version.toLowerCase().contains(query) ||
beatmap.tags.contains(query))
return true;
}
return false;
}
/**
* Checks whether the beatmap set matches a given condition.
* @param type the condition type (ar, cs, od, hp, bpm, length)
* @param operator the operator {@literal (=/==, >, >=, <, <=)}
* @param value the value
* @return true if the condition is met
*/
public boolean matches(String type, String operator, float value) {
for (Beatmap beatmap : beatmaps) {
// get value
float v;
switch (type) {
case "ar": v = beatmap.approachRate; break;
case "cs": v = beatmap.circleSize; break;
case "od": v = beatmap.overallDifficulty; break;
case "hp": v = beatmap.HPDrainRate; break;
case "bpm": v = beatmap.bpmMax; break;
case "length": v = beatmap.endTime / 1000; break;
case "star":
case "stars": v = Math.round(beatmap.starRating * 100) / 100f; break;
default: return false;
}
// get operator
boolean met;
switch (operator) {
case "=":
case "==": met = (v == value); break;
case ">": met = (v > value); break;
case ">=": met = (v >= value); break;
case "<": met = (v < value); break;
case "<=": met = (v <= value); break;
default: return false;
}
if (met)
return true;
}
return false;
}
}