116 lines
		
	
	
	
		
			2.1 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable file
		
	
	
	
	
			
		
		
	
	
			116 lines
		
	
	
	
		
			2.1 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable file
		
	
	
	
	
| #!/usr/bin/env bash
 | |
| 
 | |
| die() {
 | |
|   printf "invalid roll: $1\n" "${@:2}" >&2
 | |
|   exit 1
 | |
| }
 | |
| 
 | |
| debug() {
 | |
|   if [[ -v opts[debug] ]]; then
 | |
|     printf "DEBUG: $1\n" "${@:2}"
 | |
|   fi
 | |
| }
 | |
| 
 | |
| verbose() {
 | |
|   if [[ -v opts[verbose] ]]; then
 | |
|     printf "$1\n" "${@:2}"
 | |
|   fi
 | |
| }
 | |
| 
 | |
| is_integer() {
 | |
|   if (( $# )); then
 | |
|     [[ $1 =~ ^[0-9]+$ ]]
 | |
|   else
 | |
|     return 1
 | |
|   fi
 | |
| }
 | |
| 
 | |
| roll_die() {
 | |
|   if (( $# )); then
 | |
|     printf %d "$(( (RANDOM % $1) + 1 ))"
 | |
|   else
 | |
|     printf 0
 | |
|   fi
 | |
| }
 | |
| 
 | |
| declare -A opts
 | |
| 
 | |
| while (( $# )); do
 | |
|   case $1 in
 | |
|   -v)
 | |
|     opts[verbose]=1
 | |
|     ;;
 | |
|   -d)
 | |
|     opts[debug]=1
 | |
|     ;;
 | |
|   -x)
 | |
|     set -x
 | |
|     ;;
 | |
|   -*)
 | |
|     die "unknown option '%s'" "$1"
 | |
|     ;;
 | |
|   *)
 | |
|     break
 | |
|   esac
 | |
| 
 | |
|   shift
 | |
| done
 | |
| 
 | |
| if (( $# )); then
 | |
|   IFS=d read -r quantity rest <<< "$1"
 | |
| 
 | |
|   if [[ -z $quantity ]]; then
 | |
|     quantity=1
 | |
|   elif ! is_integer "$quantity"; then
 | |
|     die "dice quantity is not a number"
 | |
|   fi
 | |
| 
 | |
|   debug "quantity of dice is %d" "$quantity"
 | |
| 
 | |
|   while (( ${#rest} )) && [[ ${rest:0:1} != @(+|-) ]]; do
 | |
|     sides+=${rest:0:1} rest=${rest:1}
 | |
|   done
 | |
| 
 | |
|   if ! is_integer "$sides"; then
 | |
|     die "not a good number of die sides"
 | |
|   fi
 | |
| 
 | |
|   debug "die has %d side(s)" "$sides"
 | |
|   total_mod=0
 | |
| 
 | |
|   while (( ${#rest} )); do
 | |
|     mod_type=${rest:0:1} rest=${rest:1} next_mod=
 | |
| 
 | |
|     while [[ -n $rest && ${rest:0:1} != @(+|-) ]]; do
 | |
|       next_mod+=${rest:0:1} rest=${rest:1}
 | |
|     done
 | |
| 
 | |
|     if ! is_integer "$next_mod"; then
 | |
|       die "'%s' is not a proper modifier" "$next_mod"
 | |
|     elif [[ $mod_type = + ]]; then
 | |
|       (( total_mod += next_mod ))
 | |
|       debug "adding %d to modifier for a total of %d" "$next_mod" "$total_mod"
 | |
|     else
 | |
|       (( total_mod -= next_mod ))
 | |
|       debug "subtracting %d from modifier for a total of %d" "$next_mod" "$total_mod"
 | |
|     fi
 | |
|   done
 | |
| 
 | |
|   score=0 count=0
 | |
| 
 | |
|   while (( quantity-- )); do
 | |
|     roll=$(roll_die "$sides")
 | |
|     (( score += roll ))
 | |
|     debug "rolled a %d. score is now %d" "$roll" "$score"
 | |
|     verbose "roll %d: %d" "$(( count++ ))" "$roll"
 | |
|   done
 | |
| 
 | |
|   verbose "score before modifier: %d" "$score"
 | |
|   (( score += total_mod ))
 | |
|   verbose "score after modifier: %d" "$score"
 | |
|   debug "score total after modifier is %d" "$score"
 | |
| 
 | |
|   if [[ ! -v opts[verbose] ]]; then
 | |
|     printf '%d\n' "$score"
 | |
|   fi
 | |
| fi
 |