Changeset ebe70f1 in mainline for uspace/app/tetris/scores.c
- Timestamp:
- 2009-06-09T11:10:31Z (15 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- f3afd24
- Parents:
- 080ad7f
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/app/tetris/scores.c
r080ad7f rebe70f1 37 37 38 38 /** @addtogroup tetris 39 * @{ 39 * @{ 40 40 */ 41 41 /** @file … … 49 49 * Major whacks since then. 50 50 */ 51 51 52 #include <errno.h> 52 /* #include <err.h> */53 /* #include <fcntl.h> */54 /* #include <pwd.h> */55 53 #include <stdio.h> 56 /* #include <stdlib.h> */57 54 #include <string.h> 58 55 #include <io/console.h> … … 60 57 #include <vfs/vfs.h> 61 58 #include <stdlib.h> 62 /* #include <time.h> */ 63 /* #include <term.h> */ 64 /* #include <unistd.h> */ 65 /* #include <sys/param.h> */ 66 /* #include <sys/stat.h> */ 67 /* #include <sys/types.h> */ 68 69 #include "pathnames.h" 59 #include <fcntl.h> 60 #include <err.h> 61 #include <time.h> 62 70 63 #include "screen.h" 71 64 #include "tetris.h" … … 80 73 * that level. 81 74 */ 82 #define NUMSPOTS (MAXHISCORES + 1) 83 #define NLEVELS (MAXLEVEL + 1) 84 85 /* static time_t now; */ 86 /* static int nscores; */ 87 /* static int gotscores; */ 88 /* static struct highscore scores[NUMSPOTS]; */ 75 76 #define NUMSPOTS (MAXHISCORES + 1) 77 #define NLEVELS (MAXLEVEL + 1) 78 89 79 static struct highscore scores[NUMSPOTS]; 90 80 91 /* static int checkscores(struct highscore *, int); */ 92 /* static int cmpscores(const void *, const void *); */ 93 /* static void getscores(FILE **); */ 94 /* static void printem(int, int, struct highscore *, int, const char *); */ 95 /* static char *thisuser(void); */ 81 /** Copy from hiscore table score with index src to dest 82 * 83 */ 84 static void copyhiscore(int dest, int src) 85 { 86 str_cpy(scores[dest].hs_name, STR_BOUNDS(MAXLOGNAME) + 1, 87 scores[src].hs_name); 88 scores[dest].hs_score = scores[src].hs_score; 89 scores[dest].hs_level = scores[src].hs_level; 90 } 96 91 97 92 void showscores(int firstgame) … … 103 98 printf("\tRank \tLevel \tName\t points\n"); 104 99 printf("\t========================================================\n"); 105 for (i = 0; i < NUMSPOTS - 1; i++) { 106 printf("\t%6d %6d %-16s %20d\n", i+1, scores[i].hs_level, scores[i].hs_name, scores[i].hs_score); 107 } 100 101 for (i = 0; i < NUMSPOTS - 1; i++) 102 printf("\t%6d %6d %-16s %20d\n", 103 i + 1, scores[i].hs_level, scores[i].hs_name, scores[i].hs_score); 104 108 105 if (!firstgame) { 109 106 printf("\t========================================================\n"); 110 printf("\t Last %6d %-16s %20d\n", scores[NUMSPOTS - 1].hs_level, scores[NUMSPOTS - 1].hs_name, scores[NUMSPOTS - 1].hs_score); 107 printf("\t Last %6d %-16s %20d\n", 108 scores[NUMSPOTS - 1].hs_level, scores[NUMSPOTS - 1].hs_name, scores[NUMSPOTS - 1].hs_score); 111 109 } 110 112 111 printf("\n\n\n\n\tPress any key to return to main menu."); 113 112 getchar(); 114 113 } 115 114 116 /** Copy from hiscore table score with index src to dest117 *118 */119 static void copyhiscore(int dest, int src)120 {121 str_cpy(scores[dest].hs_name, STR_BOUNDS(MAXLOGNAME) + 1,122 scores[src].hs_name);123 scores[dest].hs_score = scores[src].hs_score;124 scores[dest].hs_level = scores[src].hs_level;125 }126 127 115 void insertscore(int score, int level) 128 116 { 129 int i,j; 117 int i; 118 int j; 130 119 size_t off; 131 120 console_event_t ev; 132 121 133 122 clear_screen(); 134 moveto(10 123 moveto(10, 10); 135 124 puts("Insert your name: "); 136 125 str_cpy(scores[NUMSPOTS - 1].hs_name, STR_BOUNDS(MAXLOGNAME) + 1, 137 126 "Player"); 138 i = 6; off = 6; 139 127 i = 6; 128 off = 6; 129 140 130 moveto(10 , 28); 141 printf("%s%.*s",scores[NUMSPOTS - 1].hs_name,MAXLOGNAME-i,"........................................"); 142 131 printf("%s%.*s", scores[NUMSPOTS - 1].hs_name, MAXLOGNAME-i, 132 "........................................"); 133 143 134 while (1) { 144 135 fflush(stdout); 145 136 if (!console_get_event(fphone(stdin), &ev)) 146 137 exit(1); 147 138 148 139 if (ev.type == KEY_RELEASE) 149 140 continue; 150 141 151 142 if (ev.key == KC_ENTER || ev.key == KC_NENTER) 152 143 break; 153 144 154 145 if (ev.key == KC_BACKSPACE) { 155 146 if (i > 0) { 156 147 wchar_t uc; 157 148 158 149 --i; 159 150 while (off > 0) { … … 165 156 break; 166 157 } 167 158 168 159 scores[NUMSPOTS - 1].hs_name[off] = '\0'; 169 160 } … … 178 169 } 179 170 180 moveto(10 , 28); 181 printf("%s%.*s",scores[NUMSPOTS - 1].hs_name,MAXLOGNAME-i,"........................................"); 171 moveto(10, 28); 172 printf("%s%.*s", scores[NUMSPOTS - 1].hs_name, MAXLOGNAME - i, 173 "........................................"); 182 174 } 183 175 184 scores[NUMSPOTS - 1].hs_score = score; 176 scores[NUMSPOTS - 1].hs_score = score; 185 177 scores[NUMSPOTS - 1].hs_level = level; 186 178 187 i = NUMSPOTS -1;179 i = NUMSPOTS - 1; 188 180 while ((i > 0) && (scores[i - 1].hs_score < score)) 189 181 i--; 190 191 for (j = NUMSPOTS - 2; j > i; j--) { 192 copyhiscore(j,j-1); 182 183 for (j = NUMSPOTS - 2; j > i; j--) 184 copyhiscore(j, j-1); 185 186 copyhiscore(i, NUMSPOTS - 1); 187 } 188 189 void initscores(void) 190 { 191 int i; 192 for (i = 0; i < NUMSPOTS; i++) { 193 str_cpy(scores[i].hs_name, STR_BOUNDS(MAXLOGNAME) + 1, "HelenOS Team"); 194 scores[i].hs_score = (NUMSPOTS - i) * 200; 195 scores[i].hs_level = (i + 1 > MAXLEVEL ? MAXLEVEL : i + 1); 193 196 } 194 copyhiscore(i, NUMSPOTS - 1); 195 } 196 197 void initscores(void) 198 { 199 int i; 200 for(i = 0; i < NUMSPOTS; i++) { 201 str_cpy(scores[i].hs_name, STR_BOUNDS(MAXLOGNAME) + 1, "HelenOS Team"); 202 scores[i].hs_score = (NUMSPOTS - i) * 200; 203 scores[i].hs_level = (i + 1 > MAXLEVEL?MAXLEVEL:i + 1); 204 } 205 } 206 207 /* 208 * Read the score file. Can be called from savescore (before showscores) 209 * or showscores (if savescore will not be called). If the given pointer 210 * is not NULL, sets *fpp to an open file pointer that corresponds to a 211 * read/write score file that is locked with LOCK_EX. Otherwise, the 212 * file is locked with LOCK_SH for the read and closed before return. 213 * 214 * Note, we assume closing the stdio file releases the lock. 215 */ 216 /* static void */ 217 /* getscores(FILE **fpp) */ 218 /* { */ 219 /* int sd, mint, lck, mask, i; */ 220 /* char *mstr, *human; */ 221 /* FILE *sf; */ 222 223 /* if (fpp != NULL) { */ 224 /* mint = O_RDWR | O_CREAT; */ 225 /* mstr = "r+"; */ 226 /* human = "read/write"; */ 227 /* lck = LOCK_EX; */ 228 /* } else { */ 229 /* mint = O_RDONLY; */ 230 /* mstr = "r"; */ 231 /* human = "reading"; */ 232 /* lck = LOCK_SH; */ 233 /* } */ 234 /* setegid(egid); */ 235 /* mask = umask(S_IWOTH); */ 236 /* sd = open(_PATH_SCOREFILE, mint, 0666); */ 237 /* (void)umask(mask); */ 238 /* setegid(gid); */ 239 /* if (sd < 0) { */ 240 /* if (fpp == NULL) { */ 241 /* nscores = 0; */ 242 /* return; */ 243 /* } */ 244 /* err(1, "cannot open %s for %s", _PATH_SCOREFILE, human); */ 245 /* } */ 246 /* setegid(egid); */ 247 /* if ((sf = fdopen(sd, mstr)) == NULL) */ 248 /* err(1, "cannot fdopen %s for %s", _PATH_SCOREFILE, human); */ 249 /* setegid(gid); */ 250 251 /* /\* */ 252 /* * Grab a lock. */ 253 /* *\/ */ 254 /* if (flock(sd, lck)) */ 255 /* warn("warning: score file %s cannot be locked", */ 256 /* _PATH_SCOREFILE); */ 257 258 /* nscores = fread(scores, sizeof(scores[0]), MAXHISCORES, sf); */ 259 /* if (ferror(sf)) */ 260 /* err(1, "error reading %s", _PATH_SCOREFILE); */ 261 /* for (i = 0; i < nscores; i++) */ 262 /* if (scores[i].hs_level < MINLEVEL || */ 263 /* scores[i].hs_level > MAXLEVEL) */ 264 /* errx(1, "scorefile %s corrupt", _PATH_SCOREFILE); */ 265 266 /* if (fpp) */ 267 /* *fpp = sf; */ 268 /* else */ 269 /* (void)fclose(sf); */ 270 /* } */ 271 272 void 273 savescore(int level) 274 { 275 return; 276 } 277 /* struct highscore *sp; */ 278 /* int i; */ 279 /* int change; */ 280 /* FILE *sf; */ 281 /* const char *me; */ 282 283 /* getscores(&sf); */ 284 /* gotscores = 1; */ 285 /* (void)time(&now); */ 286 287 /* /\* */ 288 /* * Allow at most one score per person per level -- see if we */ 289 /* * can replace an existing score, or (easiest) do nothing. */ 290 /* * Otherwise add new score at end (there is always room). */ 291 /* *\/ */ 292 /* change = 0; */ 293 /* me = thisuser(); */ 294 /* for (i = 0, sp = &scores[0]; i < nscores; i++, sp++) { */ 295 /* if (sp->hs_level != level || str_cmp(sp->hs_name, me) != 0) */ 296 /* continue; */ 297 /* if (score > sp->hs_score) { */ 298 /* (void)printf("%s bettered %s %d score of %d!\n", */ 299 /* "\nYou", "your old level", level, */ 300 /* sp->hs_score * sp->hs_level); */ 301 /* sp->hs_score = score; /\* new score *\/ */ 302 /* sp->hs_time = now; /\* and time *\/ */ 303 /* change = 1; */ 304 /* } else if (score == sp->hs_score) { */ 305 /* (void)printf("%s tied %s %d high score.\n", */ 306 /* "\nYou", "your old level", level); */ 307 /* sp->hs_time = now; /\* renew it *\/ */ 308 /* change = 1; /\* gotta rewrite, sigh *\/ */ 309 /* } /\* else new score < old score: do nothing *\/ */ 310 /* break; */ 311 /* } */ 312 /* if (i >= nscores) { */ 313 /* strlcpy(sp->hs_name, me, sizeof sp->hs_name); */ 314 /* sp->hs_level = level; */ 315 /* sp->hs_score = score; */ 316 /* sp->hs_time = now; */ 317 /* nscores++; */ 318 /* change = 1; */ 319 /* } */ 320 321 /* if (change) { */ 322 /* /\* */ 323 /* * Sort & clean the scores, then rewrite. */ 324 /* *\/ */ 325 /* nscores = checkscores(scores, nscores); */ 326 /* rewind(sf); */ 327 /* if (fwrite(scores, sizeof(*sp), nscores, sf) != nscores || */ 328 /* fflush(sf) == EOF) */ 329 /* warnx("error writing %s: %s\n\t-- %s", */ 330 /* _PATH_SCOREFILE, strerror(errno), */ 331 /* "high scores may be damaged"); */ 332 /* } */ 333 /* (void)fclose(sf); /\* releases lock *\/ */ 334 /* } */ 335 336 /* 337 * Get login name, or if that fails, get something suitable. 338 * The result is always trimmed to fit in a score. 339 */ 340 /* static char * */ 341 /* thisuser(void) */ 342 /* { */ 343 /* const char *p; */ 344 /* struct passwd *pw; */ 345 /* static char u[sizeof(scores[0].hs_name)]; */ 346 347 /* if (u[0]) */ 348 /* return (u); */ 349 /* p = getlogin(); */ 350 /* if (p == NULL || *p == '\0') { */ 351 /* pw = getpwuid(getuid()); */ 352 /* if (pw != NULL) */ 353 /* p = pw->pw_name; */ 354 /* else */ 355 /* p = " ???"; */ 356 /* } */ 357 /* strlcpy(u, p, sizeof(u)); */ 358 /* return (u); */ 359 /* } */ 360 361 /* 362 * Score comparison function for qsort. 363 * 364 * If two scores are equal, the person who had the score first is 365 * listed first in the highscore file. 366 */ 367 /* static int */ 368 /* cmpscores(const void *x, const void *y) */ 369 /* { */ 370 /* const struct highscore *a, *b; */ 371 /* long l; */ 372 373 /* a = x; */ 374 /* b = y; */ 375 /* l = (long)b->hs_level * b->hs_score - (long)a->hs_level * a->hs_score; */ 376 /* if (l < 0) */ 377 /* return (-1); */ 378 /* if (l > 0) */ 379 /* return (1); */ 380 /* if (a->hs_time < b->hs_time) */ 381 /* return (-1); */ 382 /* if (a->hs_time > b->hs_time) */ 383 /* return (1); */ 384 /* return (0); */ 385 /* } */ 386 387 /* 388 * If we've added a score to the file, we need to check the file and ensure 389 * that this player has only a few entries. The number of entries is 390 * controlled by MAXSCORES, and is to ensure that the highscore file is not 391 * monopolised by just a few people. People who no longer have accounts are 392 * only allowed the highest score. Scores older than EXPIRATION seconds are 393 * removed, unless they are someone's personal best. 394 * Caveat: the highest score on each level is always kept. 395 */ 396 /* static int */ 397 /* checkscores(struct highscore *hs, int num) */ 398 /* { */ 399 /* struct highscore *sp; */ 400 /* int i, j, k, numnames; */ 401 /* int levelfound[NLEVELS]; */ 402 /* struct peruser { */ 403 /* char *name; */ 404 /* int times; */ 405 /* } count[NUMSPOTS]; */ 406 /* struct peruser *pu; */ 407 408 /* /\* */ 409 /* * Sort so that highest totals come first. */ 410 /* * */ 411 /* * levelfound[i] becomes set when the first high score for that */ 412 /* * level is encountered. By definition this is the highest score. */ 413 /* *\/ */ 414 /* qsort((void *)hs, nscores, sizeof(*hs), cmpscores); */ 415 /* for (i = MINLEVEL; i < NLEVELS; i++) */ 416 /* levelfound[i] = 0; */ 417 /* numnames = 0; */ 418 /* for (i = 0, sp = hs; i < num;) { */ 419 /* /\* */ 420 /* * This is O(n^2), but do you think we care? */ 421 /* *\/ */ 422 /* for (j = 0, pu = count; j < numnames; j++, pu++) */ 423 /* if (str_cmp(sp->hs_name, pu->name) == 0) */ 424 /* break; */ 425 /* if (j == numnames) { */ 426 /* /\* */ 427 /* * Add new user, set per-user count to 1. */ 428 /* *\/ */ 429 /* pu->name = sp->hs_name; */ 430 /* pu->times = 1; */ 431 /* numnames++; */ 432 /* } else { */ 433 /* /\* */ 434 /* * Two ways to keep this score: */ 435 /* * - Not too many (per user), still has acct, & */ 436 /* * score not dated; or */ 437 /* * - High score on this level. */ 438 /* *\/ */ 439 /* if ((pu->times < MAXSCORES && */ 440 /* getpwnam(sp->hs_name) != NULL && */ 441 /* sp->hs_time + EXPIRATION >= now) || */ 442 /* levelfound[sp->hs_level] == 0) */ 443 /* pu->times++; */ 444 /* else { */ 445 /* /\* */ 446 /* * Delete this score, do not count it, */ 447 /* * do not pass go, do not collect $200. */ 448 /* *\/ */ 449 /* num--; */ 450 /* for (k = i; k < num; k++) */ 451 /* hs[k] = hs[k + 1]; */ 452 /* continue; */ 453 /* } */ 454 /* } */ 455 /* levelfound[sp->hs_level] = 1; */ 456 /* i++, sp++; */ 457 /* } */ 458 /* return (num > MAXHISCORES ? MAXHISCORES : num); */ 459 /* } */ 460 461 /* 462 * Show current scores. This must be called after savescore, if 463 * savescore is called at all, for two reasons: 464 * - Showscores munches the time field. 465 * - Even if that were not the case, a new score must be recorded 466 * before it can be shown anyway. 467 */ 468 /* 469 void 470 showscores(int level) 471 { 472 return; 473 } 474 */ 475 /* struct highscore *sp; */ 476 /* int i, n, c; */ 477 /* const char *me; */ 478 /* int levelfound[NLEVELS]; */ 479 480 /* if (!gotscores) */ 481 /* getscores((FILE **)NULL); */ 482 /* (void)printf("\n\t\t Tetris High Scores\n"); */ 483 484 /* /\* */ 485 /* * If level == 0, the person has not played a game but just asked for */ 486 /* * the high scores; we do not need to check for printing in highlight */ 487 /* * mode. If SOstr is null, we can't do highlighting anyway. */ 488 /* *\/ */ 489 /* me = level && SOstr ? thisuser() : NULL; */ 490 491 /* /\* */ 492 /* * Set times to 0 except for high score on each level. */ 493 /* *\/ */ 494 /* for (i = MINLEVEL; i < NLEVELS; i++) */ 495 /* levelfound[i] = 0; */ 496 /* for (i = 0, sp = scores; i < nscores; i++, sp++) { */ 497 /* if (levelfound[sp->hs_level]) */ 498 /* sp->hs_time = 0; */ 499 /* else { */ 500 /* sp->hs_time = 1; */ 501 /* levelfound[sp->hs_level] = 1; */ 502 /* } */ 503 /* } */ 504 505 /* /\* */ 506 /* * Page each screenful of scores. */ 507 /* *\/ */ 508 /* for (i = 0, sp = scores; i < nscores; sp += n) { */ 509 /* n = 20; */ 510 /* if (i + n > nscores) */ 511 /* n = nscores - i; */ 512 /* printem(level, i + 1, sp, n, me); */ 513 /* if ((i += n) < nscores) { */ 514 /* (void)printf("\nHit RETURN to continue."); */ 515 /* (void)fflush(stdout); */ 516 /* while ((c = getchar()) != '\n') */ 517 /* if (c == EOF) */ 518 /* break; */ 519 /* (void)printf("\n"); */ 520 /* } */ 521 /* } */ 522 523 /* if (nscores == 0) */ 524 /* printf("\t\t\t - none to date.\n"); */ 525 /* } */ 526 527 /* static void */ 528 /* printem(int level, int offset, struct highscore *hs, int n, const char *me) */ 529 /* { */ 530 /* struct highscore *sp; */ 531 /* int row, highlight, i; */ 532 /* char buf[100]; */ 533 /* #define TITLE "Rank Score Name (points/level)" */ 534 /* #define TITL2 "==========================================================" */ 535 536 /* printf("%s\n%s\n", TITLE, TITL2); */ 537 538 /* highlight = 0; */ 539 540 /* for (row = 0; row < n; row++) { */ 541 /* sp = &hs[row]; */ 542 /* (void)snprintf(buf, sizeof(buf), */ 543 /* "%3d%c %6d %-31s (%6d on %d)\n", */ 544 /* row + offset, sp->hs_time ? '*' : ' ', */ 545 /* sp->hs_score * sp->hs_level, */ 546 /* sp->hs_name, sp->hs_score, sp->hs_level); */ 547 /* /\* Print leaders every three lines *\/ */ 548 /* if ((row + 1) % 3 == 0) { */ 549 /* for (i = 0; i < sizeof(buf); i++) */ 550 /* if (buf[i] == ' ') */ 551 /* buf[i] = '_'; */ 552 /* } */ 553 /* /\* */ 554 /* * Highlight if appropriate. This works because */ 555 /* * we only get one score per level. */ 556 /* *\/ */ 557 /* if (me != NULL && */ 558 /* sp->hs_level == level && */ 559 /* sp->hs_score == score && */ 560 /* str_cmp(sp->hs_name, me) == 0) { */ 561 /* putpad(SOstr); */ 562 /* highlight = 1; */ 563 /* } */ 564 /* (void)printf("%s", buf); */ 565 /* if (highlight) { */ 566 /* putpad(SEstr); */ 567 /* highlight = 0; */ 568 /* } */ 569 /* } */ 570 /* } */ 197 } 571 198 572 199 /** @} 573 200 */ 574
Note:
See TracChangeset
for help on using the changeset viewer.