Added support for conditional search expressions.
- Pattern: {type}{operator}{value} -- Types: ar, cs, od, hp, bpm (length not yet implemented) -- Operators: =/==, >, >=, <, <= Signed-off-by: Jeffrey Han <itdelatrisu@gmail.com>
This commit is contained in:
parent
0a5e7f66ec
commit
4ecd50f488
|
@ -19,8 +19,12 @@
|
|||
package itdelatrisu.opsu;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Indexed, expanding, doubly-linked list data type for song groups.
|
||||
|
@ -43,6 +47,13 @@ public class OsuGroupList {
|
|||
"Title", "Artist", "Creator", "BPM"
|
||||
};
|
||||
|
||||
/**
|
||||
* Search pattern for conditional expressions.
|
||||
*/
|
||||
private static final Pattern SEARCH_CONDITION_PATTERN = Pattern.compile(
|
||||
"(ar|cs|od|hp|bpm|length)(=|==|>|>=|<|<=)((\\d*\\.)?\\d+)"
|
||||
);
|
||||
|
||||
/**
|
||||
* List containing all parsed nodes.
|
||||
*/
|
||||
|
@ -261,30 +272,82 @@ public class OsuGroupList {
|
|||
if (lastQuery != null && query.equals(lastQuery))
|
||||
return false;
|
||||
lastQuery = query;
|
||||
String[] terms = query.split("\\s+");
|
||||
LinkedList<String> terms = new LinkedList<String>(Arrays.asList(query.split("\\s+")));
|
||||
|
||||
// if empty query, reset to original list
|
||||
if (query.isEmpty() || terms.length < 1) {
|
||||
if (query.isEmpty() || terms.isEmpty()) {
|
||||
nodes = parsedNodes;
|
||||
return true;
|
||||
}
|
||||
|
||||
// build list from first search term
|
||||
nodes = new ArrayList<OsuGroupNode>();
|
||||
for (OsuGroupNode node : parsedNodes) {
|
||||
if (node.matches(terms[0])) {
|
||||
nodes.add(node);
|
||||
continue;
|
||||
// find and remove any conditional search terms
|
||||
LinkedList<String> condType = new LinkedList<String>();
|
||||
LinkedList<String> condOperator = new LinkedList<String>();
|
||||
LinkedList<Float> condValue = new LinkedList<Float>();
|
||||
|
||||
Iterator<String> termIter = terms.iterator();
|
||||
while (termIter.hasNext()) {
|
||||
String term = termIter.next();
|
||||
Matcher m = SEARCH_CONDITION_PATTERN.matcher(term);
|
||||
if (m.find()) {
|
||||
condType.add(m.group(1));
|
||||
condOperator.add(m.group(2));
|
||||
condValue.add(Float.parseFloat(m.group(3)));
|
||||
termIter.remove();
|
||||
}
|
||||
}
|
||||
|
||||
// remove nodes from list if they don't match all remaining terms
|
||||
for (int i = 1; i < terms.length; i++) {
|
||||
Iterator<OsuGroupNode> iter = nodes.iterator();
|
||||
while (iter.hasNext()) {
|
||||
OsuGroupNode node = iter.next();
|
||||
if (!node.matches(terms[i]))
|
||||
iter.remove();
|
||||
// build an initial list from first search term
|
||||
nodes = new ArrayList<OsuGroupNode>();
|
||||
if (terms.isEmpty()) {
|
||||
// conditional term
|
||||
String type = condType.remove();
|
||||
String operator = condOperator.remove();
|
||||
float value = condValue.remove();
|
||||
for (OsuGroupNode node : parsedNodes) {
|
||||
if (node.matches(type, operator, value))
|
||||
nodes.add(node);
|
||||
}
|
||||
} else {
|
||||
// normal term
|
||||
String term = terms.remove();
|
||||
for (OsuGroupNode node : parsedNodes) {
|
||||
if (node.matches(term))
|
||||
nodes.add(node);
|
||||
}
|
||||
}
|
||||
|
||||
// iterate through remaining normal search terms
|
||||
while (!terms.isEmpty()) {
|
||||
if (nodes.isEmpty())
|
||||
return true;
|
||||
|
||||
String term = terms.remove();
|
||||
|
||||
// remove nodes from list if they don't match all terms
|
||||
Iterator<OsuGroupNode> nodeIter = nodes.iterator();
|
||||
while (nodeIter.hasNext()) {
|
||||
OsuGroupNode node = nodeIter.next();
|
||||
if (!node.matches(term))
|
||||
nodeIter.remove();
|
||||
}
|
||||
}
|
||||
|
||||
// iterate through remaining conditional terms
|
||||
while (!condType.isEmpty()) {
|
||||
if (nodes.isEmpty())
|
||||
return true;
|
||||
|
||||
String type = condType.remove();
|
||||
String operator = condOperator.remove();
|
||||
float value = condValue.remove();
|
||||
|
||||
// remove nodes from list if they don't match all terms
|
||||
Iterator<OsuGroupNode> nodeIter = nodes.iterator();
|
||||
while (nodeIter.hasNext()) {
|
||||
OsuGroupNode node = nodeIter.next();
|
||||
if (!node.matches(type, operator, value))
|
||||
nodeIter.remove();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -214,4 +214,44 @@ public class OsuGroupNode implements Comparable<OsuGroupNode> {
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the node matches a given condition.
|
||||
* @param type the condition type (ar, cs, od, hp, bpm, length)
|
||||
* @param operator the operator (=/==, >, >=, <, <=)
|
||||
* @param value the value
|
||||
* @return true if the condition is met
|
||||
*/
|
||||
public boolean matches(String type, String operator, float value) {
|
||||
for (OsuFile osu : osuFiles) {
|
||||
// get value
|
||||
float osuValue;
|
||||
switch (type) {
|
||||
case "ar": osuValue = osu.approachRate; break;
|
||||
case "cs": osuValue = osu.circleSize; break;
|
||||
case "od": osuValue = osu.overallDifficulty; break;
|
||||
case "hp": osuValue = osu.HPDrainRate; break;
|
||||
case "bpm": osuValue = osu.bpmMax; break;
|
||||
// case "length": /* not implemented */ break;
|
||||
default: return false;
|
||||
}
|
||||
|
||||
// get operator
|
||||
boolean met;
|
||||
switch (operator) {
|
||||
case "=":
|
||||
case "==": met = (osuValue == value); break;
|
||||
case ">": met = (osuValue > value); break;
|
||||
case ">=": met = (osuValue >= value); break;
|
||||
case "<": met = (osuValue < value); break;
|
||||
case "<=": met = (osuValue <= value); break;
|
||||
default: return false;
|
||||
}
|
||||
|
||||
if (met)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -58,7 +58,7 @@ public class SongMenu extends BasicGameState {
|
|||
/**
|
||||
* Delay time, in milliseconds, between each search.
|
||||
*/
|
||||
private static final int SEARCH_DELAY = 300;
|
||||
private static final int SEARCH_DELAY = 500;
|
||||
|
||||
/**
|
||||
* Current start node (topmost menu entry).
|
||||
|
@ -314,7 +314,9 @@ public class SongMenu extends BasicGameState {
|
|||
else
|
||||
setFocus(Opsu.groups.getRandomNode(), -1, true);
|
||||
} else {
|
||||
searchResultString = String.format("%d matches found!", Opsu.groups.size());
|
||||
int size = Opsu.groups.size();
|
||||
searchResultString = String.format("%d match%s found!",
|
||||
size, (size == 1) ? "" : "es");
|
||||
setFocus(Opsu.groups.getRandomNode(), -1, true);
|
||||
}
|
||||
oldFocusNode = null;
|
||||
|
|
Loading…
Reference in New Issue
Block a user