source: mainline/tetris/scores.c@ e1c4849

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since e1c4849 was c0e674a, checked in by Ondrej Palkovsky <ondrap@…>, 19 years ago

Fix incorrect timeout handling in async framework.
Start tweak the tetris code.

  • Property mode set to 100644
File size: 13.4 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/*
39 * Score code for Tetris, by Darren Provine (kilroy@gboro.glassboro.edu)
40 * modified 22 January 1992, to limit the number of entries any one
41 * person has.
42 *
43 * Major whacks since then.
44 */
45#include <errno.h>
46/* #include <err.h> */
47/* #include <fcntl.h> */
48/* #include <pwd.h> */
49/* #include <stdio.h> */
50/* #include <stdlib.h> */
51/* #include <string.h> */
52/* #include <time.h> */
53/* #include <term.h> */
54/* #include <unistd.h> */
55/* #include <sys/param.h> */
56/* #include <sys/stat.h> */
57/* #include <sys/types.h> */
58
59#include "pathnames.h"
60#include "screen.h"
61#include "tetris.h"
62#include "scores.h"
63
64/*
65 * Within this code, we can hang onto one extra "high score", leaving
66 * room for our current score (whether or not it is high).
67 *
68 * We also sometimes keep tabs on the "highest" score on each level.
69 * As long as the scores are kept sorted, this is simply the first one at
70 * that level.
71 */
72#define NUMSPOTS (MAXHISCORES + 1)
73#define NLEVELS (MAXLEVEL + 1)
74
75/* static time_t now; */
76/* static int nscores; */
77/* static int gotscores; */
78/* static struct highscore scores[NUMSPOTS]; */
79
80/* static int checkscores(struct highscore *, int); */
81/* static int cmpscores(const void *, const void *); */
82/* static void getscores(FILE **); */
83/* static void printem(int, int, struct highscore *, int, const char *); */
84/* static char *thisuser(void); */
85
86/*
87 * Read the score file. Can be called from savescore (before showscores)
88 * or showscores (if savescore will not be called). If the given pointer
89 * is not NULL, sets *fpp to an open file pointer that corresponds to a
90 * read/write score file that is locked with LOCK_EX. Otherwise, the
91 * file is locked with LOCK_SH for the read and closed before return.
92 *
93 * Note, we assume closing the stdio file releases the lock.
94 */
95/* static void */
96/* getscores(FILE **fpp) */
97/* { */
98/* int sd, mint, lck, mask, i; */
99/* char *mstr, *human; */
100/* FILE *sf; */
101
102/* if (fpp != NULL) { */
103/* mint = O_RDWR | O_CREAT; */
104/* mstr = "r+"; */
105/* human = "read/write"; */
106/* lck = LOCK_EX; */
107/* } else { */
108/* mint = O_RDONLY; */
109/* mstr = "r"; */
110/* human = "reading"; */
111/* lck = LOCK_SH; */
112/* } */
113/* setegid(egid); */
114/* mask = umask(S_IWOTH); */
115/* sd = open(_PATH_SCOREFILE, mint, 0666); */
116/* (void)umask(mask); */
117/* setegid(gid); */
118/* if (sd < 0) { */
119/* if (fpp == NULL) { */
120/* nscores = 0; */
121/* return; */
122/* } */
123/* err(1, "cannot open %s for %s", _PATH_SCOREFILE, human); */
124/* } */
125/* setegid(egid); */
126/* if ((sf = fdopen(sd, mstr)) == NULL) */
127/* err(1, "cannot fdopen %s for %s", _PATH_SCOREFILE, human); */
128/* setegid(gid); */
129
130/* /\* */
131/* * Grab a lock. */
132/* *\/ */
133/* if (flock(sd, lck)) */
134/* warn("warning: score file %s cannot be locked", */
135/* _PATH_SCOREFILE); */
136
137/* nscores = fread(scores, sizeof(scores[0]), MAXHISCORES, sf); */
138/* if (ferror(sf)) */
139/* err(1, "error reading %s", _PATH_SCOREFILE); */
140/* for (i = 0; i < nscores; i++) */
141/* if (scores[i].hs_level < MINLEVEL || */
142/* scores[i].hs_level > MAXLEVEL) */
143/* errx(1, "scorefile %s corrupt", _PATH_SCOREFILE); */
144
145/* if (fpp) */
146/* *fpp = sf; */
147/* else */
148/* (void)fclose(sf); */
149/* } */
150
151void
152savescore(int level)
153{
154 return;
155}
156/* struct highscore *sp; */
157/* int i; */
158/* int change; */
159/* FILE *sf; */
160/* const char *me; */
161
162/* getscores(&sf); */
163/* gotscores = 1; */
164/* (void)time(&now); */
165
166/* /\* */
167/* * Allow at most one score per person per level -- see if we */
168/* * can replace an existing score, or (easiest) do nothing. */
169/* * Otherwise add new score at end (there is always room). */
170/* *\/ */
171/* change = 0; */
172/* me = thisuser(); */
173/* for (i = 0, sp = &scores[0]; i < nscores; i++, sp++) { */
174/* if (sp->hs_level != level || strcmp(sp->hs_name, me) != 0) */
175/* continue; */
176/* if (score > sp->hs_score) { */
177/* (void)printf("%s bettered %s %d score of %d!\n", */
178/* "\nYou", "your old level", level, */
179/* sp->hs_score * sp->hs_level); */
180/* sp->hs_score = score; /\* new score *\/ */
181/* sp->hs_time = now; /\* and time *\/ */
182/* change = 1; */
183/* } else if (score == sp->hs_score) { */
184/* (void)printf("%s tied %s %d high score.\n", */
185/* "\nYou", "your old level", level); */
186/* sp->hs_time = now; /\* renew it *\/ */
187/* change = 1; /\* gotta rewrite, sigh *\/ */
188/* } /\* else new score < old score: do nothing *\/ */
189/* break; */
190/* } */
191/* if (i >= nscores) { */
192/* strlcpy(sp->hs_name, me, sizeof sp->hs_name); */
193/* sp->hs_level = level; */
194/* sp->hs_score = score; */
195/* sp->hs_time = now; */
196/* nscores++; */
197/* change = 1; */
198/* } */
199
200/* if (change) { */
201/* /\* */
202/* * Sort & clean the scores, then rewrite. */
203/* *\/ */
204/* nscores = checkscores(scores, nscores); */
205/* rewind(sf); */
206/* if (fwrite(scores, sizeof(*sp), nscores, sf) != nscores || */
207/* fflush(sf) == EOF) */
208/* warnx("error writing %s: %s\n\t-- %s", */
209/* _PATH_SCOREFILE, strerror(errno), */
210/* "high scores may be damaged"); */
211/* } */
212/* (void)fclose(sf); /\* releases lock *\/ */
213/* } */
214
215/*
216 * Get login name, or if that fails, get something suitable.
217 * The result is always trimmed to fit in a score.
218 */
219/* static char * */
220/* thisuser(void) */
221/* { */
222/* const char *p; */
223/* struct passwd *pw; */
224/* static char u[sizeof(scores[0].hs_name)]; */
225
226/* if (u[0]) */
227/* return (u); */
228/* p = getlogin(); */
229/* if (p == NULL || *p == '\0') { */
230/* pw = getpwuid(getuid()); */
231/* if (pw != NULL) */
232/* p = pw->pw_name; */
233/* else */
234/* p = " ???"; */
235/* } */
236/* strlcpy(u, p, sizeof(u)); */
237/* return (u); */
238/* } */
239
240/*
241 * Score comparison function for qsort.
242 *
243 * If two scores are equal, the person who had the score first is
244 * listed first in the highscore file.
245 */
246/* static int */
247/* cmpscores(const void *x, const void *y) */
248/* { */
249/* const struct highscore *a, *b; */
250/* long l; */
251
252/* a = x; */
253/* b = y; */
254/* l = (long)b->hs_level * b->hs_score - (long)a->hs_level * a->hs_score; */
255/* if (l < 0) */
256/* return (-1); */
257/* if (l > 0) */
258/* return (1); */
259/* if (a->hs_time < b->hs_time) */
260/* return (-1); */
261/* if (a->hs_time > b->hs_time) */
262/* return (1); */
263/* return (0); */
264/* } */
265
266/*
267 * If we've added a score to the file, we need to check the file and ensure
268 * that this player has only a few entries. The number of entries is
269 * controlled by MAXSCORES, and is to ensure that the highscore file is not
270 * monopolised by just a few people. People who no longer have accounts are
271 * only allowed the highest score. Scores older than EXPIRATION seconds are
272 * removed, unless they are someone's personal best.
273 * Caveat: the highest score on each level is always kept.
274 */
275/* static int */
276/* checkscores(struct highscore *hs, int num) */
277/* { */
278/* struct highscore *sp; */
279/* int i, j, k, numnames; */
280/* int levelfound[NLEVELS]; */
281/* struct peruser { */
282/* char *name; */
283/* int times; */
284/* } count[NUMSPOTS]; */
285/* struct peruser *pu; */
286
287/* /\* */
288/* * Sort so that highest totals come first. */
289/* * */
290/* * levelfound[i] becomes set when the first high score for that */
291/* * level is encountered. By definition this is the highest score. */
292/* *\/ */
293/* qsort((void *)hs, nscores, sizeof(*hs), cmpscores); */
294/* for (i = MINLEVEL; i < NLEVELS; i++) */
295/* levelfound[i] = 0; */
296/* numnames = 0; */
297/* for (i = 0, sp = hs; i < num;) { */
298/* /\* */
299/* * This is O(n^2), but do you think we care? */
300/* *\/ */
301/* for (j = 0, pu = count; j < numnames; j++, pu++) */
302/* if (strcmp(sp->hs_name, pu->name) == 0) */
303/* break; */
304/* if (j == numnames) { */
305/* /\* */
306/* * Add new user, set per-user count to 1. */
307/* *\/ */
308/* pu->name = sp->hs_name; */
309/* pu->times = 1; */
310/* numnames++; */
311/* } else { */
312/* /\* */
313/* * Two ways to keep this score: */
314/* * - Not too many (per user), still has acct, & */
315/* * score not dated; or */
316/* * - High score on this level. */
317/* *\/ */
318/* if ((pu->times < MAXSCORES && */
319/* getpwnam(sp->hs_name) != NULL && */
320/* sp->hs_time + EXPIRATION >= now) || */
321/* levelfound[sp->hs_level] == 0) */
322/* pu->times++; */
323/* else { */
324/* /\* */
325/* * Delete this score, do not count it, */
326/* * do not pass go, do not collect $200. */
327/* *\/ */
328/* num--; */
329/* for (k = i; k < num; k++) */
330/* hs[k] = hs[k + 1]; */
331/* continue; */
332/* } */
333/* } */
334/* levelfound[sp->hs_level] = 1; */
335/* i++, sp++; */
336/* } */
337/* return (num > MAXHISCORES ? MAXHISCORES : num); */
338/* } */
339
340/*
341 * Show current scores. This must be called after savescore, if
342 * savescore is called at all, for two reasons:
343 * - Showscores munches the time field.
344 * - Even if that were not the case, a new score must be recorded
345 * before it can be shown anyway.
346 */
347void
348showscores(int level)
349{
350 return;
351}
352
353/* struct highscore *sp; */
354/* int i, n, c; */
355/* const char *me; */
356/* int levelfound[NLEVELS]; */
357
358/* if (!gotscores) */
359/* getscores((FILE **)NULL); */
360/* (void)printf("\n\t\t Tetris High Scores\n"); */
361
362/* /\* */
363/* * If level == 0, the person has not played a game but just asked for */
364/* * the high scores; we do not need to check for printing in highlight */
365/* * mode. If SOstr is null, we can't do highlighting anyway. */
366/* *\/ */
367/* me = level && SOstr ? thisuser() : NULL; */
368
369/* /\* */
370/* * Set times to 0 except for high score on each level. */
371/* *\/ */
372/* for (i = MINLEVEL; i < NLEVELS; i++) */
373/* levelfound[i] = 0; */
374/* for (i = 0, sp = scores; i < nscores; i++, sp++) { */
375/* if (levelfound[sp->hs_level]) */
376/* sp->hs_time = 0; */
377/* else { */
378/* sp->hs_time = 1; */
379/* levelfound[sp->hs_level] = 1; */
380/* } */
381/* } */
382
383/* /\* */
384/* * Page each screenful of scores. */
385/* *\/ */
386/* for (i = 0, sp = scores; i < nscores; sp += n) { */
387/* n = 20; */
388/* if (i + n > nscores) */
389/* n = nscores - i; */
390/* printem(level, i + 1, sp, n, me); */
391/* if ((i += n) < nscores) { */
392/* (void)printf("\nHit RETURN to continue."); */
393/* (void)fflush(stdout); */
394/* while ((c = getchar()) != '\n') */
395/* if (c == EOF) */
396/* break; */
397/* (void)printf("\n"); */
398/* } */
399/* } */
400
401/* if (nscores == 0) */
402/* printf("\t\t\t - none to date.\n"); */
403/* } */
404
405/* static void */
406/* printem(int level, int offset, struct highscore *hs, int n, const char *me) */
407/* { */
408/* struct highscore *sp; */
409/* int row, highlight, i; */
410/* char buf[100]; */
411/* #define TITLE "Rank Score Name (points/level)" */
412/* #define TITL2 "==========================================================" */
413
414/* printf("%s\n%s\n", TITLE, TITL2); */
415
416/* highlight = 0; */
417
418/* for (row = 0; row < n; row++) { */
419/* sp = &hs[row]; */
420/* (void)snprintf(buf, sizeof(buf), */
421/* "%3d%c %6d %-31s (%6d on %d)\n", */
422/* row + offset, sp->hs_time ? '*' : ' ', */
423/* sp->hs_score * sp->hs_level, */
424/* sp->hs_name, sp->hs_score, sp->hs_level); */
425/* /\* Print leaders every three lines *\/ */
426/* if ((row + 1) % 3 == 0) { */
427/* for (i = 0; i < sizeof(buf); i++) */
428/* if (buf[i] == ' ') */
429/* buf[i] = '_'; */
430/* } */
431/* /\* */
432/* * Highlight if appropriate. This works because */
433/* * we only get one score per level. */
434/* *\/ */
435/* if (me != NULL && */
436/* sp->hs_level == level && */
437/* sp->hs_score == score && */
438/* strcmp(sp->hs_name, me) == 0) { */
439/* putpad(SOstr); */
440/* highlight = 1; */
441/* } */
442/* (void)printf("%s", buf); */
443/* if (highlight) { */
444/* putpad(SEstr); */
445/* highlight = 0; */
446/* } */
447/* } */
448/* } */
Note: See TracBrowser for help on using the repository browser.