def process_help( command: str, ) -> None: """Process help commands. Keyword arguments: command -- A string containing a help command """ # Remove "help " at the beginning and comments. help_command = command.split('#')[0][4:].strip() # Choose the correct help message. if help_command.lower().strip() == 'grid': str_help = 'helpGrid' elif help_command.lower().strip() == 'color': str_help = 'helpColor' elif help_command.lower().strip() == 'lang': str_help = 'helpLang' else: str_help = 'help' # Print the help message. print(wrap( lang[str_help] % { 'lc': ansi.fx(fgc='c', fgl=1, on=settings['colorOn']), 'br': ansi.fx(fgc='r', fxs='b', on=settings['colorOn']), 'blg': ansi.fx(fgc='g', fgl=1, fxs='b', on=settings['colorOn']), 'lg': ansi.fx(fgc='g', fgl=1, on=settings['colorOn']), 'b': ansi.fx(fxs='b', on=settings['colorOn']), 'r': ansi.reset(on=settings['colorOn']), 'prog': 'grid_drawer', } ))
def process_help(command: str, ) -> None: """Process help commands. Keyword arguments: command -- A string containing a help command """ help_key = die[5:].lower().strip() if help_key == 'rolls': str_help = 'helpRolls' elif help_key == 'cond': str_help = 'helpCond' elif help_key == 'stack': str_help = 'helpStack' elif help_key == 'color': str_help = 'helpColor' elif help_key == 'lang': str_help = 'helpLang' elif help_key == 'log': str_help = 'helpLog' elif help_key == 'macro': str_help = 'helpMacro' elif help_key == 'profile': str_help = 'helpProfile' elif help_key == 'verbose': str_help = 'helpVerbose' else: str_help = 'help' print( wrap( lang[str_help] % { 'lc': ansi.fx(fgc='c', fgl=1, on=settings['colorOn']), 'br': ansi.fx(fgc='r', fxs='b', on=settings['colorOn']), 'blg': ansi.fx( fgc='g', fgl=1, fxs='b', on=settings['colorOn']), 'lg': ansi.fx(fgc='g', fgl=1, on=settings['colorOn']), 'b': ansi.fx(fxs='b', on=settings['colorOn']), 'r': ansi.reset(on=settings['colorOn']), 'prog': 'dice_roller', }))
def pre_process( grids: str, ) -> None: """Process commands. Keyword arguments: grids -- A string containing the user's input This function processes all the commands inserted by the user. """ def process_language( command: str, ) -> None: """Process language commands. Keyword arguments: command -- A string containing a language command """ # Remove "lang " at the beginning and comments. lang_command = command.split('#')[0][5:].strip() # List installed languages. if lang_command.lower().startswith('list'): lang_files = glob.glob(os.path.join(lang_path, '*.py')) lang_files.sort() for language in lang_files: if lang_path + lang_prefix in language: lang_code = \ language[:-3].replace(lang_path + lang_prefix, '') print(f' {lang_code}') # Change language. elif lang_command.lower().startswith('file'): language = lang_command[5:].strip() try: exec(f'from {lang_pack}{language} import lang', globals()) settings['lang'] = language save_settings(settings) print(lang['langSwitch']) except ImportError: print(lang['langError'] % language) # Unrecognized command. else: error(command) return None def process_color( command: str, ) -> None: """Process color commands. Keyword arguments: command -- A string containing a color command """ # Remove "color " at the beginning and comments. color_command = command.split('#')[0][6:].strip() # Activate colored text. if color_command[:2].lower() == 'on': settings['colorOn'] = True save_settings(settings) print(lang['colorOn']) # Deactivate colored text. elif color_command[:3].lower() == 'off': settings['colorOn'] = False save_settings(settings) print(lang['colorOff']) # Unrecognized command. else: error(command) return None def process_help( command: str, ) -> None: """Process help commands. Keyword arguments: command -- A string containing a help command """ # Remove "help " at the beginning and comments. help_command = command.split('#')[0][4:].strip() # Choose the correct help message. if help_command.lower().strip() == 'grid': str_help = 'helpGrid' elif help_command.lower().strip() == 'color': str_help = 'helpColor' elif help_command.lower().strip() == 'lang': str_help = 'helpLang' else: str_help = 'help' # Print the help message. print(wrap( lang[str_help] % { 'lc': ansi.fx(fgc='c', fgl=1, on=settings['colorOn']), 'br': ansi.fx(fgc='r', fxs='b', on=settings['colorOn']), 'blg': ansi.fx(fgc='g', fgl=1, fxs='b', on=settings['colorOn']), 'lg': ansi.fx(fgc='g', fgl=1, on=settings['colorOn']), 'b': ansi.fx(fxs='b', on=settings['colorOn']), 'r': ansi.reset(on=settings['colorOn']), 'prog': 'grid_drawer', } )) def process_grid( command: str, ) -> None: """Process grid commands. Keyword arguments: command -- A string containing a grid command """ def xml_line( x1: float, y1: float, x2: float, y2: float, ) -> str: """Create the text for an SVG line. Keyword arguments: x1, y1, x2, y2 -- Coordinates of the initial and final points of the line segment This function returns the XML code for an SVG line. """ return ( f'\t\t\t<line x1="{x1}" y1="{y1}" x2="{x2}" y2="{y2}" ' + 'style="stroke:#777777;stroke-width:1px;" />\n' ) def xml_label( x: float, y: float, font_size: int, label: Union[int, str], ) -> str: """Create the text for an SVG line. Keyword arguments: x, y -- Coordinates of the text label font_size -- A number of pixels label -- The actual text to be displayed This function returns the XML code for an SVG text label. """ return ( f'\t\t\t<text x="{x}" y="{y}" ' + f'style="font-size:{font_size}px;' + f'font-family:sans-serif;fill:#000000;">{label}</text>\n' ) # Parsing the user input. letters = 'ABCDEFGHKLMNPQRSTUVWXYZ' if len(command.split(' ')) == 4: width, height, side, file_name = command.split(' ') side = float(side.strip()) elif len(command.split(' ')) == 3: width, height, file_name = command.split(' ') side = 40 else: error(command) return None if ( int(width) != float(width) or int(width) > len(letters) + len(letters) ** 2 ): error( command, lang['gridWidthError'] % str(len(letters) + len(letters) ** 2), ) return None else: width = int(width.strip()) if int(height) != float(height) or int(height) >= 100: error(command, lang['gridHeightError'] % '99') return None else: height = int(height.strip()) file_name = file_name.strip() if file_name.split('.')[-1] != 'svg': file_name += '.svg' complete_file_name = grids_path + file_name.strip() overwrite = True if os.path.isfile(complete_file_name): while True: answer = input(lang['gridOver']) answer = answer.lower() if answer in lang['yes'] + ['']: break elif answer in lang['no']: overwrite = False break else: continue # File creation. if overwrite: with open(complete_file_name, 'w') as f: img_width = (width + 2) * side + 40 img_height = (height + 2) * side + 40 # XML declaration and svg tag. f.write( '<?xml version="1.0" encoding="UTF-8"?>\n' + f'<svg width="{img_width}" height="{img_height}">\n' + '\t<g>\n' + '\t\t<g>\n' ) # Horizontal lines of the grid. for i in range(height + 1): y = 20 + side * (i + 1) f.write(xml_line(20, y, (width + 2) * side + 20, y)) # Vertical lines of the grid. for i in range(width + 1): x = 20 + side * (i + 1) f.write(xml_line(x, 20, x, (height + 2) * side + 20)) f.write('\t\t</g>\n\t\t<g>\n') # Numerical vertical labels, left and right of the grid. font_size = 2 * side // 3 for i in range(height): x1 = 25 - 2 * font_size * (len(str(i + 1)) - 1) // 5 x2 = \ img_width - 20 - font_size * (len(str(i + 1)) + 4) // 5 y = 13 + side * (i + 2) f.write(xml_label(x1, y, font_size, i + 1)) f.write(xml_label(x2, y, font_size, i + 1)) # Alphabetical horizontal label, above and below the grid. if width <= len(letters): # Only single-letter labels. for i in range(width): x = 20 + side * (i + 1.25) y1 = 10 + side y2 = img_height - 20 - 3 * (side - 10) // 10 f.write(xml_label(x, y1, font_size, letters[i])) f.write(xml_label(x, y2, font_size, letters[i])) else: # Single- and double-letter labels. for i in range(len(letters)): x = 20 + side * (i + 1.25) y1 = 10 + side y2 = img_height - 20 - 3 * (side - 10) // 10 f.write(xml_label(x, y1, font_size, letters[i])) f.write(xml_label(x, y2, font_size, letters[i])) # A different cycle is needed because a double-letter # label has to be positioned differently. letters2 = list(product(letters, repeat=2)) for i in range(width - len(letters)): x = 21 + side * (i + len(letters) + 1) y1 = 10 + side y2 = img_height - 20 - 3 * (font_size) // 10 label = ''.join(letters2[i]) f.write(xml_label(x, y1, font_size, label)) f.write(xml_label(x, y2, font_size, label)) f.write('\t\t</g>\n\t</g>\n</svg>') print(lang['gridComplete'] % file_name) else: print(lang['gridAbort'] % file_name) return None for grid in grids.split(','): try: grid = grid.strip() # Language commands. if grid.lower().startswith('lang '): process_language(grid) # Color commands. elif grid.lower().startswith('color '): process_color(grid) # Help commands. elif grid.lower().startswith('help'): process_help(grid) # Settings commands. elif grid.lower() in ['settings', 's']: print(lang['langName']) get_settings() # Exit commands. elif grid.lower() in ['exit', 'q', 'quit']: print(lang['goodbye'] + '!\n') raise SystemExit # Copyright commands. elif grid.lower() in ['copyright', 'c']: print(wrap(lang['copyright'] % '2017')) # Version commands. elif grid.lower() in ['version', 'v']: print(wrap(lang['version'] % ('grid_drawer', __version__))) # Empty command (feeds new line). elif grid == '': continue # Draw grid. else: process_grid(grid) except KeyboardInterrupt: error(grid, lang['interrupted']) except SystemExit: sys.exit() except Exception: error(grid)
if key.endswith('On'): value = bool(int(value)) settings[key] = value if len(settings['lang']) > 3: settings['lang'] = settings['lang'][0:3] except OSError: # Settings file does not exist. Write a new default settings file. with open(settings_path, 'w') as settings_file: settings_file.write('lang=eng\ncolorOn=1') settings = {'lang': 'eng', 'colorOn': True} exec(f'from {lang_pack}{settings["lang"]} import lang', globals()) bg_green = ansi.fx(bgc='g', fgl=1, on=settings['colorOn']) print(wrap( ansi.clear(on=settings['colorOn']) + lang['welcome'] % ('grid_drawer', __version__, '"help" or "copyright"') )) get_settings() print('') # Main loop. while True: try: grids = input(lang['prompt'] % ( ansi.fx(fgc='c', fgl=1, esc=1, on=settings['colorOn']), ansi.reset(esc=1, on=settings['colorOn']), )) pre_process(grids) print('') # Add an empty line after a grid generation. except EOFError: print('\n' + lang['goodbye'] + '!\n')
def pre_process(dice: str, ) -> None: """Process commands. Keyword arguments: dice -- A string containing the user's input This function processes all the commands inserted by the user. """ def process_conditional(command: str, ) -> None: """Process conditional commands. Keyword arguments: command -- A string containing a conditional command """ die, conditions = command.split('??', 1) conditions = \ [condition.split('::') for condition in conditions.split('&&')] # Prepare repeated conditional rolls. if len(die.split('#')[0].split('x')) == 2: die, max_counter = die.split('#')[0].split('x') multiplier = 'x' + max_counter max_counter = int(max_counter) else: multiplier = '' max_counter = 1 counter = 0 # Repeat conditional rolls. while counter < max_counter: pre_process(die.replace(multiplier, '', 1)) for condition in conditions: cond_test = test(stack[-1], condition[0].strip()) if cond_test == -1: break elif cond_test: pre_process(condition[1].strip()) break if max_counter - counter > 1: print('') counter += 1 return None def process_log(command: str, ) -> None: """Process log commands. Keyword arguments: command -- A string containing a log command """ die = command.split('#')[0][4:].strip() # Activate log. if die.lower() == 'on': settings['logOn'] = True save_settings(settings) print(lang['logOn'] % (bg_green + settings['logFile'][:-4] + ansi.reset(on=settings['colorOn']))) # Deactivate log. elif die.lower() == 'off': settings['logOn'] = False save_settings(settings) print(lang['logOff']) # Set a new log. elif die[:4].lower() == 'file': settings['logFile'] = die[5:].strip() # Add .log extension if necessary. if (len(settings['logFile']) < 5 or settings['logFile'][-4:] != '.log'): settings['logFile'] += '.log' save_settings(settings) print(lang['logSwitch'] % (bg_green + settings['logFile'][:-4] + ansi.reset(on=settings['colorOn']))) # Wrong log command. else: error(command) return None def process_macro(command: str, ) -> None: """Process macro commands. Keyword arguments: command -- A string containing a macro command """ global macro die = command.split('#')[0][6:].strip() # New macro. if die.lower().startswith('set'): macro_name, macro_dice = \ command[6:].strip()[4:].strip().split(' ', 1) macro_dice = macro_dice.split(';') for i in range(len(macro_dice)): macro_dice[i] = macro_dice[i].split('#', 1) # Delete useless spaces. if len(macro_dice[i]) == 1: macro_dice[i] = macro_dice[i][0].replace(' ', '') else: macro_dice[i][0] = macro_dice[i][0].replace(' ', '') macro_dice[i] = \ macro_dice[i][0] + ' #' + macro_dice[i][1].strip() macro_dice = ', '.join(macro_dice) # Overwrite existing macro. if macro_name in macro.keys(): while True: answer = input(lang['macroOver']) answer = answer.lower() if answer in lang['yes'] + ['']: macro[macro_name] = macro_dice save_macro(macro, macro_path + settings['macroFile']) print(lang['macroAdded'] % (ansi.fx(fgc='g', fgl=1, on=settings['colorOn']), macro_name, ansi.reset(on=settings['colorOn']))) break elif answer in lang['no']: print(lang['macroNotAdded'] % (ansi.fx(fgc='r', fgl=1, on=settings['colorOn']), macro_name, ansi.reset(on=settings['colorOn']))) break else: continue # Save new macro. else: macro[macro_name] = macro_dice save_macro(macro, macro_path + settings['macroFile']) print(lang['macroAdded'] % (ansi.fx(fgc='g', fgl=1, on=settings['colorOn']), macro_name, ansi.reset(on=settings['colorOn']))) # Delete macro, if it exists. elif die.lower().startswith('del'): macro_name = die[4:].strip() if macro_name in macro.keys(): macro.pop(macro_name) save_macro(macro, macro_path + settings['macroFile']) print(lang['macroRemoved'] % (ansi.fx(fgc='g', fgl=1, on=settings['colorOn']), macro_name, ansi.reset(on=settings['colorOn']))) else: print(lang['macroNotExisting'] % (ansi.fx(fgc='r', fgl=1, on=settings['colorOn']), macro_name, ansi.reset(on=settings['colorOn']))) # List macro. elif die.lower().startswith('list'): macro_names = list(macro.keys()) macro_names.sort() if len(macro_names) == 0: print(lang['macroEmpty'] % (ansi.fx(fgc='r', fgl=1, on=settings['colorOn']), ansi.reset(on=settings['colorOn']))) else: for name in macro_names: print( ansi.fx(fgc='b', on=settings['colorOn']) + ' ' + name + ansi.reset(on=settings['colorOn']) + ': ' + macro[name]) # Change macro file. elif die.lower().startswith('file'): settings['macroFile'] = die[5:].strip() # Add .macro extension, if necessary. if (len(settings['macroFile']) < 7 or settings['macroFile'][-6] != '.macro'): settings['macroFile'] += '.macro' macro = open_macro(macro_path + settings['macroFile']) save_settings(settings) print(lang['macroSwitch'] % (bg_green + settings['macroFile'][:-6] + ansi.reset(on=settings['colorOn']), len(macro))) else: error(command) return None def process_profile(command: str, ) -> None: """Process profile commands. Keyword arguments: command -- A string containing a profile command """ global macro profile = command.split('#')[0][8:].strip() if profile.lower() == 'list': prof_files = glob.glob(os.path.join(log_path, '*.log')) prof_files.sort() for prof in prof_files: print(' ' + prof[:-4].replace(log_path, '')) else: settings['logFile'] = profile + '.log' settings['macroFile'] = profile + '.macro' macro = open_macro(macro_path + settings['macroFile']) save_settings(settings) print(lang['logSwitch'] % (bg_green + settings['logFile'][:-4] + ansi.reset(on=settings['colorOn']))) print(lang['macroSwitch'] % (bg_green + settings['macroFile'][:-6] + ansi.reset(on=settings['colorOn']), len(macro))) return None def process_language(command: str, ) -> None: """Process language commands. Keyword arguments: command -- A string containing a language command """ die = command.split('#')[0][5:].strip() if die.lower().startswith('list'): lang_files = glob.glob(os.path.join(lang_path, '*.py')) lang_files.sort() for language in lang_files: if lang_path + lang_prefix in language: print(' ' + language[:-3].replace(lang_path + lang_prefix, '')) elif die.lower().startswith('file'): language = die[5:].strip() try: exec(f'from {lang_pack}{language} import lang', globals()) settings['lang'] = language save_settings(settings) print(lang['langSwitch']) except Exception: print(lang['langError'] % language) else: error(command) return None def process_verbose(command: str, ) -> None: """Process verbose commands. Keyword arguments: command -- A string containing a verbose command """ die = command.split('#')[0][8:].strip() if die.lower().startswith('on'): settings['verboseOn'] = True save_settings(settings) print(lang['verboseOn']) elif die.lower().startswith('off'): settings['verboseOn'] = False save_settings(settings) print(lang['verboseOff']) else: error(command) return None def process_color(command: str, ) -> None: """Process color commands. Keyword arguments: command -- A string containing a color command """ die = command.split('#')[0][6:].strip() if die.lower().startswith('on'): settings['colorOn'] = True save_settings(settings) print(lang['colorOn']) elif die.lower().startswith('off'): settings['colorOn'] = False save_settings(settings) print(lang['colorOff']) else: error(command) return None def process_help(command: str, ) -> None: """Process help commands. Keyword arguments: command -- A string containing a help command """ help_key = die[5:].lower().strip() if help_key == 'rolls': str_help = 'helpRolls' elif help_key == 'cond': str_help = 'helpCond' elif help_key == 'stack': str_help = 'helpStack' elif help_key == 'color': str_help = 'helpColor' elif help_key == 'lang': str_help = 'helpLang' elif help_key == 'log': str_help = 'helpLog' elif help_key == 'macro': str_help = 'helpMacro' elif help_key == 'profile': str_help = 'helpProfile' elif help_key == 'verbose': str_help = 'helpVerbose' else: str_help = 'help' print( wrap( lang[str_help] % { 'lc': ansi.fx(fgc='c', fgl=1, on=settings['colorOn']), 'br': ansi.fx(fgc='r', fxs='b', on=settings['colorOn']), 'blg': ansi.fx( fgc='g', fgl=1, fxs='b', on=settings['colorOn']), 'lg': ansi.fx(fgc='g', fgl=1, on=settings['colorOn']), 'b': ansi.fx(fxs='b', on=settings['colorOn']), 'r': ansi.reset(on=settings['colorOn']), 'prog': 'dice_roller', })) def process_test(command: str, ) -> None: """Process test commands. Keyword arguments: command -- A string containing a test command """ repetitions = 10 command = command[1:].strip() # Compose plot title. if '#' in command: die, comment = command.split('#', 1) orig_die = die.split('x')[0] die = die \ .replace(' ', '') \ .replace('%', '100') \ .replace('**', '^') \ .replace('//', '|') \ .split('x')[0] title = f'{comment.strip()} [{orig_die}]' else: title = command.split('x')[0] die = command \ .replace(' ', '') \ .replace('%', '100') \ .replace('**', '^') \ .replace('//', '|') \ .split('x')[0] counter = 0 values = [] tot_results = [] min_dice, max_dice = get_extremes(die) throws = min([(max_dice - min_dice + 1) * 5000, 100000]) bins = [min_dice + x for x in range(max_dice - min_dice + 2)] # Set of throws to study variance between sets. while counter < repetitions: result = [] # Repeatedly throws dice to test their distribution. for i in range(throws): result.append(roll(die)[3]) tot_results += result hist, bins2 = histogram(result, bins=bins, density=True) values.append(hist * 100) counter += 1 results = [[] for x in range(len(values[0]))] for i in range(repetitions): for j in range(len(values[i])): results[j].append(values[i][j]) hist = [] sigma_b = [] # Calculate mean value and standard deviation for every possible value. for result in results: hist.append(mean(result)) sigma_b.append(std(result)) mu_x = mean(tot_results) sigma_x = std(tot_results) mu_y = mean(hist) sigma_y = std(hist) plt.figure() plt.title(title) plt.xlabel( lang['testValue'] + fr' ($\mu$ = {round(mu_x, 2)}, $\sigma$ = {round(sigma_x, 2)})') plt.ylabel(lang['testFreq'] + fr' [%] ($\mu$ = {round(mu_y, 2)}, ' + fr'$\sigma$ = {round(sigma_y, 2)})') plt.bar(bins[:-1], hist, 1, color=['#33CC33', '#55FF55'], yerr=sigma_b, ecolor='k') plt.axis(xmin=min(bins) - 0.5, xmax=max(bins) - 0.5, ymin=0) # Add value labels if there are not too many bars. if len(bins) <= 30: for i in range(len(hist)): x = (bins[i] + bins[i + 1]) // 2 percent = round(hist[i], 2) text = fr'{int(x)}: ({percent}$\pm${round(sigma_b[i], 2)})%' if percent < 0.35 * max(hist): y = percent + 0.021 * max(hist) else: y = 0.015 * max(hist) plt.text( x + 0.2, y, text, rotation='vertical', rotation_mode='anchor', ) return None def process_roll(command: str, ) -> None: """Process roll commands. Keyword arguments: command -- A string containing a roll command """ if '#' in command: die, comment = command.split('#', 1) comment.strip() else: die = command comment = '' # Shouldn't find a macro at this point. if len(die) > 0 and die[0] == '@': error(die[1:], lang['macroError']) return orig_die = die die = die \ .replace(' ', '') \ .replace('%', '100') \ .replace('**', '^') \ .replace('//', '|') # Formats output string. if comment: title = f'{comment} ({orig_die.split("x")[0].strip()})' else: title = orig_die.split('x')[0].strip() # Prepare repeated rolls. if len(die.split('x')) == 2: die, max_counter = die.split('x') max_counter = int(max_counter) else: max_counter = 1 counter = 0 while counter < max_counter: temp_die = die while '{' in temp_die and '}' in temp_die: curly = temp_die[temp_die.index('{'):temp_die.index('}') + 1] pos = int(curly[1:-1]) if pos > 0: pos -= 1 try: temp_die = temp_die.replace(curly, str(stack[pos])) except IndexError: error(temp_die, lang['stackError']) return dice_results = roll(temp_die) if dice_results: stack.append(dice_results[3]) output_num = \ ' ' + \ ansi.fx(fgc='g', fgl=1, on=settings['colorOn']) + \ f'{{{len(stack)}}}' + \ ansi.reset(on=settings['colorOn']) + \ ' ' output = title + ': ' if (dice_results[0] == dice_results[1] and format_dice(dice_results[0]) or not settings['verboseOn']): output += format_dice(dice_results[1]) else: output += \ format_dice(dice_results[0]) + \ ' --> ' + \ format_dice(dice_results[1]) if (dice_results[2] == dice_results[3] or not settings['verboseOn']): output += f' --> {dice_results[3]}' else: output += f' --> {dice_results[2]} --> {dice_results[3]}' print(output_num + output) if settings['logOn']: log_file = open(log_path + settings['logFile'], 'a') log_file.write( time.strftime('%d/%m/%Y %H:%M:%S') + '\t' + output.strip() + '\n') log_file.flush() log_file.close() else: error(die) counter += 1 return None # Replace macros with the actual rolls. for m in macro.keys(): position = 0 for i in range(dice.count('@' + m)): macro_name = dice[dice[position:].find('@' + m):] \ .split(',')[0] \ .split('#')[0] # Replace parameters in macro. params = macro_name.replace('@' + m, '').strip()[1:-1].split('][') position = dice[position:].find('@' + m) + 1 subst = macro[m] for param in params: if param != '': param_name, param_value = param.split('=', 1) subst = subst.replace('[' + param_name + ']', param_value) while '[' + param_name + '=' in subst: pos1 = subst.find('[' + param_name + '=') pos2 = subst[pos1:].find(']') + pos1 + 1 subst = subst.replace(subst[pos1:pos2], param_value) while '[' in subst: pos1 = subst.find('[') pos2 = subst[pos1:].find(']') + pos1 + 1 if '=' in subst[pos1:pos2]: subst = subst.replace( subst[pos1:pos2], subst[pos1 + 1:pos2 - 1].split('=', 1)[1], ) else: subst = subst.replace(subst[pos1:pos2], '0') dice = dice.replace(macro_name, subst) # Parse every roll. plots = False for die in dice.split(','): try: die = die.strip() # Conditional roll. if (die.count('??') > 0 and die.count('::') > 0 and not die.lower().startswith('macro')): process_conditional(die) # Log commands. elif die.lower().startswith('log'): process_log(die) # Macro commands. elif die.lower().startswith('macro'): process_macro(die) # Profile commands. elif die.lower().startswith('profile'): process_profile(die) # Language commands. elif die.lower().startswith('lang'): process_language(die) # Verbose commands. elif die.lower().startswith('verbose'): process_verbose(die) # Color commands. elif die.lower().startswith('color'): process_color(die) # Help commands. elif die.lower().startswith('help'): process_help(die) # Settings commands. elif die.lower() in ['settings', 's']: print(lang['langName']) get_settings() # Exit commands. elif die.lower() in ['exit', 'q', 'quit']: print(lang['goodbye'] + '!\n') raise SystemExit # Copyright commands. elif die.lower() in ['c', 'copyright']: print(wrap(lang['copyright'] % '2015')) # Changelog commands. elif die.lower() == 'changelog': print( wrap( lang['changelog'] % { 'bb': ansi.fx( fgc='b', fxs='b', on=settings['colorOn']), 'r': ansi.reset(on=settings['colorOn']) })) # Version commands. elif die.lower() in ['v', 'version']: print(wrap(lang['version'] % ('dice_roller', __version__))) # Empty commands (feed new line). elif die == '': continue # Comment line. elif die[0] == '#': print(f' {die[1:].strip()}') # Probability distribution tester. elif die[0] == 't': process_test(die) plots = True # Roll dice. else: process_roll(die) except KeyboardInterrupt: error(die, lang['interrupted']) except SystemExit: sys.exit() except Exception: error(die) # Show plots all together. if plots: plt.show()
'lang': 'eng', 'logOn': False, 'verboseOn': True, 'colorOn': True, 'logFile': 'dice.log', 'macroFile': 'dice.macro', } exec(f'from {lang_pack}{settings["lang"]} import lang', globals()) macro = open_macro(macro_path + settings['macroFile']) bg_green = ansi.fx(bgc='g', fgl=1, on=settings['colorOn']) print( wrap( ansi.clear(on=settings['colorOn']) + lang['welcome'] % ( 'dice_roller', __version__, '"help", "copyright" or "changelog"', ))) get_settings() print('') while True: try: dice = input(lang['prompt'] % (ansi.fx(fgc='c', fgl=1, esc=1, on=settings['colorOn']), ansi.reset(esc=1, on=settings['colorOn']))) pre_process(dice) print('') # Add an empty line after a list of rolls. except EOFError: print('\n' + lang['goodbye'] + '!\n') sys.exit()