source: mainline/uspace/tetris/scores.c@ f1d1f5d3

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since f1d1f5d3 was 0166e99, checked in by jermar <jermar@…>, 17 years ago

Merge the uspace branch.

  • Property mode set to 100644
File size: 15.6 KB
Line 
1/* $OpenBSD: scores.c,v 1.11 2006/04/20 03:25:36 ray Exp $ */
2/* $NetBSD: scores.c,v 1.2 1995/04/22 07:42:38 cgd Exp $ */
3
4/*-
5 * Copyright (c) 1992, 1993
6 * The Regents of the University of California. All rights reserved.
7 *
8 * This code is derived from software contributed to Berkeley by
9 * Chris Torek and Darren F. Provine.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 * @(#)scores.c 8.1 (Berkeley) 5/31/93
36 */
37
38/** @addtogroup tetris
39 * @{
40 */
41/** @file
42 */
43
44/*
45 * Score code for Tetris, by Darren Provine (kilroy@gboro.glassboro.edu)
46 * modified 22 January 1992, to limit the number of entries any one
47 * person has.
48 *
49 * Major whacks since then.
50 */
51#include <errno.h>
52/* #include <err.h> */
53/* #include <fcntl.h> */
54/* #include <pwd.h> */
55 #include <stdio.h>
56/* #include <stdlib.h> */
57#include <string.h>
58/* #include <time.h> */
59/* #include <term.h> */
60/* #include <unistd.h> */
61/* #include <sys/param.h> */
62/* #include <sys/stat.h> */
63/* #include <sys/types.h> */
64
65#include "pathnames.h"
66#include "screen.h"
67#include "tetris.h"
68#include "scores.h"
69
70/*
71 * Within this code, we can hang onto one extra "high score", leaving
72 * room for our current score (whether or not it is high).
73 *
74 * We also sometimes keep tabs on the "highest" score on each level.
75 * As long as the scores are kept sorted, this is simply the first one at
76 * that level.
77 */
78#define NUMSPOTS (MAXHISCORES + 1)
79#define NLEVELS (MAXLEVEL + 1)
80
81/* static time_t now; */
82/* static int nscores; */
83/* static int gotscores; */
84/* static struct highscore scores[NUMSPOTS]; */
85static struct highscore scores[NUMSPOTS];
86
87/* static int checkscores(struct highscore *, int); */
88/* static int cmpscores(const void *, const void *); */
89/* static void getscores(FILE **); */
90/* static void printem(int, int, struct highscore *, int, const char *); */
91/* static char *thisuser(void); */
92
93void showscores(int firstgame)
94{
95 int i;
96
97 clear_screen();
98 moveto(10, 0);
99 printf("\tRank \tLevel \tName\t points\n");
100 printf("\t========================================================\n");
101 for (i = 0; i < NUMSPOTS - 1; i++) {
102 printf("\t%6d %6d %-16s %20d\n", i+1, scores[i].hs_level, scores[i].hs_name, scores[i].hs_score);
103 }
104 if (!firstgame) {
105 printf("\t========================================================\n");
106 printf("\t Last %6d %-16s %20d\n", scores[NUMSPOTS - 1].hs_level, scores[NUMSPOTS - 1].hs_name, scores[NUMSPOTS - 1].hs_score);
107 }
108 printf("\n\n\n\n\tPress any key to return to main menu.");
109 getchar();
110}
111
112/** Copy from hiscore table score with index src to dest
113 *
114 */
115static void copyhiscore(int dest, int src)
116{
117 strcpy(scores[dest].hs_name, scores[src].hs_name);
118 scores[dest].hs_score = scores[src].hs_score;
119 scores[dest].hs_level = scores[src].hs_level;
120}
121
122void insertscore(int score, int level)
123{
124 int i,j;
125 int key;
126
127
128 clear_screen();
129 moveto(10 , 10);
130 puts("Insert your name: ");
131 strncpy(scores[NUMSPOTS - 1].hs_name, "Player", MAXLOGNAME);
132 i = 6;
133
134 moveto(10 , 28);
135 printf("%s%.*s",scores[NUMSPOTS - 1].hs_name,MAXLOGNAME-i,"........................................");
136 key = getchar();
137 while(key != '\n') {
138 if (key == '\b') {
139 if (i > 0)
140 scores[NUMSPOTS - 1].hs_name[--i] = '\0';
141 } else {
142 if (i < (MAXLOGNAME - 1))
143 scores[NUMSPOTS - 1].hs_name[i++] = key;
144 scores[NUMSPOTS - 1].hs_name[i] = '\0';
145 }
146
147 moveto(10 , 28);
148 printf("%s%.*s",scores[NUMSPOTS - 1].hs_name,MAXLOGNAME-i,"........................................");
149
150 key = getchar();
151 }
152
153 scores[NUMSPOTS - 1].hs_score = score;
154 scores[NUMSPOTS - 1].hs_level = level;
155
156 i = NUMSPOTS-1;
157 while ((i > 0) && (scores[i - 1].hs_score < score))
158 i--;
159
160 for (j = NUMSPOTS - 2; j > i; j--) {
161 copyhiscore(j,j-1);
162 }
163 copyhiscore(i, NUMSPOTS - 1);
164}
165
166void initscores(void)
167{
168 int i;
169 for(i = 0; i < NUMSPOTS; i++) {
170 strncpy(scores[i].hs_name, "HelenOS Team", MAXLOGNAME);
171 scores[i].hs_score = (NUMSPOTS - i) * 200;
172 scores[i].hs_level = (i + 1 > MAXLEVEL?MAXLEVEL:i + 1);
173 }
174}
175
176/*
177 * Read the score file. Can be called from savescore (before showscores)
178 * or showscores (if savescore will not be called). If the given pointer
179 * is not NULL, sets *fpp to an open file pointer that corresponds to a
180 * read/write score file that is locked with LOCK_EX. Otherwise, the
181 * file is locked with LOCK_SH for the read and closed before return.
182 *
183 * Note, we assume closing the stdio file releases the lock.
184 */
185/* static void */
186/* getscores(FILE **fpp) */
187/* { */
188/* int sd, mint, lck, mask, i; */
189/* char *mstr, *human; */
190/* FILE *sf; */
191
192/* if (fpp != NULL) { */
193/* mint = O_RDWR | O_CREAT; */
194/* mstr = "r+"; */
195/* human = "read/write"; */
196/* lck = LOCK_EX; */
197/* } else { */
198/* mint = O_RDONLY; */
199/* mstr = "r"; */
200/* human = "reading"; */
201/* lck = LOCK_SH; */
202/* } */
203/* setegid(egid); */
204/* mask = umask(S_IWOTH); */
205/* sd = open(_PATH_SCOREFILE, mint, 0666); */
206/* (void)umask(mask); */
207/* setegid(gid); */
208/* if (sd < 0) { */
209/* if (fpp == NULL) { */
210/* nscores = 0; */
211/* return; */
212/* } */
213/* err(1, "cannot open %s for %s", _PATH_SCOREFILE, human); */
214/* } */
215/* setegid(egid); */
216/* if ((sf = fdopen(sd, mstr)) == NULL) */
217/* err(1, "cannot fdopen %s for %s", _PATH_SCOREFILE, human); */
218/* setegid(gid); */
219
220/* /\* */
221/* * Grab a lock. */
222/* *\/ */
223/* if (flock(sd, lck)) */
224/* warn("warning: score file %s cannot be locked", */
225/* _PATH_SCOREFILE); */
226
227/* nscores = fread(scores, sizeof(scores[0]), MAXHISCORES, sf); */
228/* if (ferror(sf)) */
229/* err(1, "error reading %s", _PATH_SCOREFILE); */
230/* for (i = 0; i < nscores; i++) */
231/* if (scores[i].hs_level < MINLEVEL || */
232/* scores[i].hs_level > MAXLEVEL) */
233/* errx(1, "scorefile %s corrupt", _PATH_SCOREFILE); */
234
235/* if (fpp) */
236/* *fpp = sf; */
237/* else */
238/* (void)fclose(sf); */
239/* } */
240
241void
242savescore(int level)
243{
244 return;
245}
246/* struct highscore *sp; */
247/* int i; */
248/* int change; */
249/* FILE *sf; */
250/* const char *me; */
251
252/* getscores(&sf); */
253/* gotscores = 1; */
254/* (void)time(&now); */
255
256/* /\* */
257/* * Allow at most one score per person per level -- see if we */
258/* * can replace an existing score, or (easiest) do nothing. */
259/* * Otherwise add new score at end (there is always room). */
260/* *\/ */
261/* change = 0; */
262/* me = thisuser(); */
263/* for (i = 0, sp = &scores[0]; i < nscores; i++, sp++) { */
264/* if (sp->hs_level != level || strcmp(sp->hs_name, me) != 0) */
265/* continue; */
266/* if (score > sp->hs_score) { */
267/* (void)printf("%s bettered %s %d score of %d!\n", */
268/* "\nYou", "your old level", level, */
269/* sp->hs_score * sp->hs_level); */
270/* sp->hs_score = score; /\* new score *\/ */
271/* sp->hs_time = now; /\* and time *\/ */
272/* change = 1; */
273/* } else if (score == sp->hs_score) { */
274/* (void)printf("%s tied %s %d high score.\n", */
275/* "\nYou", "your old level", level); */
276/* sp->hs_time = now; /\* renew it *\/ */
277/* change = 1; /\* gotta rewrite, sigh *\/ */
278/* } /\* else new score < old score: do nothing *\/ */
279/* break; */
280/* } */
281/* if (i >= nscores) { */
282/* strlcpy(sp->hs_name, me, sizeof sp->hs_name); */
283/* sp->hs_level = level; */
284/* sp->hs_score = score; */
285/* sp->hs_time = now; */
286/* nscores++; */
287/* change = 1; */
288/* } */
289
290/* if (change) { */
291/* /\* */
292/* * Sort & clean the scores, then rewrite. */
293/* *\/ */
294/* nscores = checkscores(scores, nscores); */
295/* rewind(sf); */
296/* if (fwrite(scores, sizeof(*sp), nscores, sf) != nscores || */
297/* fflush(sf) == EOF) */
298/* warnx("error writing %s: %s\n\t-- %s", */
299/* _PATH_SCOREFILE, strerror(errno), */
300/* "high scores may be damaged"); */
301/* } */
302/* (void)fclose(sf); /\* releases lock *\/ */
303/* } */
304
305/*
306 * Get login name, or if that fails, get something suitable.
307 * The result is always trimmed to fit in a score.
308 */
309/* static char * */
310/* thisuser(void) */
311/* { */
312/* const char *p; */
313/* struct passwd *pw; */
314/* static char u[sizeof(scores[0].hs_name)]; */
315
316/* if (u[0]) */
317/* return (u); */
318/* p = getlogin(); */
319/* if (p == NULL || *p == '\0') { */
320/* pw = getpwuid(getuid()); */
321/* if (pw != NULL) */
322/* p = pw->pw_name; */
323/* else */
324/* p = " ???"; */
325/* } */
326/* strlcpy(u, p, sizeof(u)); */
327/* return (u); */
328/* } */
329
330/*
331 * Score comparison function for qsort.
332 *
333 * If two scores are equal, the person who had the score first is
334 * listed first in the highscore file.
335 */
336/* static int */
337/* cmpscores(const void *x, const void *y) */
338/* { */
339/* const struct highscore *a, *b; */
340/* long l; */
341
342/* a = x; */
343/* b = y; */
344/* l = (long)b->hs_level * b->hs_score - (long)a->hs_level * a->hs_score; */
345/* if (l < 0) */
346/* return (-1); */
347/* if (l > 0) */
348/* return (1); */
349/* if (a->hs_time < b->hs_time) */
350/* return (-1); */
351/* if (a->hs_time > b->hs_time) */
352/* return (1); */
353/* return (0); */
354/* } */
355
356/*
357 * If we've added a score to the file, we need to check the file and ensure
358 * that this player has only a few entries. The number of entries is
359 * controlled by MAXSCORES, and is to ensure that the highscore file is not
360 * monopolised by just a few people. People who no longer have accounts are
361 * only allowed the highest score. Scores older than EXPIRATION seconds are
362 * removed, unless they are someone's personal best.
363 * Caveat: the highest score on each level is always kept.
364 */
365/* static int */
366/* checkscores(struct highscore *hs, int num) */
367/* { */
368/* struct highscore *sp; */
369/* int i, j, k, numnames; */
370/* int levelfound[NLEVELS]; */
371/* struct peruser { */
372/* char *name; */
373/* int times; */
374/* } count[NUMSPOTS]; */
375/* struct peruser *pu; */
376
377/* /\* */
378/* * Sort so that highest totals come first. */
379/* * */
380/* * levelfound[i] becomes set when the first high score for that */
381/* * level is encountered. By definition this is the highest score. */
382/* *\/ */
383/* qsort((void *)hs, nscores, sizeof(*hs), cmpscores); */
384/* for (i = MINLEVEL; i < NLEVELS; i++) */
385/* levelfound[i] = 0; */
386/* numnames = 0; */
387/* for (i = 0, sp = hs; i < num;) { */
388/* /\* */
389/* * This is O(n^2), but do you think we care? */
390/* *\/ */
391/* for (j = 0, pu = count; j < numnames; j++, pu++) */
392/* if (strcmp(sp->hs_name, pu->name) == 0) */
393/* break; */
394/* if (j == numnames) { */
395/* /\* */
396/* * Add new user, set per-user count to 1. */
397/* *\/ */
398/* pu->name = sp->hs_name; */
399/* pu->times = 1; */
400/* numnames++; */
401/* } else { */
402/* /\* */
403/* * Two ways to keep this score: */
404/* * - Not too many (per user), still has acct, & */
405/* * score not dated; or */
406/* * - High score on this level. */
407/* *\/ */
408/* if ((pu->times < MAXSCORES && */
409/* getpwnam(sp->hs_name) != NULL && */
410/* sp->hs_time + EXPIRATION >= now) || */
411/* levelfound[sp->hs_level] == 0) */
412/* pu->times++; */
413/* else { */
414/* /\* */
415/* * Delete this score, do not count it, */
416/* * do not pass go, do not collect $200. */
417/* *\/ */
418/* num--; */
419/* for (k = i; k < num; k++) */
420/* hs[k] = hs[k + 1]; */
421/* continue; */
422/* } */
423/* } */
424/* levelfound[sp->hs_level] = 1; */
425/* i++, sp++; */
426/* } */
427/* return (num > MAXHISCORES ? MAXHISCORES : num); */
428/* } */
429
430/*
431 * Show current scores. This must be called after savescore, if
432 * savescore is called at all, for two reasons:
433 * - Showscores munches the time field.
434 * - Even if that were not the case, a new score must be recorded
435 * before it can be shown anyway.
436 */
437/*
438void
439showscores(int level)
440{
441 return;
442}
443*/
444/* struct highscore *sp; */
445/* int i, n, c; */
446/* const char *me; */
447/* int levelfound[NLEVELS]; */
448
449/* if (!gotscores) */
450/* getscores((FILE **)NULL); */
451/* (void)printf("\n\t\t Tetris High Scores\n"); */
452
453/* /\* */
454/* * If level == 0, the person has not played a game but just asked for */
455/* * the high scores; we do not need to check for printing in highlight */
456/* * mode. If SOstr is null, we can't do highlighting anyway. */
457/* *\/ */
458/* me = level && SOstr ? thisuser() : NULL; */
459
460/* /\* */
461/* * Set times to 0 except for high score on each level. */
462/* *\/ */
463/* for (i = MINLEVEL; i < NLEVELS; i++) */
464/* levelfound[i] = 0; */
465/* for (i = 0, sp = scores; i < nscores; i++, sp++) { */
466/* if (levelfound[sp->hs_level]) */
467/* sp->hs_time = 0; */
468/* else { */
469/* sp->hs_time = 1; */
470/* levelfound[sp->hs_level] = 1; */
471/* } */
472/* } */
473
474/* /\* */
475/* * Page each screenful of scores. */
476/* *\/ */
477/* for (i = 0, sp = scores; i < nscores; sp += n) { */
478/* n = 20; */
479/* if (i + n > nscores) */
480/* n = nscores - i; */
481/* printem(level, i + 1, sp, n, me); */
482/* if ((i += n) < nscores) { */
483/* (void)printf("\nHit RETURN to continue."); */
484/* (void)fflush(stdout); */
485/* while ((c = getchar()) != '\n') */
486/* if (c == EOF) */
487/* break; */
488/* (void)printf("\n"); */
489/* } */
490/* } */
491
492/* if (nscores == 0) */
493/* printf("\t\t\t - none to date.\n"); */
494/* } */
495
496/* static void */
497/* printem(int level, int offset, struct highscore *hs, int n, const char *me) */
498/* { */
499/* struct highscore *sp; */
500/* int row, highlight, i; */
501/* char buf[100]; */
502/* #define TITLE "Rank Score Name (points/level)" */
503/* #define TITL2 "==========================================================" */
504
505/* printf("%s\n%s\n", TITLE, TITL2); */
506
507/* highlight = 0; */
508
509/* for (row = 0; row < n; row++) { */
510/* sp = &hs[row]; */
511/* (void)snprintf(buf, sizeof(buf), */
512/* "%3d%c %6d %-31s (%6d on %d)\n", */
513/* row + offset, sp->hs_time ? '*' : ' ', */
514/* sp->hs_score * sp->hs_level, */
515/* sp->hs_name, sp->hs_score, sp->hs_level); */
516/* /\* Print leaders every three lines *\/ */
517/* if ((row + 1) % 3 == 0) { */
518/* for (i = 0; i < sizeof(buf); i++) */
519/* if (buf[i] == ' ') */
520/* buf[i] = '_'; */
521/* } */
522/* /\* */
523/* * Highlight if appropriate. This works because */
524/* * we only get one score per level. */
525/* *\/ */
526/* if (me != NULL && */
527/* sp->hs_level == level && */
528/* sp->hs_score == score && */
529/* strcmp(sp->hs_name, me) == 0) { */
530/* putpad(SOstr); */
531/* highlight = 1; */
532/* } */
533/* (void)printf("%s", buf); */
534/* if (highlight) { */
535/* putpad(SEstr); */
536/* highlight = 0; */
537/* } */
538/* } */
539/* } */
540
541/** @}
542 */
543
Note: See TracBrowser for help on using the repository browser.