I'm a Ruby newbie (started 4 days ago and hey it rhymes!) and decided to code a simple little tool for fun/learning. The following code was the result. It works fine, but I would really appreciate critique from some more experienced Ruby developers. I'm looking for comments on style, verbosity, and any misc. tips/tricks.
By the way, I'm really interested in how I can rewrite the lambda recursion to be more elegant. (ctrl-f for 'lambda recursion')
Note: This is not a Ruby On Rails project. It's a little tool for Eve Online.
require 'rubygems'
require 'reve'
require 'yaml'
BASE_SKILLPOINTS = [0, 250, 1414, 8000, 45255, 256000]
def calc_remaining_sp(rank, from_level, to_level)
sp = BASE_SKILLPOINTS.map { |x| x * rank }
[sp[to_level] - sp[from_level], 0].max
end
def summarize_skills(user_id, api_key)
spec = YAML::load(File.open('ukc_skillsets.yaml'))
api = Reve::API.new user_id, api_key
#skill id => general skill info
skills_list = Hash[api.skill_tree.map { |x| [x.type_id, x] }]
api.characters.each { |char|
char_sheet = api.character_sheet :characterID => char.id
puts ""
puts "Character - #{char.name}"
puts "-------------------------------------------------"
char_skills = Hash[skills_list.map { |id, skill| [skill.name, {:level => 0, :remaining_sp => [], :info => skill}] }]
char_sheet.skills.each do |skill|
skill_name = skills_list[skill.id].name
char_skills[skill_name][:level] = skill.level
end
#compute the sp needed for each skill / each level
char_skills.each_pair do |outer_skill_name, *|
#lambda recursion
calc_prereq_sp = lambda do |skill_name|
prereq_remaining_sp = char_skills[skill_name][:info].required_skills.inject(0) do |sum, prereq_skill|
prereq_skill_name = skills_list[prereq_skill.id].name
#call the lambda
calc_prereq_sp.call prereq_skill_name
sum + char_skills[prereq_skill_name][:remaining_sp][prereq_skill.level]
end
current_skill = char_skills[skill_name]
(0..5).each do |target_level|
char_skills[skill_name][:remaining_sp][target_level] =
(calc_remaining_sp current_skill[:info].rank, current_skill[:level], target_level) +
prereq_remaining_sp
end
end
calc_prereq_sp.call outer_skill_name
end
results = {}
spec.each_pair do |skillset_name, *|
process_skillset = lambda do |name|
details = spec[name]
#puts "#{results} , name = #{name}"
if results.include?(name) == false
#puts "#{details['Prerequisites']}"
remaining_sp = 0
remaining_sp += details['Prerequisites'].inject(0) { |sp_remaining, prereq|
process_skillset.call prereq
sp_remaining + results[prereq][:remaining_sp]
} if (details.include? 'Prerequisites') && (details['Prerequisites'] != nil)
details['Required skills'].each_pair { |required_skill, target_level|
remaining_sp += char_skills[required_skill][:remaining_sp][target_level]
} if (details.include? 'Required skills') && (details['Required skills'] != nil)
results[name] = {:remaining_sp => remaining_sp}
end
end
process_skillset.call skillset_name
end
results.reject {|x| (spec[x].include? 'Private') && (spec[x]['Private'] == true)}.to_a().sort_by {|x|x[1][:remaining_sp]} \
.each { |x, y| puts "#{x} = #{y[:remaining_sp]} sp left\n" }
}
end
#userid, apikey hidden for confidentiality
summarize_skills 'xxxxxxx', 'yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy'
and here's a short snippet of 'ukc_skillsets.yaml'
Basics:
#private = don't show at the end
Private: True
Required skills:
#skill name: skill level
Electronics: 4
Engineering: 4
Weapon Upgrades: 1
Energy Systems Operation: 1
Armor Ship:
Private: True
Prerequisites:
- Basics
Required skills:
Hull Upgrades: 4
Mechanic: 4
......