## Project Euler #22

return to ProjectEuler

http://projecteuler.net/problem=22

=begin

http://projecteuler.net/problem=22

PROBLEM
Using names.txt (right click and 'Save Link/Target As...'), a 46K text file
containing over five-thousand first names, begin by sorting it into
alphabetical order. Then working out the alphabetical value for each name,
multiply this value by its alphabetical position in the list to obtain a
name score.

For example, when the list is sorted into alphabetical order, COLIN, which
is worth 3 + 15 + 12 + 9 + 14 = 53, is the 938th name in the list. So,
COLIN would obtain a score of 938 * 53 = 49714.

What is the total of all the name scores in the file?

REFERENCES
http://stackoverflow.com/questions/308749/whats-the-opposite-of-chr-in-ruby

PERFORMANCE
real    0m0.327s

=end

#
# Constants / Globals
#
DATA_FILE = "022_data.txt"

def assert_match(value, expected)
raise "value %s != expected %s" % [value, expected] unless value == expected
true
end

#
# Test Case / Solution
#
def test_case
file_contents = read_file(get_full_path(DATA_FILE))
raise "problem reading file %s" % [DATA_FILE] unless
file_contents.length > 1000

names = parse_file(file_contents)
raise "problem parsing file" unless names.length > 5000
assert_match(names, "MARY")

name, index = "COLIN", 938
letter_score = get_letter_score(name)
name_score = get_name_score(name, index)
assert_match(letter_score, 53)
assert_match(name_score, 49714)

puts "test case passed!"
end

def solution
fpath = get_full_path(DATA_FILE)
sum_name_scores_in_file(fpath)
end

#
# Solution Code
#
def sum_name_scores_in_file(fpath)
total_score = 0
contents = read_file(fpath)
names = parse_file(contents).sort

i = 0
names.each do |name|
i += 1;
total_score += get_name_score(name, i)
end

return total_score
end

def get_name_score(name, i)
# name letter score * alphabetical order in file
letter_score = get_letter_score(name)
return letter_score * i;
end

def get_letter_score(name)
letter_score = 0
name.split('').each do | letter |
letter_score += letter_value(letter)
end
return letter_score
end

def letter_value(letter)
ord_A = "A".unpack('C')
ord = letter.upcase.unpack('C')
return ord - ord_A + 1;
end

def parse_file(contents)
names = []
raw_names = contents.split(",")
raw_names.each do |raw_name|
names << raw_name.gsub('"', '').strip
end

return names
end

def get_full_path(fname)
this_dir = File.expand_path(File.dirname(__FILE__))
return File.join(this_dir, fname)
end

def read_file(path)
f = File.open(path)
contents = f.read
f.close
return contents
end

#
# Test Code
#

#
# Main
#
test_case
puts solution