A set of classes for parsing, evaluating, and formatting die roll strings.
Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

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