@@ -8,10 +8,10 @@ import kotlin.math.pow
8
8
object Countables {
9
9
10
10
fun getCountableAmount (countable : String , stateForConditionals : StateForConditionals ): Int? {
11
- if (! countable.contains( ' [ ' ) && ! countable.contains( ' ] ' )) {
12
- return simpleCountableAmount (countable, stateForConditionals)
11
+ if (isExpression( countable)) {
12
+ return evaluateExpression (countable, stateForConditionals)
13
13
}
14
- return evaluateExpression (countable, stateForConditionals)
14
+ return simpleCountableAmount (countable, stateForConditionals)
15
15
}
16
16
17
17
private fun simpleCountableAmount (countable : String , stateForConditionals : StateForConditionals ): Int? {
@@ -30,29 +30,54 @@ object Countables {
30
30
if (countable == " Cities" ) return civInfo.cities.size
31
31
32
32
val placeholderParameters = countable.getPlaceholderParameters()
33
- if (countable.equalsPlaceholderText(" [] Cities" ))
34
- return civInfo.cities.count { it.matchesFilter(placeholderParameters[0 ]) }
33
+ if (countable.equalsPlaceholderText(" [] Cities" )) {
34
+ val filter = placeholderParameters[0 ]
35
+ return civInfo.cities.count { it.matchesFilter(filter) }
36
+ }
35
37
36
38
if (countable == " Units" ) return civInfo.units.getCivUnitsSize()
37
- if (countable.equalsPlaceholderText(" [] Units" ))
38
- return civInfo.units.getCivUnits().count { it.matchesFilter(placeholderParameters[0 ]) }
39
+ if (countable.equalsPlaceholderText(" [] Units" )) {
40
+ val filter = placeholderParameters[0 ]
41
+ return civInfo.units.getCivUnits().count { it.matchesFilter(filter) }
42
+ }
39
43
40
- if (countable.equalsPlaceholderText(" [] Buildings" ))
41
- return civInfo.cities.sumOf { it.cityConstructions.getBuiltBuildings()
42
- .count { it.matchesFilter(placeholderParameters[0 ]) } }
44
+ if (countable.equalsPlaceholderText(" [] Buildings" )) {
45
+ val filter = placeholderParameters[0 ]
46
+ var totalBuildings = 0
47
+ for (city in civInfo.cities) {
48
+ val builtBuildings = city.cityConstructions.getBuiltBuildings()
49
+ totalBuildings + = builtBuildings.count { it.matchesFilter(filter) }
50
+ }
51
+ return totalBuildings
52
+ }
43
53
44
- if (countable.equalsPlaceholderText(" Remaining [] Civilizations" ))
45
- return gameInfo.civilizations.filter { ! it.isDefeated() }
46
- .count { it.matchesFilter(placeholderParameters[0 ]) }
54
+ if (countable.equalsPlaceholderText(" Remaining [] Civilizations" )) {
55
+ val filter = placeholderParameters[0 ]
56
+ var remainingCivs = 0
57
+ for (civ in gameInfo.civilizations) {
58
+ if (! civ.isDefeated() && civ.matchesFilter(filter)) {
59
+ remainingCivs++
60
+ }
61
+ }
62
+ return remainingCivs
63
+ }
47
64
48
- if (countable.equalsPlaceholderText(" Completed Policy branches" ))
65
+ if (countable.equalsPlaceholderText(" Completed Policy branches" )) {
49
66
return civInfo.getCompletedPolicyBranchesCount()
67
+ }
50
68
51
- if (countable.equalsPlaceholderText(" Owned [] Tiles" ))
52
- return civInfo.cities.sumOf { it.getTiles().count { it.matchesFilter(placeholderParameters[0 ]) } }
69
+ if (countable.equalsPlaceholderText(" Owned [] Tiles" )) {
70
+ val filter = placeholderParameters[0 ]
71
+ var totalTiles = 0
72
+ for (city in civInfo.cities) {
73
+ totalTiles + = city.getTiles().count { it.matchesFilter(filter) }
74
+ }
75
+ return totalTiles
76
+ }
53
77
54
- if (gameInfo.ruleset.tileResources.containsKey(countable))
78
+ if (gameInfo.ruleset.tileResources.containsKey(countable)) {
55
79
return stateForConditionals.getResourceAmount(countable)
80
+ }
56
81
57
82
return null
58
83
}
@@ -65,15 +90,22 @@ object Countables {
65
90
}
66
91
67
92
private fun parseExpression (expression : String ): List <String > {
68
- val regex = Regex (" ([+\\ -*/%^()]|\\ [[^]]+]|\\ b\\ w+\\ b)" )
93
+ val regex = Regex (
94
+ " (?:^|(?<=]))\\ s*(\\ [[^\\ [\\ ]]*(?:\\ [[^\\ [\\ ]]*][^\\ [\\ ]]*)*])|([+\\ -*/%^()])|(\\ d+)"
95
+ )
69
96
val matches = regex.findAll(expression)
70
97
val tokens = mutableListOf<String >()
71
98
for (match in matches) {
72
- tokens.add(match.value)
99
+ val token = match.groups.asSequence()
100
+ .filter { it != null && it.value.isNotEmpty() }
101
+ .firstOrNull()?.value
102
+ ?.trim()
103
+ if (! token.isNullOrEmpty()) {
104
+ tokens.add(token)
105
+ }
73
106
}
74
107
return tokens
75
108
}
76
-
77
109
private fun calculateExpression (tokens : List <String >, stateForConditionals : StateForConditionals ): Int? {
78
110
val outputQueue = mutableListOf<String >()
79
111
val operatorStack = mutableListOf<String >()
@@ -83,7 +115,7 @@ object Countables {
83
115
outputQueue.add(token)
84
116
} else if (token.startsWith(" [" ) && token.endsWith(" ]" )) {
85
117
val innerToken = token.substring(1 , token.length - 1 )
86
- val value = getCountableAmount (innerToken, stateForConditionals)
118
+ val value = simpleCountableAmount (innerToken, stateForConditionals)
87
119
if (value == null ) return null
88
120
outputQueue.add(value.toString())
89
121
} else if (token == " (" ) {
@@ -105,6 +137,7 @@ object Countables {
105
137
}
106
138
}
107
139
140
+
108
141
while (operatorStack.isNotEmpty()) {
109
142
outputQueue.add(operatorStack.removeLast())
110
143
}
@@ -122,8 +155,8 @@ object Countables {
122
155
" +" -> a + b
123
156
" -" -> a - b
124
157
" *" -> a * b
125
- " /" -> if (b == 0 ) return null else a / b
126
- " %" -> if (b == 0 ) return null else a % b
158
+ " /" -> if (b == 0 ) return 0 else a / b
159
+ " %" -> if (b == 0 ) return 0 else a % b
127
160
" ^" -> a.toDouble().pow(b.toDouble()).toInt()
128
161
else -> return null
129
162
}
@@ -150,4 +183,10 @@ object Countables {
150
183
else -> 0
151
184
}
152
185
}
186
+
187
+ private fun isExpression (countable : String ): Boolean {
188
+ return countable.contains(' ' ) || countable.contains(' +' ) || countable.contains(' -' ) ||
189
+ countable.contains(' *' ) || countable.contains(' /' ) || countable.contains(' %' ) ||
190
+ countable.contains(' ^' ) || countable.contains(' (' ) || countable.contains(' )' )
191
+ }
153
192
}
0 commit comments