summaryrefslogtreecommitdiff
path: root/BJC-Utils2/src/main/java/bjc/utils/dice/ast/DiceASTExpression.java
blob: 3b81888777a0f0e8054fca0d538ce52488fea2e8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
package bjc.utils.dice.ast;

import java.util.HashMap;
import java.util.Map;
import java.util.function.BinaryOperator;

import org.apache.commons.lang3.StringUtils;

import bjc.utils.data.Pair;
import bjc.utils.dice.ComplexDice;
import bjc.utils.dice.CompoundDice;
import bjc.utils.dice.IDiceExpression;
import bjc.utils.parserutils.AST;

public class DiceASTExpression implements IDiceExpression {
	private AST<IDiceASTNode>				ast;
	private Map<String, DiceASTExpression>	env;

	public DiceASTExpression(AST<IDiceASTNode> ast,
			Map<String, DiceASTExpression> env) {
		this.ast = ast;
		this.env = env;
	}

	private Pair<Integer, AST<IDiceASTNode>> evalLeaf(IDiceASTNode tokn) {
		if (tokn instanceof VariableDiceNode) {
			String varName = ((VariableDiceNode) tokn).getVariable();
			
			if (env.containsKey(varName)) {
				return new Pair<>(env.get(varName).roll(), new AST<>(tokn));
			} else {
				// Handle special case for defining variables
				return new Pair<>(0, new AST<>(tokn));
			}
		} else {
			LiteralDiceNode lnod = (LiteralDiceNode) tokn;
			String dat = lnod.getData();

			if (StringUtils.countMatches(dat, 'c') == 1
					&& !dat.equalsIgnoreCase("c")) {
				String[] strangs = dat.split("c");
				return new Pair<>(new CompoundDice(strangs).roll(),
						new AST<>(tokn));
			} else if (StringUtils.countMatches(dat, 'd') == 1
					&& !dat.equalsIgnoreCase("d")) {
				/*
				 * Handle dice groups
				 */
				return new Pair<>(ComplexDice.fromString(dat).roll(),
						new AST<>(tokn));
			} else {
				return new Pair<>(Integer.parseInt(dat), new AST<>(tokn));
			}
		}
	}

	private static
			Map<IDiceASTNode, BinaryOperator<Pair<Integer, AST<IDiceASTNode>>>>
			buildOperations(Map<String, DiceASTExpression> env) {
		Map<IDiceASTNode, BinaryOperator<Pair<Integer, AST<IDiceASTNode>>>> opCollapsers =
				new HashMap<>();

		opCollapsers.put(OperatorDiceNode.ADD, (left, right) -> {
			return left.merge((lval, last) -> right.merge((rval, rast) -> {
				return new Pair<>(lval + rval,
						new AST<>(OperatorDiceNode.ADD, last, rast));
			}));

		});
		opCollapsers.put(OperatorDiceNode.SUBTRACT, (left, right) -> {
			return left.merge((lval, last) -> right.merge((rval, rast) -> {
				return new Pair<>(lval - rval,
						new AST<>(OperatorDiceNode.SUBTRACT, last, rast));
			}));

		});
		opCollapsers.put(OperatorDiceNode.MULTIPLY, (left, right) -> {
			return left.merge((lval, last) -> right.merge((rval, rast) -> {
				return new Pair<>(lval * rval,
						new AST<>(OperatorDiceNode.MULTIPLY, last, rast));
			}));

		});
		opCollapsers.put(OperatorDiceNode.DIVIDE, (left, right) -> {
			return left.merge((lval, last) -> right.merge((rval, rast) -> {
				return new Pair<>(lval / rval,
						new AST<>(OperatorDiceNode.DIVIDE, last, rast));
			}));
		});

		opCollapsers.put(OperatorDiceNode.ASSIGN, (left, right) -> {
			return left.merge((lval, last) -> right.merge((rval, rast) -> {
				String nam = last.collapse((nod) -> {
					return ((VariableDiceNode) nod).getVariable();
				} , (v) -> (lv, rv) -> null, (r) -> r);

				env.put(nam, new DiceASTExpression(rast, env));

				return new Pair<>(rval,
						new AST<>(OperatorDiceNode.ASSIGN, last, rast));
			}));
		});

		opCollapsers.put(OperatorDiceNode.COMPOUND, (left, right) -> {
			return left.merge((lval, last) -> right.merge((rval, rast) -> {
				int ival = Integer.parseInt(
						Integer.toString(lval) + Integer.toString(rval));

				return new Pair<>(ival,
						new AST<>(OperatorDiceNode.COMPOUND, last, rast));
			}));
		});
		opCollapsers.put(OperatorDiceNode.GROUP, (left, right) -> {
			return left.merge((lval, last) -> right.merge((rval, rast) -> {

				return new Pair<>(new ComplexDice(lval, rval).roll(),
						new AST<>(OperatorDiceNode.GROUP, last, rast));
			}));
		});

		return opCollapsers;
	}

	@Override
	public int roll() {
		Map<IDiceASTNode, BinaryOperator<Pair<Integer, AST<IDiceASTNode>>>> operations =
				buildOperations(env);

		return ast.collapse(this::evalLeaf, operations::get,
				(r) -> r.merge((left, right) -> left));
	}

	@Override
	public String toString() {
		return ast.toString();
	}

	/**
	 * @return the ast
	 */
	public AST<IDiceASTNode> getAst() {
		return ast;
	}
}