bhaberer/cinch-dicebag

View on GitHub
lib/cinch/plugins/dicebag/bag.rb

Summary

Maintainability
A
25 mins
Test Coverage
module Cinch
  module Plugins
    class Dicebag
      # Class to handle rolling of a preset bag of dice.
      class Bag
        attr_accessor :count, :dice, :score

        # Create a new bag
        # @param [Hash] dice_hash Hash of dice, in the format of
        #   { :num_sides => :max_dice_to_roll, ... }
        #   The bag will randomly roll (1-:max_dice_to_roll) :num_sided dice.
        def initialize(dice_hash)
          fail unless good_hash?(dice_hash)
          @dice = dice_hash
          @count = 0
          @score = 0
        end

        def stats
          max_score = @dice.keys.inject(0) { |sum, x| sum + (x * @dice[x]) }
          min_score = @dice.keys.count
          max_count = @dice.values.inject(0) { |sum, x| sum + x }
          min_count = @dice.keys.count
          { min_count: min_count, max_count: max_count,
            min_score: min_score, max_score: max_score }
        end

        # Roll the bag of dice, this will roll the dice and update the current
        #   score and count
        def roll
          dice = die_array
          @score = Die.roll(dice)
          @count = dice.map { |d| d[/(\d+)d\d+/, 1].to_i || 1 }.inject(0, :+)
          return self
        end

        # Simple method to return a flavor text 'size' description based on
        #   how many dice you happened to get in your dicebag roll.
        # @param [Fixnum] size The number of dice in the dicebag.
        # @return [String] Description of the size of the bag.
        def size
          case
          when @count < 1000 then 'tiny'
          when @count < 2000 then 'small'
          when @count < 3000 then 'medium'
          when @count < 4000 then 'large'
          when @count < 5000 then 'hefty'
          else 'massive'
          end
        end

        private

        # Check to make sure that the passed hash of dice looks basically
        #   reasonable.
        # e.g. { 4 => 10, 6 => 20, 100 => 20 }
        def good_hash?(dice_hash)
          dice_hash.keys { |k| return false unless k.is_a?(Integer) }
          dice_hash.values { |k| return false unless k.is_a?(Integer) }
          true
        end

        # Render the @dice hash as an array of rolls to pass to the Die module.
        #   This also is where we randomly select how many dice from the range
        #   are actually rolled.
        def die_array
          @dice.keys.map do |sides|
            "#{rand(@dice[sides] + 1)}d#{sides}"
          end
        end
      end
    end
  end
end