def openFunctionCache( name ): if name in g.functionCaches: return g.functionCaches[ name ] else: debugPrint( 'opening', name, 'function cache database' ) g.functionCaches[ name ] = PersistentDict( getCacheFileName( name ) ) return g.functionCaches[ name ]
def openFunctionCache(name): if name in g.functionCaches: return g.functionCaches[name] debugPrint('opening', name, 'function cache database') g.functionCaches[name] = PersistentDict(getCacheFileName(name)) return g.functionCaches[name]
def runYAFU(n): fullOut = subprocess.run([ g.userConfiguration['yafu_path'] + os.sep + g.userConfiguration['yafu_binary'], '-xover', '120' ], input='factor(' + str(int(n)) + ')\n', encoding='ascii', stdout=subprocess.PIPE, cwd=g.userConfiguration['yafu_path'], check=True).stdout #print( 'out', fullOut ) out = fullOut[fullOut.find('***factors found***'):] if len(out) < 2: if log10(n) > 40: raise ValueError('yafu seems to have crashed trying to factor ' + str(int(n)) + '.\n\nyafu output follows:\n' + fullOut) debugPrint( 'yafu seems to have crashed, switching to built-in factoring code') return factorise(int(n)) result = [] while True: prime = '' out = out[out.find('P'):] if len(out) < 2: break out = out[out.find('='):] index = 2 while out[index] >= '0' and out[index] <= '9': prime += out[index] index += 1 result.append(mpmathify(prime)) if not result: raise ValueError('yafu seems to have failed.') answer = fprod(result) if answer != n: debugPrint('\nyafu has barfed') for i in result: n = fdiv(n, i) result.extend(runYAFU(n)) return sorted(result)
def getFactors(target): if target < -1: result = [-1] result.extend(getFactors(fneg(target))) return result if target == -1: return [-1] if target == 0: return [0] if target == 1: return [1] n = int(floor(target)) setAccuracy(floor(fadd(log10(n), 2))) if g.factorCache is None: loadFactorCache() if not g.ignoreCache: if n in g.factorCache: if g.verbose and n != 1: print('cache hit:', n) print() debugPrint('\nfactor cache', n, g.factorCache[n]) return g.factorCache[n] try: result = factorByTrialDivision(n) # throws if n is too big if n > g.minValueToCache and n not in g.factorCache: g.factorCache[n] = result return result except ValueError: pass if g.useYAFU and n > g.minValueForYAFU: result = runYAFU(n) else: result = factorise(int(n)) if n > g.minValueToCache: if g.ignoreCache or (not g.ignoreCache and n not in g.factorCache): debugPrint('\ncaching factors of ', n, result) g.factorCache[n] = result return result
def getPartitionNumber(n): ''' This version is, um, less recursive than the original, which I've kept. The strategy is to create a list of the smaller partition numbers we need to calculate and then start calling them recursively, starting with the smallest. This will minimize the number of recursions necessary, and in combination with caching values, will calculate practically any integer partition without the risk of a stack overflow. I can't help but think this is still grossly inefficient compared to what's possible. It seems that using this algorithm, calculating any integer partition ends up necessitating calculating the integer partitions of every integer smaller than the original argument. ''' debugPrint('partition', int(n)) if n in (0, 1): return 1 sign = 1 i = 1 k = 1 estimate = log10( fdiv(power(e, fmul(pi, sqrt(fdiv(fmul(2, n), 3)))), fprod([4, n, sqrt(3)]))) if mp.dps < estimate + 5: mp.dps = estimate + 5 partitionList = [] while n - k >= 0: partitionList.append((fsub(n, k), sign)) i += 1 if i % 2: sign *= -1 k = getNthGeneralizedPolygonalNumber(i, 5) partitionList = partitionList[::-1] total = 0 for partition, sign in partitionList: total = fadd(total, fmul(sign, getPartitionNumber(partition))) return total
def evaluateDiceExpression(args, sumIfPossible=True): result = [] modifierSum = 0 # currently only a single modifier is allowed if sumIfPossible: result = [0] for diceCount, diceValue, dropLowestCount, dropHighestCount, modifier in args: modifierSum += modifier if dropLowestCount == 0 and dropHighestCount == 0: if sumIfPossible: for _ in range(0, diceCount): result[0] += (randrange(diceValue) + 1) else: for _ in range(0, diceCount): result.append(randrange(diceValue) + 1) else: dice = [] for _ in range(0, diceCount): dice.append(randrange(diceValue) + 1) dice.sort() debugPrint('dice', dice) if dropHighestCount > 0: debugPrint('drop', dice[dropLowestCount:-dropHighestCount]) result.extend(dice[dropLowestCount:-dropHighestCount]) else: debugPrint('drop', dice[dropLowestCount:]) result.extend(dice[dropLowestCount:]) return result, modifierSum
def convertUnits(unit1, unit2): if isinstance(unit1, RPNGenerator): unit1 = list(unit1) if len(unit1) == 1: unit1 = unit1[0] if isinstance(unit2, RPNGenerator): unit2 = list(unit2) if len(unit2) == 1: unit2 = unit2[0] if isinstance(unit1, list): result = [] for unit in unit1: result.append(convertUnits(unit, unit2)) return result if not isinstance(unit1, RPNMeasurement): raise ValueError('cannot convert non-measurements') if isinstance(unit2, list): return unit1.convertValue(unit2) if isinstance(unit2, (str, RPNUnits)): measurement = RPNMeasurement(1, unit2) return RPNMeasurement(unit1.convertValue(measurement), unit2) if not isinstance(unit2, (list, str, RPNUnits, RPNMeasurement)): raise ValueError('cannot convert non-measurements') debugPrint('convertUnits') debugPrint('unit1:', unit1.getUnitTypes()) debugPrint('unit2:', unit2.getUnitTypes()) newValue = unit1.convertValue(unit2) debugPrint('*** value:', newValue) return RPNMeasurement(newValue, unit2.units)
def findInput(value, func, estimator, minimum=0, maximum=inf): guess1 = floor(estimator(value)) if guess1 > maximum: guess1 = maximum if guess1 < minimum: guess1 = minimum # closing in result = func(guess1) debugPrint('findInput func call', guess1) if result == value: return True, guess1 elif result > value: over = True delta = -1 else: over = False delta = 1 guess2 = guess1 + delta if guess2 > maximum: guess2 = maximum if guess2 < minimum: guess2 = minimum result = func(guess2) debugPrint('findInput func call', guess2) if result == value: return True, guess2 if over: def comparator(a, b): return a > b else: def comparator(a, b): return a < b while comparator(result, value): delta *= 2 guess1 = guess2 guess2 += delta if guess2 > maximum: return False, 0 if guess2 < minimum: break result = func(guess2) debugPrint('findInput func call', guess2) if result == value: return True, guess2 if guess1 < minimum: guess1 = minimum if guess2 < minimum: guess2 = minimum if guess1 == guess2: return False, 0 elif guess1 > guess2: guess1, guess2 = int(guess2), int(guess1) else: guess1, guess2 = int(guess1), int(guess2) debugPrint('->guesses:', guess1, guess2) while guess1 + 1 != guess2: newGuess = guess1 + (guess2 - guess1) // 2 result = func(newGuess) debugPrint('findInput func call', newGuess) if result == value: return True, newGuess elif result > value: guess2 = newGuess else: guess1 = newGuess debugPrint('didn\'t find anything') return False, 0
def convertValue(self, other): if not isinstance(other, (RPNUnits, RPNMeasurement, str, list)): raise ValueError( 'convertValue must be called with an RPNUnits object, ' 'an RPNMeasurement object, a string or a list of RPNMeasurement' ) if isinstance(other, (str, RPNUnits)): other = RPNMeasurement(1, other) if not self.isCompatible(other): # We can try to convert incompatible units. return self.convertIncompatibleUnit(other) if not g.unitConversionMatrix: loadUnitConversionMatrix() # handle list conversions like [ year, day, minute, hour ] if isinstance(other, list): # a list of length one is treated the same as a single measurement if len(other) == 1: return self.convertValue(other[0]) else: listToConvert = [] for i in other: if isinstance(i, str): listToConvert.append(RPNMeasurement(1, i)) elif isinstance(i, RPNMeasurement): listToConvert.append(i) else: raise ValueError('we\'ve got something else') return self.convertUnitList(listToConvert) conversions = [] value = self.value # This is what we'll return down below # let's look for straightforward conversions units1 = self.units units2 = other.units unit1String = units1.getUnitString() unit2String = units2.getUnitString() if unit1String == unit2String: return value exponents = {} # look for a straight-up conversion if (unit1String, unit2String) in g.unitConversionMatrix: value = fmul( value, mpmathify(g.unitConversionMatrix[(unit1String, unit2String)])) elif (unit1String, unit2String) in specialUnitConversionMatrix: value = specialUnitConversionMatrix[(unit1String, unit2String)](value) else: # TODO: Should we just convert to base units regardless? It would be safer... if other.doDimensionsCancel(): other = other.convertToPrimitiveUnits() units2 = other.units value = fdiv(value, other.value) # otherwise, we need to figure out how to do the conversion conversionValue = value # if that isn't found, then we need to do the hard work and break the units down newUnits1 = RPNUnits(units1) newUnits2 = RPNUnits(units2) debugPrint('newUnits1:', newUnits1) debugPrint('newUnits2:', newUnits2) debugPrint() debugPrint('iterating through units to match for conversion:') for unit1 in newUnits1: foundConversion = False for unit2 in newUnits2: debugPrint('units 1:', unit1, newUnits1[unit1], getUnitType(unit1)) debugPrint('units 2:', unit2, newUnits2[unit2], getUnitType(unit2)) if getUnitType(unit1) == getUnitType(unit2): debugPrint('found a conversion:', unit1, unit2) conversions.append((unit1, unit2)) exponents[(unit1, unit2)] = units1[unit1] foundConversion = True break if not foundConversion: debugPrint() debugPrint('didn\'t find a conversion, try reducing') debugPrint() reduced = self.convertToPrimitiveUnits() debugPrint('reduced:', self.units, 'becomes', reduced.units) reducedOther = other.convertToPrimitiveUnits() reduced.value = fdiv(reduced.value, reducedOther.value) debugPrint('reduced other:', other.units, 'becomes', reducedOther.units) # check to see if reducing did anything and bail if it didn't... bail out if (reduced.units == self.units) and (reducedOther.units == other.units): debugPrint('reducing didn\'t help') break return reduced.convertValue(reducedOther) debugPrint() value = conversionValue debugPrint('Iterating through conversions...') for conversion in conversions: if conversion[0] == conversion[1]: continue # no conversion needed debugPrint('----> conversion', conversion) conversionIndex = tuple(conversion) if conversionIndex in g.unitConversionMatrix: debugPrint('unit conversion:', g.unitConversionMatrix[tuple(conversion)]) debugPrint('exponents', exponents) conversionValue = mpmathify( g.unitConversionMatrix[conversionIndex]) conversionValue = power(conversionValue, exponents[conversionIndex]) debugPrint('conversion: ', conversion, conversionValue) debugPrint('value before', value) value = fmul(value, conversionValue) debugPrint('value after', value) else: # we're ignoring the exponents, but this works for dBm<->milliwatt, etc. baseUnit = g.basicUnitTypes[getUnitType( conversion[0])].baseUnit conversion1 = (conversion[0], baseUnit) conversion2 = (baseUnit, conversion[1]) debugPrint('conversion1', conversion1) debugPrint('conversion2', conversion2) debugPrint('value0', value) if conversion1 in g.unitConversionMatrix: debugPrint('standard conversion 1') value = fmul( value, mpmathify(g.unitConversionMatrix[conversion1])) else: debugPrint('special conversion 1') value = specialUnitConversionMatrix[conversion1](value) debugPrint('value1', value) if conversion2 in g.unitConversionMatrix: debugPrint('standard conversion 2') value = fmul( value, mpmathify(g.unitConversionMatrix[conversion2])) else: debugPrint('special conversion 2') value = specialUnitConversionMatrix[conversion2](value) debugPrint('value2', value) debugPrint('convertValue final', value) return value
def convertToPrimitiveUnits(self): debugPrint() debugPrint('convertToPrimitiveUnits:', self.value, self.units) if not g.unitConversionMatrix: loadUnitConversionMatrix() value = self.value units = RPNUnits() debugPrint('value', value) for unit in self.units: if self.units[unit] == 0: continue newUnits = g.basicUnitTypes[getUnitType(unit)].primitiveUnit debugPrint('unit', unit, 'newUnits', newUnits) if unit != newUnits: debugPrint('unit vs newUnits:', unit, newUnits) if (unit, newUnits) in g.unitConversionMatrix: value = fmul( value, power(mpf(g.unitConversionMatrix[(unit, newUnits)]), self.units[unit])) elif (unit, newUnits) in specialUnitConversionMatrix: value = power( specialUnitConversionMatrix[(unit, newUnits)](value), self.units[unit]) else: if unit == '1' and newUnits == '_null_unit': reduced = RPNMeasurement(value, units) debugPrint('convertToPrimitiveUnits 2:', reduced.value, reduced.units) return reduced raise ValueError('cannot find a conversion for ' + unit + ' and ' + newUnits) newUnits = RPNUnits(newUnits) for newUnit in newUnits: newUnits[newUnit] *= self.units[unit] units.update(newUnits) debugPrint('value', value) baseUnits = RPNMeasurement(value, units) debugPrint('convertToPrimitiveUnits 3:', baseUnits.value, baseUnits.units) debugPrint() return baseUnits
def isCompatible(self, other): if isinstance(other, str): return self.isCompatible(RPNMeasurement(1, other)) if isinstance(other, RPNUnits): return self.getUnitTypes() == other.getUnitTypes() if isinstance(other, RPNMeasurement): debugPrint('isCompatible -----------------------') debugPrint('units: ', self.units, other.units) debugPrint('types: ', self.getUnitTypes(), other.getUnitTypes()) debugPrint('dimensions: ', self.getDimensions(), other.getDimensions()) debugPrint() if self.getUnitTypes() == other.getUnitTypes(): return True if self.getDimensions() == other.getDimensions(): return True debugPrint('RPNMeasurement.isCompatible exiting with false...') return False if isinstance(other, list): result = True for item in other: result = self.isCompatible(item) if not result: break return result raise ValueError('RPNMeasurement or dict expected')
def normalizeUnits(self): units = self.units.normalizeUnits() debugPrint() debugPrint('normalize', units) if units == RPNUnits(): return self.value # look for units that cancel between the numerator and denominator numerator, denominator = units.splitUnits() # if we don't have a numerator or denominator, we're done if not numerator or not denominator: return RPNMeasurement(self.value, units) if not g.basicUnitTypes: loadUnitData() debugPrint('numerator', numerator) debugPrint('denominator', denominator) nOriginalElements = sorted(list(numerator.elements())) dOriginalElements = sorted(list(denominator.elements())) changed = False nElements = [] for nUnit in numerator: for i in range(min(numerator[nUnit], 3)): nElements.append(nUnit) dElements = [] for dUnit in denominator: for i in range(min(denominator[dUnit], 3)): dElements.append(dUnit) debugPrint('nOriginalElements', nOriginalElements) debugPrint('nElements', nElements) debugPrint('dOriginalElements', dOriginalElements) debugPrint('dElements', dElements) matchFound = True # technically not true yet, but it gets us into the loop conversionsNeeded = [] while matchFound: matchFound = False for nSubset in getPowerSet(nElements): for dSubset in getPowerSet(dElements): #debugPrint( '))) nSubset', list( nSubset ) ) #debugPrint( '))) dSubset', list( dSubset ) ) nSubsetUnit = RPNUnits('*'.join(sorted(list(nSubset)))) dSubsetUnit = RPNUnits('*'.join(sorted(list(dSubset)))) #debugPrint( '1 nSubset', dSubsetUnit ) #debugPrint( '2 dSubset', dSubsetUnit ) if nSubsetUnit.getDimensions( ) == dSubsetUnit.getDimensions(): debugPrint('dimensions matched', dSubsetUnit.getDimensions()) newNSubset = [] newDSubset = [] for nUnit in nSubset: baseUnit = g.basicUnitTypes[getUnitType( nUnit)].baseUnit if nUnit != baseUnit: debugPrint('conversion added:', nUnit, baseUnit) conversionsNeeded.append((nUnit, baseUnit)) newNSubset.append(baseUnit) for dUnit in dSubset: baseUnit = g.basicUnitTypes[getUnitType( dUnit)].baseUnit if dUnit != baseUnit: debugPrint('conversion added:', dUnit, baseUnit) conversionsNeeded.append((dUnit, baseUnit)) newDSubset.append(baseUnit) # This maybe isn't quite what we want. debugPrint('conversions added', '*'.join(sorted(newNSubset)), '*'.join(sorted(newDSubset))) conversionsNeeded.append( ('*'.join(sorted(newNSubset)), '*'.join(sorted(newDSubset)))) matchFound = True for nUnit in nSubset: #print( 'nOriginalElements', nOriginalElements, 'n', nUnit ) nOriginalElements.remove(nUnit) changed = True for dUnit in dSubset: #print( 'dOriginalElements', dOriginalElements, 'd', dUnit ) dOriginalElements.remove(dUnit) changed = True break if matchFound: break if matchFound: break debugPrint('final nElements', nOriginalElements) debugPrint('final dElements', dOriginalElements) # convert the value based on all the conversions we queued up convertedValue = self.value if not g.unitConversionMatrix: loadUnitConversionMatrix() for i in conversionsNeeded: if i in g.unitConversionMatrix: convertedValue = fmul(convertedValue, g.unitConversionMatrix[i]) else: convertedValue = fmul( convertedValue, RPNMeasurement(1, i[0]).convertValue(i[1])) # build up the resulting units units = RPNUnits('*'.join(nOriginalElements)) denominator = RPNUnits('*'.join(dOriginalElements)) for dUnit in denominator: units[dUnit] += denominator[dUnit] * -1 debugPrint('normalizeUnits final units', units) debugPrint() if units and units != RPNUnits(): result = RPNMeasurement(convertedValue, units) if changed: return result.normalizeUnits() return result return convertedValue
def rpn(cmdArgs): ''' This is the main function which processes the command-line arguments, handling both options and the expression to evaluate. This function is mainly concerned with parsing and handling the command-line options. It finally calls evaluate( ) with the expression to be calculated, and returns the results, which can be formatted for output or used in another way (such as the unit test functionality). ''' # initialize globals g.outputRadix = 10 # look for help argument before we start setting everything up (because it's faster this way) showHelp = False helpArgs = [] for arg in cmdArgs: if arg == 'help': showHelp = True else: if showHelp: helpArgs.append(arg) if showHelp: parser = argparse.ArgumentParser( prog=PROGRAM_NAME, description=RPN_PROGRAM_NAME + ' - ' + PROGRAM_DESCRIPTION + '\n ' + COPYRIGHT_MESSAGE, add_help=False, formatter_class=argparse.RawTextHelpFormatter, prefix_chars='-') parser.add_argument('terms', nargs='*', metavar='term') parser.add_argument('-l', '--line_length', type=int, action='store', default=g.defaultLineLength) args = parser.parse_args(cmdArgs) loadUnitNameData() g.aliases.update(operatorAliases) printHelp(helpArgs) return None # set up the command-line options parser parser = argparse.ArgumentParser( prog=PROGRAM_NAME, description=RPN_PROGRAM_NAME + ' - ' + PROGRAM_DESCRIPTION + '\n ' + COPYRIGHT_MESSAGE, add_help=False, formatter_class=argparse.RawTextHelpFormatter, prefix_chars='-') parser.add_argument('-a', '--output_accuracy', nargs='?', type=int, default=g.defaultOutputAccuracy, const=g.defaultOutputAccuracy) parser.add_argument('-b', '--input_radix', type=str, default=g.defaultInputRadix) parser.add_argument('-c', '--comma', action='store_true') parser.add_argument('-d', '--decimal_grouping', nargs='?', type=int, default=0, const=g.defaultDecimalGrouping) parser.add_argument('-D', '--DEBUG', action='store_true') parser.add_argument('-e', '--profile', action='store_true') parser.add_argument('-E', '--echo_command', action='store_true') parser.add_argument('-g', '--integer_grouping', nargs='?', type=int, default=0, const=g.defaultIntegerGrouping) parser.add_argument('-h', '--help', action='store_true') parser.add_argument('-I', '--ignore_cache', action='store_true') parser.add_argument('-l', '--line_length', type=int, default=g.defaultLineLength) parser.add_argument('-m', '--maximum_fixed', type=int, default=g.defaultMaximumFixed) parser.add_argument('-n', '--numerals', type=str, default=g.defaultNumerals) parser.add_argument('-o', '--octal', action='store_true') parser.add_argument('-p', '--precision', type=int, default=g.defaultPrecision) parser.add_argument('-r', '--output_radix', type=str, default=g.defaultOutputRadix) parser.add_argument('-s', '--list_format_level', nargs='?', type=int, default=0, const=g.defaultListFormatLevel) parser.add_argument('-t', '--timer', action='store_true') parser.add_argument('-T', '--time_limit', nargs='?', type=int, default=0, const=g.timeLimit) parser.add_argument('-V', '--version', action='store_true') parser.add_argument('-v', '--verbose', action='store_true') parser.add_argument('-w', '--bitwise_group_size', type=int, default=g.defaultBitwiseGroupSize) parser.add_argument('-x', '--hex', action='store_true') parser.add_argument('-y', '--identify', action='store_true') parser.add_argument('-z', '--leading_zero', action='store_true') parser.add_argument('-!', '--print_options', action='store_true') parser.add_argument('-?', '--other_help', action='store_true') # pull out the options and the terms options = [] terms = [] loadUserVariablesFile() loadUserFunctionsFile() loadUserConfigurationFile() if 'yafu_path' in g.userConfiguration and 'yafu_binary' in g.userConfiguration: g.useYAFU = True else: g.useYAFU = False for arg in cmdArgs: if len(arg) > 1: if arg[0] == '$' and arg[1:] not in g.userVariables: raise ValueError('undefined user variable referenced: ' + arg) if arg[0] == '@' and arg[1:] not in g.userFunctions: raise ValueError('undefined user function referenced: ' + arg) if arg[0] == '-': if arg[1].isdigit(): # a negative number, not an option terms.append(arg) elif arg[1] in ('i', 'j'): # -i and -j are also numbers terms.append('-1j') else: options.append(arg) else: terms.append(arg) else: terms.append(arg) debugPrint('terms', terms) debugPrint('options', options) # OK, let's parse and validate the options args = parser.parse_args(options) g.aliases.update(operatorAliases) if args.help or args.other_help: loadUnitNameData() printHelp() return None valid, errorString = validateOptions(args) if not valid: print('rpn: ' + errorString) return None # these are either globals or can be modified by other options (like -x) g.bitwiseGroupSize = args.bitwise_group_size g.integerGrouping = args.integer_grouping g.leadingZero = args.leading_zero # handle -a setAccuracy(args.output_accuracy) # handle -b g.inputRadix = int(args.input_radix) # handle -c g.comma = args.comma # handle -d g.decimalGrouping = args.decimal_grouping # handle -D if args.DEBUG: g.debugMode = True # handle -e g.echo_command = args.echo_command # handle -g g.integerGrouping = args.integer_grouping # handle -i g.identify = args.identify # handle -I g.ignoreCache = args.ignore_cache g.refreshOEISCache = args.ignore_cache # handle -l g.lineLength = args.line_length # handle -m g.maximumFixed = args.maximum_fixed # handle -n g.numerals = parseNumerals(args.numerals) # handle -o if args.octal: g.outputRadix = 8 g.leadingZero = True g.integerGrouping = 3 g.bitwiseGroupSize = 9 # handle -p setPrecision(args.precision) # handle -r if args.output_radix in specialBaseNames: g.outputRadix = specialBaseNames[args.output_radix] else: try: # if g.outputRadix was already set (e.g., by -o) then we don't want to override it if g.outputRadix == 10: g.outputRadix = int(args.output_radix) except ValueError: print('rpn: cannot interpret output radix \'%s\' as a number' % args.output_radix) return [nan] # -r validation if ((g.outputRadix < g.maxSpecialBase) or (g.outputRadix == 0) or (g.outputRadix == 1) or (g.outputRadix > 62)): print( 'rpn: output radix must be from 2 to 62, fib, phi, fac, doublefac, square, lucas' ) return [nan] # handle -s g.listFormatLevel = args.list_format_level # handle -t g.timer = args.timer # handle -T g.timeLimit = args.time_limit # handle -v g.verbose = args.verbose # handle -V if args.version: return [int(i) for i in PROGRAM_VERSION.split('.')] # handle -x if args.hex: g.outputRadix = 16 g.leadingZero = True g.integerGrouping = 4 g.bitwiseGroupSize = 16 # handle -u and -y: mpmath wants precision of at least 53 for these functions if args.identify and mp.dps < 53: setAccuracy(53) if args.print_options: print('--output_accuracy: %d' % g.outputAccuracy) print('--input_radix: %d' % g.inputRadix) print('--comma: ' + ('true' if g.comma else 'false')) print('--decimal_grouping: %d' % g.decimalGrouping) print('--integer_grouping: %d' % g.integerGrouping) print('--line_length: %d' % g.lineLength) print('--numerals: ' + g.numerals) print('--octal: ' + ('true' if args.octal else 'false')) print('--precision: %d' % args.precision) print('--output_radix: %d' % g.outputRadix) print('--list_format_level: %d' % g.listFormatLevel) print('--timer: ' + ('true' if args.timer else 'false')) print('--verbose: ' + ('true' if g.verbose else 'false')) print('--bitwise_group_size: %d' % g.bitwiseGroupSize) print('--hex: ' + ('true' if args.hex else 'false')) print('--identify: ' + ('true' if args.identify else 'false')) print('--leading_zero: ' + ('true' if g.leadingZero else 'false')) print('--ignore_cache: ' + ('true' if g.ignoreCache else 'false')) print() g.creatingFunction = False # enter interactive mode if there are no arguments if not terms: if not loadUnitNameData(): return None enterInteractiveMode() return None # let's check out the arguments before we start to do any calculations if not validateArguments(terms): return None #newTerms = preprocessTerms( terms ) #print( 'newTerms', newTerms ) # waiting until we've validated the arguments to do this because it's slow if not loadUnitNameData(): return None if g.echo_command: print(*sys.argv) if g.timer: g.startTime = time_ns() return evaluate(terms)
def parseDiceExpression(arg): counter = Counter(arg) if counter['a'] > 1: raise ValueError('dice expressions can only contain a single \'x\'') if counter['h'] > 1: raise ValueError('dice expressions can only contain a single \'h\'') if counter['+'] > 1: raise ValueError('dice expressions can only contain a single \'+\'') if counter['-'] > 1: raise ValueError('dice expressions can only contain a single \'-\'') if counter['+'] + counter['-'] > 1: raise ValueError( 'dice expressions can only have a single modifier (\'+\' or \'-\')' ) expressions = re.split(',', arg) result = [] for expr in expressions: pieces = re.split('([dhx+-])', expr) debugPrint('pieces', pieces) diceValue = 0 diceCount = 0 dropLowestCount = 0 dropHighestCount = 0 modifier = 0 defaultState = 0 diceValueState = 1 dropLowestCountState = 2 dropHighestCountState = 3 plusModifierState = 4 minusModifierState = 5 state = defaultState for piece in pieces: if state == defaultState: if piece == 'd': state = diceValueState elif piece == 'x': state = dropLowestCountState elif piece == 'h': state = dropHighestCountState elif piece == '-': state = minusModifierState elif piece == '+': state = plusModifierState else: if piece == '': diceCount = 1 else: diceCount = int(piece) elif state == diceValueState: diceValue = int(piece) if diceValue < 2: raise ValueError('dice value must be greater than 1') state = defaultState elif state == dropLowestCountState: if piece == '': dropLowestCount = 1 else: dropLowestCount = int(piece) if dropLowestCount < 1: raise ValueError('drop lowest count must be positive') state = defaultState elif state == dropHighestCountState: if piece == '': dropHighestCount = 1 else: dropHighestCount = int(piece) if dropHighestCount < 1: raise ValueError('drop highest count must be positive') elif state == plusModifierState: if piece == '': modifier = 1 else: modifier = int(piece) state = defaultState elif state == minusModifierState: if piece == '': modifier = -1 else: modifier = -int(piece) state = defaultState if diceCount == 0: diceCount = 1 if dropLowestCount != 0 and diceValue == 0: raise ValueError('dice expression requires \'d\' if \'x\' is used') if dropHighestCount != 0 and diceValue == 0: raise ValueError('dice expression requires \'d\' if \'h\' is used') if (dropLowestCount + dropHighestCount) >= diceCount: raise ValueError( 'this dice expression is dropping as many or more dice than are being rolled' ) debugPrint('expression', expr) debugPrint('diceCount', diceCount) debugPrint('diceValue', diceValue) debugPrint('dropLowestCount', dropLowestCount) debugPrint('dropHighestCount', dropHighestCount) debugPrint('modifier', modifier) result.append((diceCount, diceValue, dropLowestCount, dropHighestCount, modifier)) return result