Skip to content

Commit

Permalink
improve minus and sum (#98)
Browse files Browse the repository at this point in the history
* improve minus and sum
  • Loading branch information
twonirwana authored Apr 3, 2024
1 parent 848ba9e commit 50a1369
Show file tree
Hide file tree
Showing 7 changed files with 68 additions and 29 deletions.
4 changes: 2 additions & 2 deletions README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ All operators are case insensitiv.
|Greater |`<left> >? <right>` |`d6>?5` | Compare the left and the right and returns true if `<left>` is greater than `<right>` otherwise false | 9 |left |a single number | a single number
|Greater Equal |`<left> >=? <right>` |`d6>=?5` | Compare the left and the right and returns true if `<left>` is greater or equal than `<right>` otherwise false | 10 |left |a single number | a single number
| In |`<left> in <right>` |`d6 in [1/3/5]` | Returns true if every element in left is contained in right otherwise false | 11 |left |a one or more elements | one or more elements
|Sum |`<left> =` |`2d6=` |Sums the list of on the left side of the symbol |12 |left |a list of numbers |-
|Sum |`<left> =` |`2d6=` |Sums the list of on the left side of the symbol. An empty list has the sum of 0 |12 |left |a list of numbers |-
|Modulo |`<left> mod <right>` |`d6 mod 2` | returns the remainder of the division |13 |left |a single integer number |a single non zero integer number
|Multiply |`<left> * <right>` |`2 * 6` |Multiplies the right number with the left number |14|left |a single number |a single number
|Divide |`<left> / <right>` |`4 / 2` |Divides the right number with the left number and rounds down to the next full number |15 |left |a single integer number |a single integer number
Expand All @@ -90,7 +90,7 @@ All operators are case insensitiv.
|Keep Highest |`<list> k <numberToKept>` |`3d6k2` |keeps the highest values out a list, like the roll of multiple dice. Applies only to elements with the same tag. |23 |left |one or more elements |a single number
|Keep Lowest |`<list> l <numberToKept>` |`3d6l2` |keeps the lowest values out a list, like the roll of multiple dice. Applies only to elements with the same tag. |24 |left |one or more elements |a single number
|Add to List |`<left> + <right>` |`2d6 + 2` or `+3` |Combines the rolls of both sides to a single list. If used as unary operator, it will be ignored e.g. `+5` will process to `5` |25 |left for binary and right for unary |none or more elements |one or more elements
|Negative add to List |`<left> - <right>` |`2 - 1` or `-d6` |Combines the rolls of both sides to a single list. The right side is multiplied by -1. |26 |left for binary and right for unary |none or more elements |one or more numbers
|Remove or Negative add to List |`<left> - <right>` |`2 - 1` or `-d6` |Combines the rolls of both sides to a single list. If the element exists on both sides, it will be removed. If the element only exists on the right side and is a number then it will be multiplied with -1 and added |26 |left for binary and right for unary |none or more elements | numbers or elements that are also elements of the left side
|Reroll |`<expression>rr<rerollIfIn>` |`10d6rr1` | Reroll the whole `<expression>` once if any of the elements of `<expression>` are in the elements of `<rerollIfIn>` |27 |left|one or more elements|one or more elements
|Tag |`<expression>tag<text>` |`d6 tag 'special'` | Set a tag to all elements of an expression, most operator work on elements with the same tag. The tag will be appended to the name but a number remains a number, even with a text tag. |28 |left|one or more elements|a single text
|Color |`<expression>col<text>` |`d6 col 'red'` | Set a color to all elements, and all in it involved random elements, of an expression. The color will not directly given in the result and has no effect on other operations |29 |left|one or more elements|a single text
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/de/janno/evaluator/dice/DiceEvaluator.java
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public DiceEvaluator(@NonNull NumberSupplier numberSupplier, int maxNumberOfDice
.add(new Sum(maxNumberOfElements, keepChildrenRolls))
.add(new Repeat(maxNumberOfElements, keepChildrenRolls))
.add(new RepeatList(maxNumberOfElements, keepChildrenRolls))
.add(new NegateOrNegativAddToList(maxNumberOfElements, keepChildrenRolls))
.add(new NegateAddRemove(maxNumberOfElements, keepChildrenRolls))
.add(new IntegerDivide(maxNumberOfElements, keepChildrenRolls))
.add(new DecimalDivide(maxNumberOfElements, keepChildrenRolls))
.add(new Multiply(maxNumberOfElements, keepChildrenRolls))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public final class OperatorOrder {
.add(KeepLowest.class)
//dice should be first
.add(AddToList.class)
.add(NegateOrNegativAddToList.class)
.add(NegateAddRemove.class)
.add(Reroll.class)
.add(Tag.class)
.add(Color.class)
Expand Down
13 changes: 10 additions & 3 deletions src/main/java/de/janno/evaluator/dice/operator/list/Sum.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,16 @@ private static BigDecimal sumExact(List<RollElement> elements) {
Roll left = rolls.getFirst();
checkContainsOnlyDecimal(inputValue, left, "left");

ImmutableList<RollElement> res = left.getElements().stream().collect(Collectors.groupingBy(RollElement::getTag)).entrySet().stream()
.map(e -> new RollElement(sumExact(e.getValue()).stripTrailingZeros().stripTrailingZeros().toPlainString(), e.getKey(), RollElement.NO_COLOR))
.collect(ImmutableList.toImmutableList());

final ImmutableList<RollElement> res;
if (left.getElements().isEmpty()) {
res = ImmutableList.of(new RollElement("0", RollElement.NO_TAG, RollElement.NO_COLOR));
} else {
res = left.getElements().stream().collect(Collectors.groupingBy(RollElement::getTag)).entrySet().stream()
.map(e -> new RollElement(sumExact(e.getValue()).stripTrailingZeros().toPlainString(), e.getKey(), RollElement.NO_COLOR))
.collect(ImmutableList.toImmutableList());
}


return Optional.of(ImmutableList.of(new Roll(toExpression(),
res,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,17 @@
import lombok.NonNull;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.*;

import static de.janno.evaluator.dice.RollBuilder.extendAllBuilder;
import static de.janno.evaluator.dice.ValidatorUtil.checkContainsOnlyDecimal;
import static de.janno.evaluator.dice.ValidatorUtil.checkRollSize;

public final class NegateOrNegativAddToList extends Operator {
public final class NegateAddRemove extends Operator {
private final static BigDecimal MINUS_ONE = BigDecimal.valueOf(-1);

public NegateOrNegativAddToList(int maxNumberOfElements, boolean keepChildrenRolls) {
super("-", Operator.Associativity.RIGHT, OperatorOrder.getOderNumberOf(NegateOrNegativAddToList.class), Operator.Associativity.LEFT, OperatorOrder.getOderNumberOf(NegateOrNegativAddToList.class), maxNumberOfElements, keepChildrenRolls);
public NegateAddRemove(int maxNumberOfElements, boolean keepChildrenRolls) {
super("-", Operator.Associativity.RIGHT, OperatorOrder.getOderNumberOf(NegateAddRemove.class), Operator.Associativity.LEFT, OperatorOrder.getOderNumberOf(NegateAddRemove.class), maxNumberOfElements, keepChildrenRolls);
}

@Override
Expand All @@ -44,16 +42,35 @@ public NegateOrNegativAddToList(int maxNumberOfElements, boolean keepChildrenRol

Roll left = rolls.getFirst();
Roll right = rolls.get(1);
checkContainsOnlyDecimal(inputValue, right, "right");
final ImmutableList<RollElement> res = ImmutableList.<RollElement>builder()
.addAll(left.getElements())
.addAll(right.getElements().stream()
.map(e -> new RollElement(e.asDecimal().orElseThrow().multiply(MINUS_ONE).stripTrailingZeros().toPlainString(), e.getTag(), e.getColor()))
.toList()
).build();


ImmutableList.Builder<RollElement> resultBuilder = ImmutableList.builder();

List<RollElement> toRemove = new ArrayList<>(right.getElements());
for (RollElement rollElement : left.getElements()) {
Optional<RollElement> matchingElement = toRemove.stream()
.filter((r -> r.isEqualValueAndTag(rollElement)))
.findFirst();
if (matchingElement.isPresent()) {
toRemove.remove(matchingElement.get());
} else {
resultBuilder.add(rollElement);
}
}

if (toRemove.stream().anyMatch(r -> r.asDecimal().isEmpty())) {
throw new ExpressionException(String.format("'%s' requires as right input only decimals or elements that are on the left side '%s' but was '%s'",
inputValue,
left.getElements().stream().map(RollElement::getValue).toList(),
right.getElements().stream().map(RollElement::getValue).toList()));
}

resultBuilder.addAll(toRemove.stream()
.map(e -> new RollElement(e.asDecimal().orElseThrow().multiply(MINUS_ONE).stripTrailingZeros().toPlainString(), e.getTag(), e.getColor()))
.toList());

return Optional.of(ImmutableList.of(new Roll(toExpression(),
res,
resultBuilder.build(),
UniqueRandomElements.from(rolls),
ImmutableList.of(left, right),
maxNumberOfElements, keepChildrenRolls)));
Expand Down
19 changes: 17 additions & 2 deletions src/test/java/de/janno/evaluator/dice/DiceEvaluatorTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,12 @@ private static Stream<Arguments> generateStringDiceData() {
Arguments.of("+1d[a/b/c]", List.of(2), List.of("b")),
Arguments.of("1d[a/b/c]", List.of(2), List.of("b")),

//sum
Arguments.of("[1/2]=", List.of(), List.of("3")),
Arguments.of("[1/-2]=", List.of(), List.of("-1")),
Arguments.of("[]=", List.of(), List.of("0")),


//Add to List
Arguments.of("1+1", List.of(), List.of("1", "1")),
Arguments.of("1++1", List.of(), List.of("1", "1")),
Expand All @@ -220,7 +226,7 @@ private static Stream<Arguments> generateStringDiceData() {


//Add negative to List
Arguments.of("1-1", List.of(), List.of("1", "-1")),
Arguments.of("1-1", List.of(), List.of()),
Arguments.of("1--1", List.of(), List.of("1", "1")),
Arguments.of("--1", List.of(), List.of("1")),
Arguments.of("-d6", List.of(1), List.of("-1")),
Expand All @@ -237,6 +243,13 @@ private static Stream<Arguments> generateStringDiceData() {
Arguments.of("-2d6-1", List.of(2, 3), List.of("-2", "-3", "-1")),
Arguments.of("1-d6k1", List.of(2), List.of("1")),
Arguments.of("1-d6l1", List.of(2), List.of("-2")),
Arguments.of("[a/b/a]-'a'", List.of(), List.of("b", "a")),
Arguments.of("[a/b/a]-[b/a]", List.of(), List.of("a")),
Arguments.of("[a/b/a]-1", List.of(), List.of("a", "b", "a", "-1")),
Arguments.of("[1/2/1]-1", List.of(), List.of("2", "1")),
Arguments.of("[1/2/1]-[2/1]", List.of(), List.of("1")),
Arguments.of("[1/3/1]-[2/1]", List.of(), List.of("3", "1", "-2")),


Arguments.of("1d6 + 'a' + 1", List.of(3), List.of("3", "a", "1")),
Arguments.of("1d6 + [x/y] + 1", List.of(3), List.of("3", "x", "y", "1")),
Expand Down Expand Up @@ -578,6 +591,8 @@ private static Stream<Arguments> generateErrorData() {
Arguments.of("exp(1d6, 3, -1)", "'exp' requires as third argument a number between 0 and 100"),
Arguments.of("exp(1d6, 3, if('false', 1d6))", "'exp' requires a non-empty input as third argument"),
Arguments.of("exp(1d6, 3, 101)", "'exp' requires as third argument a number between 0 and 100"),
Arguments.of("1 - [a]", "'-' requires as right input only decimals or elements that are on the left side '[1]' but was '[a]'"),
Arguments.of("1 - [3/a]", "'-' requires as right input only decimals or elements that are on the left side '[1]' but was '[3, a]'"),

Arguments.of("d", "Operator d has right associativity but the right value was: empty")

Expand Down Expand Up @@ -623,7 +638,7 @@ private static Stream<Arguments> generateHasOperatorOrFunction() {
void debug() throws ExpressionException {
DiceEvaluator underTest = new DiceEvaluator(new GivenNumberSupplier(1, 2, 3, 4, 5, 6, 6, 1), 1000, 10_000, true);

List<Roll> res = underTest.evaluate("replace(exp(d[0/0/1/1/'2#'/2],2),'2#','2')");
List<Roll> res = underTest.evaluate("[]=");
System.out.println(res.size());
res.forEach(r -> System.out.println(r.getResultString()));
System.out.println(res);
Expand Down
Loading

0 comments on commit 50a1369

Please sign in to comment.