A set of classes for parsing, evaluating, and formatting die roll strings.
Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

SA_DiceExpression.m 8.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. //
  2. // SA_DiceExpression.m
  3. //
  4. // Copyright 2016-2021 Said Achmiz.
  5. // See LICENSE and README.md for more info.
  6. #import "SA_DiceExpression.h"
  7. #import "SA_DiceFormatter.h"
  8. /*********************/
  9. #pragma mark Functions
  10. /*********************/
  11. NSString *NSStringFromSA_DiceExpressionOperator(SA_DiceExpressionOperator operator) {
  12. static NSDictionary <NSNumber *, NSString *> *SA_DiceExpressionOperatorStringValues;
  13. static dispatch_once_t onceToken;
  14. dispatch_once(&onceToken, ^{
  15. SA_DiceExpressionOperatorStringValues = @{ @(SA_DiceExpressionOperator_NONE) : @"SA_DB_OPERATOR_NONE",
  16. @(SA_DiceExpressionOperator_MINUS) : @"SA_DB_OPERATOR_MINUS",
  17. @(SA_DiceExpressionOperator_PLUS) : @"SA_DB_OPERATOR_PLUS",
  18. @(SA_DiceExpressionOperator_TIMES) : @"SA_DB_OPERATOR_TIMES"
  19. };
  20. });
  21. return SA_DiceExpressionOperatorStringValues[@(operator)];
  22. }
  23. NSString *NSStringFromSA_DiceExpressionRollCommand(SA_DiceExpressionRollCommand command) {
  24. static NSDictionary <NSNumber *, NSString *> *SA_DiceExpressionRollCommandStringValues;
  25. static dispatch_once_t onceToken;
  26. dispatch_once(&onceToken, ^{
  27. SA_DiceExpressionRollCommandStringValues = @{ @(SA_DiceExpressionRollCommand_SUM) : @"SA_DB_ROLL_COMMAND_SUM",
  28. @(SA_DiceExpressionRollCommand_SUM_EXPLODING) : @"SA_DB_ROLL_COMMAND_SUM_EXPLODING"
  29. };
  30. });
  31. return SA_DiceExpressionRollCommandStringValues[@(command)];
  32. }
  33. NSString *NSStringFromSA_DiceExpressionRollModifier(SA_DiceExpressionRollModifier modifier) {
  34. static NSDictionary <NSNumber *, NSString *> *SA_DiceExpressionRollModifierStringValues;
  35. static dispatch_once_t onceToken;
  36. dispatch_once(&onceToken, ^{
  37. SA_DiceExpressionRollModifierStringValues = @{ @(SA_DiceExpressionRollModifier_KEEP_HIGHEST) : @"SA_DB_ROLL_MODIFIER_KEEP_HIGHEST",
  38. @(SA_DiceExpressionRollModifier_KEEP_LOWEST) : @"SA_DB_ROLL_MODIFIER_KEEP_LOWEST"
  39. };
  40. });
  41. return SA_DiceExpressionRollModifierStringValues[@(modifier)];
  42. }
  43. NSString *NSStringFromSA_DiceExpressionError(SA_DiceExpressionError error) {
  44. static NSDictionary <NSNumber *, NSString *> *SA_DiceExpressionErrorStringValues;
  45. static dispatch_once_t onceToken;
  46. dispatch_once(&onceToken, ^{
  47. SA_DiceExpressionErrorStringValues = @{ @(SA_DiceExpressionError_ROLL_STRING_EMPTY) : @"SA_DB_ERROR_ROLL_STRING_EMPTY",
  48. @(SA_DiceExpressionError_ROLL_STRING_HAS_ILLEGAL_CHARACTERS) : @"SA_DB_ERROR_ROLL_STRING_HAS_ILLEGAL_CHARACTERS",
  49. @(SA_DiceExpressionError_UNKNOWN_ROLL_COMMAND) : @"SA_DB_ERROR_UNKNOWN_ROLL_COMMAND",
  50. @(SA_DiceExpressionError_ROLL_MODIFIER_INAPPLICABLE) : @"SA_DB_ERROR_ROLL_MODIFIER_INAPPLICABLE",
  51. @(SA_DiceExpressionError_UNKNOWN_ROLL_MODIFIER) : @"SA_DB_ERROR_UNKNOWN_ROLL_MODIFIER",
  52. @(SA_DiceExpressionError_DIE_COUNT_NEGATIVE) : @"SA_DB_ERROR_DIE_COUNT_NEGATIVE",
  53. @(SA_DiceExpressionError_DIE_COUNT_EXCESSIVE) : @"SA_DB_ERROR_DIE_COUNT_EXCESSIVE",
  54. @(SA_DiceExpressionError_DIE_SIZE_INVALID) : @"SA_DB_ERROR_DIE_SIZE_INVALID",
  55. @(SA_DiceExpressionError_DIE_SIZE_EXCESSIVE) : @"SA_DB_ERROR_DIE_SIZE_EXCESSIVE",
  56. @(SA_DiceExpressionError_UNKNOWN_OPERATOR) : @"SA_DB_ERROR_UNKNOWN_OPERATOR",
  57. @(SA_DiceExpressionError_INVALID_EXPRESSION) : @"SA_DB_ERROR_INVALID_EXPRESSION",
  58. @(SA_DiceExpressionError_INTEGER_OVERFLOW_NEGATION) : @"SA_DB_ERROR_INTEGER_OVERFLOW_NEGATION",
  59. @(SA_DiceExpressionError_INTEGER_OVERFLOW_ADDITION) : @"SA_DB_ERROR_INTEGER_OVERFLOW_ADDITION",
  60. @(SA_DiceExpressionError_INTEGER_UNDERFLOW_ADDITION) : @"SA_DB_ERROR_INTEGER_UNDERFLOW_ADDITION",
  61. @(SA_DiceExpressionError_INTEGER_OVERFLOW_SUBTRACTION) : @"SA_DB_ERROR_INTEGER_OVERFLOW_SUBTRACTION",
  62. @(SA_DiceExpressionError_INTEGER_UNDERFLOW_SUBTRACTION) : @"SA_DB_ERROR_INTEGER_UNDERFLOW_SUBTRACTION",
  63. @(SA_DiceExpressionError_INTEGER_OVERFLOW_MULTIPLICATION) : @"SA_DB_ERROR_INTEGER_OVERFLOW_MULTIPLICATION",
  64. @(SA_DiceExpressionError_INTEGER_UNDERFLOW_MULTIPLICATION) : @"SA_DB_ERROR_INTEGER_UNDERFLOW_MULTIPLICATION",
  65. @(SA_DiceExpressionError_KEEP_COUNT_EXCEEDS_ROLL_COUNT) : @"SA_DB_ERROR_KEEP_COUNT_EXCEEDS_ROLL_COUNT",
  66. @(SA_DiceExpressionError_KEEP_COUNT_NEGATIVE) : @"SA_DB_ERROR_KEEP_COUNT_NEGATIVE"
  67. };
  68. });
  69. __block NSMutableArray *errorStrings = [NSMutableArray array];
  70. [SA_DiceExpressionErrorStringValues enumerateKeysAndObjectsUsingBlock:^(NSNumber *errorKey,
  71. NSString *errorString,
  72. BOOL *stop) {
  73. if (errorKey.unsignedIntegerValue & error)
  74. [errorStrings addObject:errorString];
  75. }];
  76. return [errorStrings componentsJoinedByString:@","];
  77. // return SA_DiceExpressionErrorStringValues[@(error)];
  78. }
  79. NSComparisonResult compareEvaluatedExpressionsByResult(SA_DiceExpression *expression1,
  80. SA_DiceExpression *expression2) {
  81. if (expression1.result.integerValue < expression2.result.integerValue)
  82. return NSOrderedAscending;
  83. else if (expression1.result.integerValue > expression2.result.integerValue)
  84. return NSOrderedDescending;
  85. else
  86. return NSOrderedSame;
  87. }
  88. NSComparisonResult compareEvaluatedExpressionsByAttemptBonus(SA_DiceExpression *expression1,
  89. SA_DiceExpression *expression2) {
  90. if (expression1.rightOperand.result.integerValue < expression2.rightOperand.result.integerValue)
  91. return NSOrderedAscending;
  92. else if (expression1.rightOperand.result.integerValue > expression2.rightOperand.result.integerValue)
  93. return NSOrderedDescending;
  94. else
  95. return NSOrderedSame;
  96. }
  97. /****************************************************/
  98. #pragma mark - SA_DiceExpression class implementation
  99. /****************************************************/
  100. @implementation SA_DiceExpression
  101. +(SA_DiceExpression *) expressionByJoiningExpression:(SA_DiceExpression *)leftHandExpression
  102. toExpression:(SA_DiceExpression *)rightHandExpression
  103. withOperator:(SA_DiceExpressionOperator)operator {
  104. SA_DiceExpression *expression = [SA_DiceExpression new];
  105. // First, we check that the operands and operator are not nil. If they are,
  106. // then the expression is invalid...
  107. if ( leftHandExpression == nil
  108. || rightHandExpression == nil
  109. || operator == SA_DiceExpressionOperator_NONE
  110. ) {
  111. expression.type = SA_DiceExpressionTerm_NONE;
  112. expression.errorBitMask |= SA_DiceExpressionError_INVALID_EXPRESSION;
  113. return expression;
  114. }
  115. // If the operands and operator are present, then the expression is an
  116. // operation expression...
  117. expression.type = SA_DiceExpressionTerm_OPERATION;
  118. // ... but does it have a valid operator?
  119. if ( operator == SA_DiceExpressionOperator_MINUS
  120. || operator == SA_DiceExpressionOperator_PLUS
  121. || operator == SA_DiceExpressionOperator_TIMES
  122. ) {
  123. expression.operator = operator;
  124. } else {
  125. expression.errorBitMask |= SA_DiceExpressionError_UNKNOWN_OPERATOR;
  126. return expression;
  127. }
  128. // The operator is valid. Set the operands...
  129. expression.leftOperand = leftHandExpression;
  130. expression.rightOperand = rightHandExpression;
  131. // And inherit any errors that they may have.
  132. expression.errorBitMask |= expression.leftOperand.errorBitMask;
  133. expression.errorBitMask |= expression.rightOperand.errorBitMask;
  134. // Since this top-level expression was NOT generated by parsing an input
  135. // string, for completeness and consistency, we have to generate a fake
  136. // input string ourselves! We do this by wrapping each operand in
  137. // parentheses and putting the canonical representation of the operator
  138. // between them.
  139. // TODO: Shouldn't the canonical representation of an operator
  140. // possibly vary by formatter behavior...?
  141. // But on the other hand, how does a parser know what formatter behavior
  142. // is in use...?
  143. // TODO: Parentheses aren't even supported by the legacy parser!
  144. // This is total nonsense!
  145. expression.inputString = [NSString stringWithFormat:@"(%@)%@(%@)",
  146. expression.leftOperand.inputString,
  147. [SA_DiceFormatter canonicalRepresentationForOperator:expression.operator],
  148. expression.rightOperand.inputString];
  149. // The joining is complete. (Power overwhelming.)
  150. return expression;
  151. }
  152. /*******************************/
  153. #pragma mark - NSCopying methods
  154. /*******************************/
  155. -(instancetype) copyWithZone:(NSZone *)zone {
  156. SA_DiceExpression *copy = [SA_DiceExpression new];
  157. copy.type = _type;
  158. copy.errorBitMask = _errorBitMask;
  159. copy.operator = _operator;
  160. copy.leftOperand = [_leftOperand copy];
  161. copy.rightOperand = [_rightOperand copy];
  162. copy.rollCommand = _rollCommand;
  163. copy.dieCount = [_dieCount copy];
  164. copy.dieSize = [_dieSize copy];
  165. copy.dieType = _dieType;
  166. copy.rollModifier = _rollModifier;
  167. copy.value = _value;
  168. copy.inputString = _inputString;
  169. copy.attributedInputString = _attributedInputString;
  170. copy.result = _result;
  171. copy.rolls = _rolls;
  172. return copy;
  173. }
  174. @end