129 lines
3.8 KiB
C
129 lines
3.8 KiB
C
#include "highscore.h"
|
|
#include "bintree.h"
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#define MAX_LINE_LEN 100
|
|
#define MAX_PLAYER_NAME_LEN 20
|
|
|
|
typedef struct {
|
|
char name[MAX_PLAYER_NAME_LEN];
|
|
int score;
|
|
} HighscoreEntry;
|
|
|
|
static TreeNode *highscoreTree = NULL;
|
|
|
|
// Compare two highscore entries by score (descending), then by name
|
|
// (ascending).
|
|
static int compareHighscoreEntries(const void *arg1, const void *arg2) {
|
|
const HighscoreEntry *entry1 = (const HighscoreEntry *)arg1;
|
|
const HighscoreEntry *entry2 = (const HighscoreEntry *)arg2;
|
|
|
|
int result = entry2->score - entry1->score;
|
|
|
|
if (result == 0)
|
|
result = strcmp(entry1->name, entry2->name);
|
|
|
|
return result;
|
|
}
|
|
|
|
// Create a new highscore entry from name and score.
|
|
static HighscoreEntry createHighscoreEntry(const char *name, int score) {
|
|
HighscoreEntry entry = {"", score};
|
|
|
|
if (name != NULL) {
|
|
strncpy(entry.name, name, MAX_PLAYER_NAME_LEN);
|
|
entry.name[MAX_PLAYER_NAME_LEN - 1] = '\0';
|
|
}
|
|
|
|
return entry;
|
|
}
|
|
|
|
// Calculate score based on time used and number of shown numbers.
|
|
static int calculateScore(double timeInSeconds, unsigned int len) {
|
|
return (1000.0 - timeInSeconds) * len;
|
|
}
|
|
|
|
// Load highscores from file into memory.
|
|
void loadHighscores(const char *path) {
|
|
FILE *file = fopen(path, "r");
|
|
|
|
if (file != NULL) {
|
|
char buffer[MAX_LINE_LEN + 1];
|
|
|
|
while (fgets(buffer, MAX_LINE_LEN + 1, file) != NULL) {
|
|
char *name = strtok(buffer, ";\n");
|
|
char *scoreStr = strtok(NULL, ";\n");
|
|
|
|
if (name != NULL && scoreStr != NULL) {
|
|
HighscoreEntry entry =
|
|
createHighscoreEntry(name, strtol(scoreStr, NULL, 10));
|
|
highscoreTree = addToTree(highscoreTree, &entry, sizeof(entry),
|
|
compareHighscoreEntries, NULL);
|
|
}
|
|
}
|
|
|
|
fclose(file);
|
|
}
|
|
}
|
|
|
|
// Add a new highscore entry and return the calculated score.
|
|
int addHighscore(const char *name, double timeInSeconds, unsigned int len) {
|
|
HighscoreEntry entry =
|
|
createHighscoreEntry(name, calculateScore(timeInSeconds, len));
|
|
highscoreTree = addToTree(highscoreTree, &entry, sizeof(entry),
|
|
compareHighscoreEntries, NULL);
|
|
|
|
return entry.score;
|
|
}
|
|
|
|
// Print highscores (up to NUMBER_OF_SHOWN_HIGHSCORES) in a formatted table.
|
|
void showHighscores() {
|
|
const char *blanks =
|
|
" "
|
|
" ";
|
|
const char *stripes =
|
|
"------------------------------------------------------------------------"
|
|
"------------------------------------------------";
|
|
const char *header = "H I G H S C O R E S";
|
|
const int lineWidth = MAX_PLAYER_NAME_LEN + MAX_PLAYER_NAME_LEN + 5;
|
|
|
|
int blankSpace = (int)(lineWidth - strlen(header)) / 2;
|
|
|
|
HighscoreEntry *entry = nextTreeData(highscoreTree);
|
|
|
|
printf("+%*.*s+\n", lineWidth, lineWidth, stripes);
|
|
printf("|%*.*s%s%*.*s|\n", blankSpace, blankSpace, blanks, header, blankSpace,
|
|
blankSpace, blanks);
|
|
printf("+%*.*s+\n", lineWidth, lineWidth, stripes);
|
|
|
|
for (int i = 0; i < NUMBER_OF_SHOWN_HIGHSCORES && entry != NULL; i++) {
|
|
printf("| %-*s | %*d |\n", MAX_PLAYER_NAME_LEN, entry->name,
|
|
MAX_PLAYER_NAME_LEN, entry->score);
|
|
printf("+%*.*s+\n", lineWidth, lineWidth, stripes);
|
|
entry = nextTreeData(NULL);
|
|
}
|
|
}
|
|
|
|
// Save highscores to file (up to NUMBER_OF_SHOWN_HIGHSCORES).
|
|
void saveHighscores(const char *path) {
|
|
FILE *file = fopen(path, "w");
|
|
|
|
if (file != NULL) {
|
|
HighscoreEntry *entry = nextTreeData(highscoreTree);
|
|
|
|
for (int i = 0; i < NUMBER_OF_SHOWN_HIGHSCORES && entry != NULL; i++) {
|
|
fprintf(file, "%s;%d\n", entry->name, entry->score);
|
|
entry = nextTreeData(NULL);
|
|
}
|
|
|
|
fclose(file);
|
|
}
|
|
}
|
|
|
|
// Free all memory used for highscores.
|
|
void clearHighscores() {
|
|
clearTree(&highscoreTree);
|
|
highscoreTree = NULL;
|
|
} |