-
Notifications
You must be signed in to change notification settings - Fork 1
/
leaderboard.c
executable file
·187 lines (170 loc) · 4.87 KB
/
leaderboard.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
/*
* leaderboard.c
*
* Author: Thuan Song Teoh
*
* Logic to display and update leader board. Uses EEPROM for data
* storage.
*/
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/eeprom.h>
#include <avr/pgmspace.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include "serialio.h"
#include "terminalio.h"
#include "score.h"
#include "leaderboard.h"
// Memory address of stored variable in EEPROM
static Highscore EEMEM scores[MAX_NUM];
// High scores are stored as an array of Highscore structures
static Highscore current_score[MAX_NUM];
void retrive_leaderboard(void) {
eeprom_read_block((void*)¤t_score, (const void*)&scores, sizeof(scores));
}
/* Update values stored in EEPROM.
*/
static void update_leaderboard(void) {
eeprom_update_block((const void*)¤t_score, (void*)&scores, sizeof(scores));
}
/* Helper function to compare current scores with scores in leader board.
* Returns -1 if not a new record/zero, else 0 to 4 representing the ranking.
*/
static int8_t compare_score(void) {
uint8_t rank;
if(get_score() > 0) {
for(rank=0;rank<5;rank++) {
// Only compare if value initialised
if(current_score[rank].signature == SIGNATURE) {
if(get_score() > current_score[rank].score) {
return rank;
}
} else {
// Uninitialised value means space available for new record
return rank;
}
}
}
return -1;
}
/* Helper function to reposition old records and add new record.
*/
static void update_scores(char* name, uint8_t rank) {
uint8_t pos;
// Move old records down by 1 ranking to make space for new entry
for(pos=MAX_NUM-1;pos>rank;pos--) {
// Avoid repositioning uninitialised values
if(current_score[pos-1].signature == SIGNATURE) {
current_score[pos] = current_score[pos-1];
}
}
current_score[rank].signature = SIGNATURE;
strcpy(current_score[rank].name, name);
current_score[rank].score = get_score();
}
/* Helper function to get player's initials.
*/
static char* get_initials(void) {
// Initialise empty name at first
char tmp[6];
memset(tmp, 0, 6);
char input;
uint8_t pos = 0;
uint8_t escape_seq = 0;
clear_serial_input_buffer();
while(1) {
// Part of code adapted from project.c to ignore escape sequences
if(serial_input_available()) {
input = fgetc(stdin);
if(input == '\n') {
// Enter key pressed, save name
break;
} else if(escape_seq == 0 && input == ESCAPE_CHAR) {
// We've hit the first character in an escape sequence (escape)
escape_seq++;
} else if(escape_seq == 1 && (input == '[' || input == 'O')) {
// We've hit the second character in an escape sequence
escape_seq++;
} else if(escape_seq == 2) {
// Third (and last) character in the escape sequence
escape_seq = 0;
} else if(isalpha(input) && pos < 5) {
// Only alphabets are valid, maximum of 5 characters
tmp[pos] = input;
pos++;
} else if(input == BACK_SPACE) {
// Backspace key pressed, clear previous character
if(pos > 0) {
pos--;
tmp[pos] = 0;
} else {
tmp[pos] = 0;
}
}
// Redisplay updated name variable
move_cursor(38, 15);
printf_P(PSTR("%-5s"), tmp);
move_cursor(38+pos, 15);
}
}
char* name = " ";
if(tmp[0] != 0) {
strcpy(name, tmp);
} else {
// Save empty names as "Anon"
strcpy(name, "Anon");
}
return name;
}
void is_highscore(void) {
int8_t ranking = compare_score();
if (ranking != -1) {
// Display prompt to enter player initials
clear_terminal();
set_display_attribute(FG_GREEN);
move_cursor(32,8);
printf_P(PSTR("CONGRATULATIONS!"));
normal_display_mode();
move_cursor(28,10);
printf_P(PSTR("You got a new high score!"));
move_cursor(23,12);
printf_P(PSTR("Please enter your initials (max 5)"));
move_cursor(30,13);
printf_P(PSTR("Press enter to save:"));
// Read from stdin
move_cursor(38,15);
set_display_attribute(FG_CYAN);
char* name = get_initials();
normal_display_mode();
move_cursor(38,16);
// Update leader board and store in EEPROM
update_scores(name, ranking);
update_leaderboard();
}
}
void leaderboard_terminal_output(void) {
// Pretty printing of leader board
draw_horizontal_line(15, 0, 79);
move_cursor(34,16);
set_display_attribute(FG_YELLOW);
set_display_attribute(TERM_UNDERSCORE);
printf_P(PSTR("LEADER BOARD"));
normal_display_mode();
move_cursor(29,18);
set_display_attribute(FG_YELLOW);
printf_P(PSTR("Name -> Score"));
normal_display_mode();
uint8_t i;
for(i=0;i<MAX_NUM;i++) {
if(current_score[i].signature == SIGNATURE) {
move_cursor(26,19+i);
printf_P(PSTR("%d. %-5s -> %ld"), i+1, current_score[i].name, current_score[i].score);
} else {
move_cursor(26,19+i);
printf_P(PSTR("%d."), i+1);
}
}
}