Skip to content

Commit 8cb14b3

Browse files
author
Logan Johnson
committed
Merge pull request #70 from TabletopAssistant/story/MixMaxFunctionality
Min/max functionality
2 parents d19f3f7 + 5bc44c3 commit 8cb14b3

15 files changed

+569
-0
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@
2323
- :game_die: Add support for subtraction of expressions (e.g. `d20 - 5`)
2424
[Jonathan Hoffman](https://github.com/JonathanHoffman) [#80](https://github.com/TabletopAssistant/DiceKit/pull/80)
2525

26+
- :game_die: Add min/max operations.
27+
[Logan Johnson](https://github.com/loganjohnson)
28+
[#64](https://github.com/TabletopAssistant/DiceKit/pull/63)
29+
2630
## 0.1: It Starts with a Single Die (2015-07-25)
2731

2832
- :game_die: Support rolling individual dice.

DiceKit.xcodeproj/project.pbxproj

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,14 @@
5050
53ECD0E41B5B5185002D859F /* NegationExpressionResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53ECD0E31B5B5185002D859F /* NegationExpressionResult.swift */; };
5151
53FA0EAC1B6579F300C8D3B5 /* ProbabilisticExpressionType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53FA0EAB1B6579F300C8D3B5 /* ProbabilisticExpressionType.swift */; };
5252
53FA0EAE1B657A3600C8D3B5 /* ProbabilisticExpressionType_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53FA0EAD1B657A3600C8D3B5 /* ProbabilisticExpressionType_Tests.swift */; };
53+
6E0F58C91B8D63690095087F /* MinimizationExpressionResult_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E0F58C81B8D63690095087F /* MinimizationExpressionResult_Tests.swift */; };
54+
6E0F58CB1B8D63910095087F /* MaximizationExpressionResult_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E0F58CA1B8D63910095087F /* MaximizationExpressionResult_Tests.swift */; };
55+
6E9F18901B7FCD4400AB8893 /* MinimizationExpression.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E9F188F1B7FCD4400AB8893 /* MinimizationExpression.swift */; };
56+
6E9F18921B7FCD5400AB8893 /* MaximizationExpression.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E9F18911B7FCD5400AB8893 /* MaximizationExpression.swift */; };
57+
6E9F18941B7FD16100AB8893 /* MinimizationExpression_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E9F18931B7FD16100AB8893 /* MinimizationExpression_Tests.swift */; };
58+
6E9F18961B7FD18600AB8893 /* MaximizationExpression_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E9F18951B7FD18600AB8893 /* MaximizationExpression_Tests.swift */; };
59+
6E9F18981B7FDF0D00AB8893 /* MinimizationExpressionResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E9F18971B7FDF0D00AB8893 /* MinimizationExpressionResult.swift */; };
60+
6E9F189C1B7FDFF900AB8893 /* MaximizationExpressionResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6E9F189B1B7FDFF900AB8893 /* MaximizationExpressionResult.swift */; };
5361
8B4C14021B7F8B47008AC355 /* SubtractionExpression.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B4C14011B7F8B47008AC355 /* SubtractionExpression.swift */; };
5462
8B4C14041B7FA8A2008AC355 /* SubtractionExpressionResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B4C14031B7FA8A2008AC355 /* SubtractionExpressionResult.swift */; };
5563
8BFAA9F91B7ED8E800EF65AE /* SubtractionExpression_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8BFAA9F81B7ED8E800EF65AE /* SubtractionExpression_Tests.swift */; };
@@ -131,6 +139,14 @@
131139
53ECD0E31B5B5185002D859F /* NegationExpressionResult.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NegationExpressionResult.swift; sourceTree = "<group>"; };
132140
53FA0EAB1B6579F300C8D3B5 /* ProbabilisticExpressionType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProbabilisticExpressionType.swift; sourceTree = "<group>"; };
133141
53FA0EAD1B657A3600C8D3B5 /* ProbabilisticExpressionType_Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProbabilisticExpressionType_Tests.swift; sourceTree = "<group>"; };
142+
6E0F58C81B8D63690095087F /* MinimizationExpressionResult_Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MinimizationExpressionResult_Tests.swift; sourceTree = "<group>"; };
143+
6E0F58CA1B8D63910095087F /* MaximizationExpressionResult_Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MaximizationExpressionResult_Tests.swift; sourceTree = "<group>"; };
144+
6E9F188F1B7FCD4400AB8893 /* MinimizationExpression.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MinimizationExpression.swift; sourceTree = "<group>"; };
145+
6E9F18911B7FCD5400AB8893 /* MaximizationExpression.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MaximizationExpression.swift; sourceTree = "<group>"; };
146+
6E9F18931B7FD16100AB8893 /* MinimizationExpression_Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MinimizationExpression_Tests.swift; sourceTree = "<group>"; };
147+
6E9F18951B7FD18600AB8893 /* MaximizationExpression_Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MaximizationExpression_Tests.swift; sourceTree = "<group>"; };
148+
6E9F18971B7FDF0D00AB8893 /* MinimizationExpressionResult.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MinimizationExpressionResult.swift; sourceTree = "<group>"; };
149+
6E9F189B1B7FDFF900AB8893 /* MaximizationExpressionResult.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MaximizationExpressionResult.swift; sourceTree = "<group>"; };
134150
8B4C14011B7F8B47008AC355 /* SubtractionExpression.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SubtractionExpression.swift; sourceTree = "<group>"; };
135151
8B4C14031B7FA8A2008AC355 /* SubtractionExpressionResult.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SubtractionExpressionResult.swift; sourceTree = "<group>"; };
136152
8BFAA9F81B7ED8E800EF65AE /* SubtractionExpression_Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SubtractionExpression_Tests.swift; sourceTree = "<group>"; };
@@ -221,6 +237,10 @@
221237
53ECD0E31B5B5185002D859F /* NegationExpressionResult.swift */,
222238
53FA0EAB1B6579F300C8D3B5 /* ProbabilisticExpressionType.swift */,
223239
539D568D1B5C7BDA00AC6A37 /* ProbabilityMass.swift */,
240+
6E9F188F1B7FCD4400AB8893 /* MinimizationExpression.swift */,
241+
6E9F18971B7FDF0D00AB8893 /* MinimizationExpressionResult.swift */,
242+
6E9F18911B7FCD5400AB8893 /* MaximizationExpression.swift */,
243+
6E9F189B1B7FDFF900AB8893 /* MaximizationExpressionResult.swift */,
224244
);
225245
path = DiceKit;
226246
sourceTree = "<group>";
@@ -249,6 +269,10 @@
249269
8BFAA9FA1B7F708000EF65AE /* SubtractionExpressionResult_Tests.swift */,
250270
53FA0EAD1B657A3600C8D3B5 /* ProbabilisticExpressionType_Tests.swift */,
251271
533D0C7A1B6423FA003A7D32 /* ProbabilityMass_Tests.swift */,
272+
6E9F18931B7FD16100AB8893 /* MinimizationExpression_Tests.swift */,
273+
6E0F58C81B8D63690095087F /* MinimizationExpressionResult_Tests.swift */,
274+
6E9F18951B7FD18600AB8893 /* MaximizationExpression_Tests.swift */,
275+
6E0F58CA1B8D63910095087F /* MaximizationExpressionResult_Tests.swift */,
252276
);
253277
path = DiceKitTests;
254278
sourceTree = "<group>";
@@ -392,12 +416,14 @@
392416
buildActionMask = 2147483647;
393417
files = (
394418
534900341B78172900FA2804 /* ArithmeticType.swift in Sources */,
419+
6E9F18921B7FCD5400AB8893 /* MaximizationExpression.swift in Sources */,
395420
539D56821B5B69D700AC6A37 /* ExpressionResultType.swift in Sources */,
396421
539D567E1B5B66CF00AC6A37 /* AdditionExpression.swift in Sources */,
397422
53D1EC7C1B6312E100433D2C /* FrequencyDistribution.swift in Sources */,
398423
53FA0EAC1B6579F300C8D3B5 /* ProbabilisticExpressionType.swift in Sources */,
399424
531084C01B5AF993008DD696 /* MultiplicationExpressionResult.swift in Sources */,
400425
539D568C1B5C7B7700AC6A37 /* Dictionary+Functions.swift in Sources */,
426+
6E9F18981B7FDF0D00AB8893 /* MinimizationExpressionResult.swift in Sources */,
401427
53D1EC7E1B63133E00433D2C /* ApproximatelyEquatable.swift in Sources */,
402428
531084C31B5B0761008DD696 /* Die.Roll.swift in Sources */,
403429
539EAC5B1B6DB97C0097C116 /* FrequencyDistributionIndex.swift in Sources */,
@@ -408,6 +434,8 @@
408434
539D56801B5B689600AC6A37 /* AdditionExpressionResult.swift in Sources */,
409435
8B4C14041B7FA8A2008AC355 /* SubtractionExpressionResult.swift in Sources */,
410436
539D568E1B5C7BDA00AC6A37 /* ProbabilityMass.swift in Sources */,
437+
6E9F18901B7FCD4400AB8893 /* MinimizationExpression.swift in Sources */,
438+
6E9F189C1B7FDFF900AB8893 /* MaximizationExpressionResult.swift in Sources */,
411439
53CFC30D1B5AD3BF009C6C8F /* ExpressionType.swift in Sources */,
412440
53CFC30F1B5AD674009C6C8F /* MultiplicationExpression.swift in Sources */,
413441
53ECD0E41B5B5185002D859F /* NegationExpressionResult.swift in Sources */,
@@ -426,12 +454,16 @@
426454
533EB1EE1B5B293000B3F8A1 /* MultiplicationExpressionResult_Tests.swift in Sources */,
427455
53CFC3111B5AE4A0009C6C8F /* MultiplicationExpression_Tests.swift in Sources */,
428456
53D05EEC1B546C73007CE7FC /* Int+Random_Tests.swift in Sources */,
457+
6E9F18941B7FD16100AB8893 /* MinimizationExpression_Tests.swift in Sources */,
429458
539D568A1B5B6D6A00AC6A37 /* AdditionExpressionResult_Tests.swift in Sources */,
430459
533D0C771B6419F8003A7D32 /* FrequencyDistribution_Tests.swift in Sources */,
460+
6E0F58C91B8D63690095087F /* MinimizationExpressionResult_Tests.swift in Sources */,
431461
538AD96B1B768931001B5CB5 /* Constant_Tests.swift in Sources */,
432462
533F880E1B52B988003838C8 /* Die_Tests.swift in Sources */,
463+
6E0F58CB1B8D63910095087F /* MaximizationExpressionResult_Tests.swift in Sources */,
433464
539D56861B5B6D2B00AC6A37 /* NegationExpressionResult_Tests.swift in Sources */,
434465
539D56881B5B6D4A00AC6A37 /* AdditionExpression_Tests.swift in Sources */,
466+
6E9F18961B7FD18600AB8893 /* MaximizationExpression_Tests.swift in Sources */,
435467
539EAC671B6EF76A0097C116 /* FrequencyDistributionIndex_Tests.swift in Sources */,
436468
538AD9691B7678B7001B5CB5 /* Die.Roll_Tests.swift in Sources */,
437469
538AD9651B75A66F001B5CB5 /* MockExpression.swift in Sources */,

DiceKit/FrequencyDistribution.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,14 @@ extension FrequencyDistribution {
202202
return mapFrequencies { $0 / frequencies }
203203
}
204204

205+
public func minimumOutcome() -> Outcome? {
206+
return orderedOutcomes.first
207+
}
208+
209+
public func maximumOutcome() -> Outcome? {
210+
return orderedOutcomes.last
211+
}
212+
205213
public func filterZeroFrequencies(delta: Frequency) -> FrequencyDistribution {
206214
let newFrequenciesPerOutcome = frequenciesPerOutcome
207215
return FrequencyDistribution(newFrequenciesPerOutcome, delta: delta)
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
//
2+
// MaximizationExpression.swift
3+
// DiceKit
4+
//
5+
// Created by Logan Johnson on 8/15/15.
6+
// Copyright © 2015 Brentley Jones. All rights reserved.
7+
//
8+
9+
import Foundation
10+
11+
public struct MaximizationExpression<Expression: protocol<ExpressionType, Equatable>>: Equatable {
12+
13+
public let expression: Expression
14+
15+
public init(_ expression: Expression) {
16+
self.expression = expression
17+
}
18+
19+
}
20+
21+
// MARK: - ExpressionType
22+
23+
extension MaximizationExpression: ExpressionType {
24+
25+
public typealias Result = MaximizationExpressionResult<Expression.Result>
26+
27+
public func evaluate() -> Result {
28+
guard let maxOutcome = expression.probabilityMass.maximumOutcome() else {
29+
return Result(0)
30+
}
31+
32+
return Result(maxOutcome)
33+
}
34+
35+
public var probabilityMass: ExpressionProbabilityMass {
36+
if let maximumOutcome = expression.probabilityMass.maximumOutcome() {
37+
return ProbabilityMass(maximumOutcome)
38+
}
39+
40+
return ProbabilityMass(FrequencyDistribution.additiveIdentity)
41+
}
42+
43+
}
44+
45+
// MARK: CustomStringConvertible
46+
47+
extension MaximizationExpression: CustomStringConvertible {
48+
49+
public var description: String {
50+
return "max(\(expression))"
51+
}
52+
53+
}
54+
55+
// MARK: - CustomDebugStringConvertible
56+
57+
extension MaximizationExpression: CustomDebugStringConvertible {
58+
59+
public var debugDescription: String {
60+
return "max(\(String(reflecting: expression)))"
61+
}
62+
63+
}
64+
65+
// MARK: - Equatable
66+
67+
public func == <E>(lhs: MaximizationExpression<E>, rhs: MaximizationExpression<E>) -> Bool {
68+
return lhs.expression == rhs.expression
69+
}
70+
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
//
2+
// MaximizationExpressionResult.swift
3+
// DiceKit
4+
//
5+
// Created by Logan Johnson on 8/15/15.
6+
// Copyright © 2015 Brentley Jones. All rights reserved.
7+
//
8+
9+
import Foundation
10+
11+
public struct MaximizationExpressionResult<MaximizationExpressionResult: protocol<ExpressionResultType, Equatable>>: Equatable {
12+
13+
public let maximizationExpressionResult: Int
14+
15+
public init(_ maximizationExpressionResult: Int) {
16+
self.maximizationExpressionResult = maximizationExpressionResult
17+
}
18+
19+
}
20+
21+
// MARK: - CustomStringConvertible
22+
23+
extension MaximizationExpressionResult: CustomStringConvertible {
24+
25+
public var description: String {
26+
return "\(maximizationExpressionResult)"
27+
}
28+
29+
}
30+
31+
// MARK: - CustomDebugStringConvertible
32+
33+
extension MaximizationExpressionResult: CustomDebugStringConvertible {
34+
35+
public var debugDescription: String {
36+
return "\(String(reflecting: maximizationExpressionResult))"
37+
}
38+
39+
}
40+
41+
// MARK: - Equatable
42+
43+
public func == <L>(lhs: MaximizationExpressionResult<L>, rhs: MaximizationExpressionResult<L>) -> Bool {
44+
return lhs.value == rhs.value
45+
}
46+
47+
// MARK: - ExpressionResultType
48+
49+
extension MaximizationExpressionResult: ExpressionResultType {
50+
51+
public var value: Int {
52+
return maximizationExpressionResult
53+
}
54+
55+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
//
2+
// MinimizationExpression.swift
3+
// DiceKit
4+
//
5+
// Created by Logan Johnson on 8/15/15.
6+
// Copyright © 2015 Brentley Jones. All rights reserved.
7+
//
8+
9+
import Foundation
10+
11+
public struct MinimizationExpression<Expression: protocol<ExpressionType, Equatable>>: Equatable {
12+
13+
public let expression: Expression
14+
15+
public init(_ expression: Expression) {
16+
self.expression = expression
17+
}
18+
19+
}
20+
21+
// MARK: - ExpressionType
22+
23+
extension MinimizationExpression: ExpressionType {
24+
25+
public typealias Result = MinimizationExpressionResult<Expression.Result>
26+
27+
public func evaluate() -> Result {
28+
guard let minOutcome = expression.probabilityMass.minimumOutcome() else {
29+
return Result(0)
30+
}
31+
return Result(minOutcome)
32+
}
33+
34+
public var probabilityMass: ExpressionProbabilityMass {
35+
if let minimumOutcome = expression.probabilityMass.minimumOutcome() {
36+
return ProbabilityMass(minimumOutcome)
37+
}
38+
39+
return ProbabilityMass(FrequencyDistribution.additiveIdentity)
40+
}
41+
42+
}
43+
44+
// MARK: CustomStringConvertible
45+
46+
extension MinimizationExpression: CustomStringConvertible {
47+
48+
public var description: String {
49+
return "min(\(expression))"
50+
}
51+
52+
}
53+
54+
// MARK: - CustomDebugStringConvertible
55+
56+
extension MinimizationExpression: CustomDebugStringConvertible {
57+
58+
public var debugDescription: String {
59+
return "min(\(String(reflecting: expression)))"
60+
}
61+
62+
}
63+
64+
// MARK: - Equatable
65+
66+
public func == <E>(lhs: MinimizationExpression<E>, rhs: MinimizationExpression<E>) -> Bool {
67+
return lhs.expression == rhs.expression
68+
}
69+
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
//
2+
// MinimizationExpressionResult.swift
3+
// DiceKit
4+
//
5+
// Created by Logan Johnson on 8/15/15.
6+
// Copyright © 2015 Brentley Jones. All rights reserved.
7+
//
8+
9+
import Foundation
10+
11+
public struct MinimizationExpressionResult<MinimizationExpressionResult: protocol<ExpressionResultType, Equatable>>: Equatable {
12+
13+
public let minimizationExpressionResult: Int
14+
15+
public init(_ minimizationExpressionResult: Int) {
16+
self.minimizationExpressionResult = minimizationExpressionResult
17+
}
18+
19+
}
20+
21+
// MARK: - CustomStringConvertible
22+
23+
extension MinimizationExpressionResult: CustomStringConvertible {
24+
25+
public var description: String {
26+
return "\(minimizationExpressionResult)"
27+
}
28+
29+
}
30+
31+
// MARK: - CustomDebugStringConvertible
32+
33+
extension MinimizationExpressionResult: CustomDebugStringConvertible {
34+
35+
public var debugDescription: String {
36+
return "\(String(reflecting: minimizationExpressionResult))"
37+
}
38+
39+
}
40+
41+
// MARK: - Equatable
42+
43+
public func == <L>(lhs: MinimizationExpressionResult<L>, rhs: MinimizationExpressionResult<L>) -> Bool {
44+
return lhs.value == rhs.value
45+
}
46+
47+
// MARK: - ExpressionResultType
48+
49+
extension MinimizationExpressionResult: ExpressionResultType {
50+
51+
public var value: Int {
52+
return minimizationExpressionResult
53+
}
54+
55+
}

DiceKit/ProbabilityMass.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,14 @@ extension ProbabilityMass {
135135
return ProbabilityMass(freqDist, normalize: true)
136136
}
137137

138+
public func minimumOutcome() -> Outcome? {
139+
return frequencyDistribution.minimumOutcome()
140+
}
141+
142+
public func maximumOutcome() -> Outcome? {
143+
return frequencyDistribution.maximumOutcome()
144+
}
145+
138146
}
139147

140148
// MARK: - Operators

0 commit comments

Comments
 (0)