April 14, 2009

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?

This solution's final function follows the problem's definition precisely: sort the file, compute the alphabetical values for each name, then sum the values.

;;; Use the split-sequence library for splitting the names.txt file.
(require 'split-sequence)

(defparameter *ansi-base-code* 64
"Subtract this value from a character's ansi integer value to get
the characters position in the alphabet.")

(defparameter *names-file* "programming/lisp/euler/names.txt"
"The locations of names.txt on my computer.")

(defun char-position (char)
"Returns CHAR's position in the alphabet.
Example: (char #\A) => 1
(char #\C) => 3"
(- (char-int char)

(defun alphabetical-value (string)
"Returns the alphabetical value of STRING. For example, COLIN is worth
3 + 15 + 12 + 9 + 14 = 53"
(reduce #'+ (map 'list (lambda (char)
(char-position char))

(defun name-score (string position)
"Returns the name score of STRING."
(* (alphabetical-value string) position))

(defun name-scores (list)
"Returns a list of the name scores of LIST. Removes any quotes from
the items in LIST before calculating the score."
(let ((alphabetical-position 0))
(mapcar (lambda (name)
(incf alphabetical-position)
(name-score (remove #\" name) alphabetical-position))

(defun parse-file (file delimiter)
"Returns a list of items from FILE parsed by DELIMITER."
(with-open-file (stream file)
(split-sequence:split-sequence delimiter (read-line stream))))

(defun sort-list (list)
"Sorts LIST by alphabetical string value."
(sort list #'string<))

(defun sum-list (list)
"Returns the sum of all the elements in LIST."
(reduce #'+ list))

(defun euler-22 ()
(sum-list (name-scores (sort-list (parse-file *names-file* #\,)))))