/* -------------------------------------------------------------
* Project Euler, Problem #22 (more functions)
*
* Using names.txt (http://p...content-available-to-author-only...r.net/project/names.txt), 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?
*
* Solution by: migf1
* File contents are split and loaded into an ascending-ordered singly linked list
* in one pass. A second pass traverses the list to calculate the total score.
* -------------------------------------------------------------
*/
#include <stdio.h>
#include <string.h> // for strncpy(), strncmp()
#include <stdlib.h> // for calloc(), free()
#define MAX_WLEN 25+1
#define LETTVAL(c) ((c)-'A'+1)
typedef enum { FALSE=0, TRUE } Bool;
typedef struct node {
char word[ MAX_WLEN ]; // the word
struct node *next; // pointer to next node
} Node;
typedef struct {
Node *head, *tail; // pointers to 1st & last nodes
} List;
// ------------------------------------------------------------------------------------
// insert data into list in ascending order
//
Bool list_insert( List *list, char *data )
{
Node *curr = NULL, *prev = NULL;
Node
*new
= calloc( 1, sizeof(struct node
) ); if ( !new || !data ) // calloc failed or invalid data
return FALSE;
strncpy(new
->word
, data
, MAX_WLEN
-1); // initialize newly created node new->next = NULL; // ...
if ( list->head == NULL) { // list was empty, direct insertion
list->head = list->tail = new;
return TRUE;
}
// direct append
if ( strncmp(data
, list
->tail
->word
, MAX_WLEN
) >= 0 ) { list->tail->next = new;
list->tail = new;
return TRUE;
}
curr = prev = list->head; // general case (traversing)
// find spot for the insertion
while ( curr
&& strncmp(curr
->word
, data
, MAX_WLEN
) <= 0 ) { // use <= data, to allow duplicates
prev = curr; // save previous node
curr = curr->next;
}
// insert BEFORE 1st node
if ( list->head == curr /* && curr->data != data */ ) {
list->head = new;
new->next = curr;
return TRUE;
}
// insert AFTER 1st node
if ( !curr
|| strncmp(curr
->word
, data
, MAX_WLEN
) != 0 ) { prev->next = new;
new->next = curr;
}
return TRUE;
}
// ------------------------------------------------------------------------------------
void list_destroy( List *list )
{
Node *dummy = NULL;
while ( list->head ) {
dummy = list->head->next;
list->head = dummy;
}
return;
}
// ------------------------------------------------------------------------------------
int get_stringval( const char *s, const long int pos )
{
if (!s || !*s || pos < 0)
return 0;
int val = 0;
while (*s)
val += LETTVAL(*s++);
return (pos+1) * val;
}
// ------------------------------------------------------------------------------------
long int get_totscore( List list )
{
long int pos, total = 0;
if ( !list.head )
return 0;
for (pos=0; list.head; pos++ ) {
total += get_stringval(list.head->word, pos);
list.head = list.head->next;
}
return total;
}
// ------------------------------------------------------------------------------------
Bool get_fcontents( const char *fname, const char *delims, List *list )
{
FILE
*fp
= fopen(fname
, "r"); char s[ MAX_WLEN ] = {0}; // important! filling up with 0s
if ( !fp || !list) // fopen error or invalid list
return FALSE;
{
fscanf(fp
, delims
, s
); // read next clean word if ( !list_insert( list, s) ) { // if insertion to list fails
list_destroy( list ); // cleanup
return FALSE; // return error status
}
}
return TRUE;
}
// ------------------------------------------------------------------------------------
int main( void )
{
List list = {.head=NULL, .tail=NULL}; // linked list for sorted words
if ( !get_fcontents( "names.txt", "\"%[A-Z]\",", &list ) ) {
puts("*** internal error, aborting program..."); }
printf("%ld\n", get_totscore
(list
) ); // print the total score list_destroy( &list ); // free mem reserved for list
}