简体   繁体   中英

Ruby method returns hash values in binary

I wrote a method that takes six names then generates an array of seven random numbers using four 6-sided dice. The lowest value of the four 6-sided dice is dropped, then the remainder is summed to create the value. The value is then added to an array.

Once seven numbers have been generated, the array is then ordered from highest to lowest and the lowest value is dropped. Then the array of names and the array of values are zipped together to create a hash.

This method ensures that the first name in the array of names receives the highest value, and the last name receives the lowest.

This is the result of calling the method:

{:strength=>1, :dexterity=>1, :constitution=>0, :intelligence=>0, :wisdom=>0, :charisma=>1}

As you can see, all the values I receive are either "1" or "0". I have no idea how this is happening.

Here is the code:

module PriorityStatGenerator

  def self.roll_stats(first_stat, second_stat, third_stat, fourth_stat, fifth_stat, sixth_stat)
    stats_priority = [first_stat, second_stat, third_stat, fourth_stat, fifth_stat, sixth_stat].map(&:to_sym)
    roll_array = self.roll

    return Hash[stats_priority.zip(roll_array)]
  end

  private

  def self.roll

    roll_array = []

    7.times {
      roll_array << Array.new(4).map{ 1 + rand(6) }.sort.drop(1).sum
    }
    roll_array.reverse.delete_at(6)
  end
end

This is how I'm calling the method while I'm testing:

render plain: PriorityStatGenerator.roll_stats(params[:prioritize][:first_stat], params[:prioritize][:second_stat], params[:prioritize][:third_stat], params[:prioritize][:fourth_stat], params[:prioritize][:fifth_stat], params[:prioritize][:sixth_stat])

I added require 'priority_stat_generator' where I'm calling the method, so it is properly calling it.

Can someone help me make it return proper values between 1 and 18?

You need to learn to use IRB or PRY to test snippets of your code, or better, learn to use a debugger. They give you insight into what your code is doing.

In IRB:

[7,6,5,4,3,2,1].delete_at(6)
1

In other words, delete_at(6) is doing what it's supposed to, but that's not what you want. Instead, perhaps slicing the array will behave more like you expect:

>> [7,6,5,4,3,2,1][0..-2]
[
    [0] 7,
    [1] 6,
    [2] 5,
    [3] 4,
    [4] 3,
    [5] 2
]

Also, in your code, it's not necessary to return a value when that operation is the last logical step in a method. Ruby will return the last value seen:

Hash[stats_priority.zip(roll_array)]

Here's a refactoring to simplify things and use an actually random number generator, as rand is notoriously terrible :

require 'securerandom'

module PriorityStatGenerator
  def self.roll_stats(*stats)
    Hash[
      stats.map(&:to_sym).zip(self.roll(stats.length).reverse)
    ]
  end

private
  def self.roll(n = 7)
    (n + 1).times.map do
      4.times.map { 1 + SecureRandom.random_number(6) }.sort.drop(1).inject(:+)
    end.sort.last(n)
  end
end

This makes use of inject(:+) so it works in plain Ruby, no ActiveSupport required.

The use of *stats makes the roll_stats function way more flexible. Your version has a very rigid number of parameters, which is confusing and often obnoxious to use. Treating the arguments as an array avoids a lot of the binding on the expectation that there's six of them.

As a note it's not clear why you're making N+1 roles and then discarding the last. That's the same as generating N and discarding none. Maybe you meant to sort them and take the N best?

Update: Added sort and reverse to properly map in terms of priority.

As amadan said, I can't see how you are getting the results you are, but their is a definite bug in your code.

The last line in self.roll is the return value.

roll_array.reverse.delete_at(6)

Which is going to return the value that was deleted. You need to add a new lines to return the roll_array instead of the delete_at value. You are also not sorting your array prior to removing that last item which will give you the wrong values as well.

def self.roll
  roll_array = []
  7.times {
    roll_array << Array.new(4).map{ 1 + rand(6) }.sort.drop(1).sum
  }
  roll_array.sort.drop(1) 
  roll_array
end

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM