Skip to content

Commit

Permalink
Add support for indexed variables to filters
Browse files Browse the repository at this point in the history
Signed-off-by: Pablo Herrera <[email protected]>
  • Loading branch information
Pablete1234 committed Nov 17, 2023
1 parent fea7b43 commit ddae580
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 52 deletions.
Original file line number Diff line number Diff line change
@@ -1,31 +1,58 @@
package tc.oc.pgm.filters.matcher.match;

import com.google.common.collect.Range;
import tc.oc.pgm.api.filter.FilterDefinition;
import tc.oc.pgm.api.filter.Filterables;
import tc.oc.pgm.api.filter.query.MatchQuery;
import tc.oc.pgm.api.filter.query.PartyQuery;
import tc.oc.pgm.api.filter.query.Query;
import tc.oc.pgm.api.party.Competitor;
import tc.oc.pgm.api.party.Party;
import tc.oc.pgm.filters.Filterable;
import tc.oc.pgm.filters.matcher.WeakTypedFilter;
import tc.oc.pgm.filters.matcher.party.CompetitorFilter;
import tc.oc.pgm.util.xml.InvalidXMLException;
import tc.oc.pgm.util.xml.Node;
import tc.oc.pgm.variables.Variable;
import tc.oc.pgm.variables.VariableDefinition;
import tc.oc.pgm.variables.types.IndexedVariable;

public class VariableFilter implements FilterDefinition {
public abstract class VariableFilter<Q extends MatchQuery> implements WeakTypedFilter<Q> {

private final VariableDefinition<?> variable;
private final Range<Double> values;

public VariableFilter(VariableDefinition<?> variable, Range<Double> values) {
private VariableFilter(VariableDefinition<?> variable, Range<Double> values) {
this.variable = variable;
this.values = values;
}

public static VariableFilter<?> of(
VariableDefinition<?> var, Integer idx, Range<Double> range, Node node)
throws InvalidXMLException {
if (var.isIndexed()) {
if (idx == null)
throw new InvalidXMLException("Array variables must contain an index.", node);
return var.getScope() == Party.class
? new TeamIndexed(var, idx, range)
: new Indexed(var, idx, range);
} else {
if (idx != null)
throw new InvalidXMLException("Non-array variables cannot contain an index.", node);
return var.getScope() == Party.class ? new Team(var, range) : new Generic(var, range);
}
}

@Override
public QueryResponse query(Query query) {
Filterable<?> filterable =
query instanceof MatchQuery ? ((MatchQuery) query).extractFilterable() : null;
public QueryResponse queryTyped(Q query) {
Filterable<?> filterable = query.extractFilterable();
if (!Filterables.isAssignable(filterable, variable.getScope())) return QueryResponse.ABSTAIN;

return QueryResponse.fromBoolean(
values.contains(variable.getVariable(filterable.getMatch()).getValue(filterable)));
values.contains(getValue(variable.getVariable(filterable.getMatch()), filterable)));
}

protected double getValue(Variable<?> variable, Filterable<?> filterable) {
return variable.getValue(filterable);
}

@Override
Expand All @@ -44,4 +71,64 @@ public boolean isDynamic() {
public String toString() {
return "VariableFilter{" + "variable=" + variable + ", values=" + values + '}';
}

public static class Generic extends VariableFilter<MatchQuery> {

public Generic(VariableDefinition<?> variable, Range<Double> values) {
super(variable, values);
}

@Override
public Class<? extends MatchQuery> queryType() {
return MatchQuery.class;
}
}

/**
* Specialization for team variables implementing CompetitorFilter. Allows team to be set to a
* specific one.
*/
public static class Team extends VariableFilter<PartyQuery> implements CompetitorFilter {

public Team(VariableDefinition<?> variable, Range<Double> values) {
super(variable, values);
}

@Override
public boolean matches(MatchQuery query, Competitor competitor) {
QueryResponse response = super.query(competitor);
if (!response.isPresent())
throw new UnsupportedOperationException(
"Filter " + this + " did not respond to the query " + query);
return response.isAllowed();
}
}

public static class Indexed extends Generic {
private final int idx;

public Indexed(VariableDefinition<?> variable, int idx, Range<Double> values) {
super(variable, values);
this.idx = idx;
}

@Override
protected double getValue(Variable<?> variable, Filterable<?> filterable) {
return ((IndexedVariable<?>) variable).getValue(filterable, idx);
}
}

public static class TeamIndexed extends Team {
private final int idx;

public TeamIndexed(VariableDefinition<?> variable, int idx, Range<Double> values) {
super(variable, values);
this.idx = idx;
}

@Override
protected double getValue(Variable<?> variable, Filterable<?> filterable) {
return ((IndexedVariable<?>) variable).getValue(filterable, idx);
}
}
}

This file was deleted.

21 changes: 11 additions & 10 deletions core/src/main/java/tc/oc/pgm/filters/parse/FeatureFilterParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,10 @@ public Filter parseNot(Element el) throws InvalidXMLException {

private static final Pattern INLINE_VARIABLE =
Pattern.compile(
"("
+ VariablesModule.Factory.VARIABLE_ID.pattern()
+ ")\\s*=\\s*("
+ XMLUtils.RANGE_DOTTED.pattern()
+ "|-?\\d*\\.?\\d+)");
"(%VAR%)(?:\\[(\\d+)])?\\s*=\\s*(%RANGE%|%NUM%)"
.replace("%VAR%", VariablesModule.Factory.VARIABLE_ID.pattern())
.replace("%RANGE%", XMLUtils.RANGE_DOTTED.pattern())
.replace("%NUM%", "-?\\d*\\.?\\d+"));

private @Nullable Filter parseInlineFilter(Node node, String text) throws InvalidXMLException {
// Formula-style inline filter
Expand All @@ -114,12 +113,14 @@ public Filter parseNot(Element el) throws InvalidXMLException {
}

// Parse variable filter
Matcher varMatch = INLINE_VARIABLE.matcher(text);
if (varMatch.matches()) {
Matcher match = INLINE_VARIABLE.matcher(text);
if (match.matches()) {
VariableDefinition<?> variable =
features.resolve(node, varMatch.group(1), VariableDefinition.class);
Range<Double> range = XMLUtils.parseNumericRange(node, varMatch.group(2), Double.class);
return new VariableFilter(variable, range);
features.resolve(node, match.group(1), VariableDefinition.class);
Integer index =
match.group(2) == null ? null : XMLUtils.parseNumber(node, match.group(2), Integer.class);
Range<Double> range = XMLUtils.parseNumericRange(node, match.group(3), Double.class);
return VariableFilter.of(variable, index, range, node);
}

return null;
Expand Down
12 changes: 7 additions & 5 deletions core/src/main/java/tc/oc/pgm/filters/parse/FilterParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
import tc.oc.pgm.api.filter.Filter;
import tc.oc.pgm.api.filter.FilterDefinition;
import tc.oc.pgm.api.map.factory.MapFactory;
import tc.oc.pgm.api.party.Party;
import tc.oc.pgm.api.player.PlayerRelation;
import tc.oc.pgm.api.region.Region;
import tc.oc.pgm.classes.ClassModule;
Expand Down Expand Up @@ -48,7 +47,6 @@
import tc.oc.pgm.filters.matcher.party.RankFilter;
import tc.oc.pgm.filters.matcher.party.ScoreFilter;
import tc.oc.pgm.filters.matcher.party.TeamFilter;
import tc.oc.pgm.filters.matcher.party.TeamVariableFilter;
import tc.oc.pgm.filters.matcher.player.CanFlyFilter;
import tc.oc.pgm.filters.matcher.player.CarryingFlagFilter;
import tc.oc.pgm.filters.matcher.player.CarryingItemFilter;
Expand Down Expand Up @@ -633,11 +631,15 @@ public PlayerCountFilter parsePlayerCountFilter(Element el) throws InvalidXMLExc
public Filter parseVariableFilter(Element el) throws InvalidXMLException {
VariableDefinition<?> varDef =
features.resolve(Node.fromRequiredAttr(el, "var"), VariableDefinition.class);
Integer index = null;
if (varDef.isIndexed())
index = XMLUtils.parseNumber(Node.fromRequiredAttr(el, "index"), Integer.class);
Range<Double> range = XMLUtils.parseNumericRange(new Node(el), Double.class);

if (varDef.getScope() == Party.class)
return parseExplicitTeam(el, new TeamVariableFilter(varDef, range));
else return new VariableFilter(varDef, range);
VariableFilter<?> filter = VariableFilter.of(varDef, index, range, new Node(el));
return filter instanceof CompetitorFilter
? parseExplicitTeam(el, (CompetitorFilter) filter)
: filter;
}

@MethodParser("blocks")
Expand Down

0 comments on commit ddae580

Please sign in to comment.