A set of classes for parsing, evaluating, and formatting die roll strings.
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

SA_DiceExpression.m 8.8KB

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