klenwell information services : Euler22Ruby

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[0], "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')[0]
    ord = letter.upcase.unpack('C')[0]
    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