games@tekred.CNA.TEK.COM (04/28/89)
Submitted-by: gmp@rayssdb.RAY.COM (Gregory M. Paris) Posting-number: Volume 6, Issue 66 Archive-name: cubes2/Part08 #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of archive 8 (of 8)." # Contents: Makefile avg.c cubeorder.sh cuberank.6 cubes.h # cubeserver.6 histconv.sh random.c # Wrapped by billr@saab on Thu Apr 27 12:13:41 1989 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'Makefile' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'Makefile'\" else echo shar: Extracting \"'Makefile'\" \(4919 characters\) sed "s/^X//" >'Makefile' <<'END_OF_FILE' X#! /bin/make -f X# vi:set sw=4 ts=4: X XOWNER= gdaemon XGROUP= games XGAMEDIR= /usr/games XGLIBDIR= $(GAMEDIR)/lib XPATHNAME= $(GLIBDIR)/cubeserver XHISTFILE= $(GLIBDIR)/cubes.hist XMONFILE= $(GLIBDIR)/cubes.monikers XMANDIR= /usr/man/man6 XMANPAGES= $(MANDIR)/cubes.6 $(MANDIR)/cubes.long.6 \ X $(MANDIR)/cubestat.6 $(MANDIR)/cuberank.6 \ X $(MANDIR)/cubeserver.6 X X# If you want the server and client to use a UNIX domain socket X# for local connections, define UNIXSOCK here. It must be a pathname X# to a file in a directory where OWNER has write permission. X# X# If you want the server to open an INET domain socket -- allowing X# players from remote systems -- then define INETSOCK. The client X# INET code is compiled in, whether or not INETSOCK is defined. X# X# The server will not run if both UNIXSOCK and INETSOCK are left undefined. X# XSOCKETS= -DUNIXSOCK=\"/usr/tmp/cubesocket\" -DINETSOCK X#SOCKETS= -DINETSOCK X#SOCKETS= -DUNIXSOCK=\"/usr/tmp/cubesocket\" X X# GECOS and LIBGECOS are for special password file gecos field decoding. X# Defining it works only at the author's locale. X#GECOS= -DGECOS X#LIBGECOS= -lgecos XGECOS= XLIBGECOS= X X# if graphics won't work, add -DLONGNAMEBUG to CFLAGS X# I use -OG on our pyramid X#CFLAGS= -OG XCFLAGS= -O XLDFLAGS= X XSRVFLAGS= -DPATHNAME=\"$(PATHNAME)\" -DHISTFILE=\"$(HISTFILE)\" $(SOCKETS) XCLIFLAGS= $(SOCKETS) XHANFLAGS= -DHISTFILE=\"$(HISTFILE)\" XMONFLAGS= -DMONFILE=\"$(MONFILE)\" X XLIBS= -lcurses -ltermcap -lm X XSRVOBJS= cubeserv1.o cubeserv2.o announce.o comptbl.o history.o moniker.o \ X turn.o risk.o tempers.o strategies.o tactics.o dieopts.o random.o XCLIOBJS= cubes.o actions.o screen.o random.o fullname.o XAVGOBJS= avg.o dieopts.o random.o XHSTOBJS= histanal.o comptbl.o history.o tempers.o strategies.o \ X random.o fullname.o XSTTOBJS= cubestat.o X XSRVSRCS= cubeserv1.c cubeserv2.c announce.c comptbl.c history.c moniker.c \ X turn.c risk.c tempers.c strategies.c tactics.c dieopts.c random.c XCLISRCS= cubes.c actions.c screen.c random.c fullname.c XAVGSRCS= avg.c dieopts.c random.c XHSTSRCS= histanal.c comptbl.c history.c tempers.c strategies.c \ X random.c fullname.c XSTTSRCS= cubestat.c X Xall: source cubeserver cubes cuberank cubestat avg \ X cubes.6 cubes.long.6 cubestat.6 cuberank.6 cubeserver.6 Xsource: $(SRVSRCS) $(CLISRCS) $(AVGSRCS) $(HSTSRCS) $(STTSRCS) Xbins: $(GLIBDIR)/cubeserver Xbins: $(GAMEDIR)/cubes $(GAMEDIR)/cubestat $(GAMEDIR)/cuberank Xbins: $(GAMEDIR)/scr Xfiles: $(HISTFILE) $(MONFILE) $(MANPAGES) Xinstall: source all bins files X X$(GLIBDIR)/cubeserver: cubeserver X install -c -m 4100 -o $(OWNER) -g $(GROUP) cubeserver $(GLIBDIR) X X$(GAMEDIR)/cubes: cubes X install -c -m 111 -o $(OWNER) -g $(GROUP) cubes $(GAMEDIR) X install -c -m 111 -o $(OWNER) -g $(GROUP) cubes $(GAMEDIR) X X$(GAMEDIR)/cubestat: cubestat X install -c -m 111 -o $(OWNER) -g $(GROUP) cubestat $(GAMEDIR) X X$(GAMEDIR)/cuberank: cuberank X install -c -m 4111 -o $(OWNER) -g $(GROUP) cuberank $(GAMEDIR) X X$(GAMEDIR)/scr: scr.sh X install -c -m 755 -o $(OWNER) -g $(GROUP) scr.sh $(GAMEDIR)/scr X X Xcubeserver: $(SRVOBJS) X cc $(LDFLAGS) -o cubeserver $(SRVOBJS) $(LIBS) X Xcubes: $(CLIOBJS) X cc $(LDFLAGS) -o cubes $(CLIOBJS) $(LIBS) $(LIBGECOS) X Xavg: $(AVGOBJS) X cc $(LDFLAGS) -o avg $(AVGOBJS) $(LIBS) X Xhistanal cuberank: $(HSTOBJS) X cc $(LDFLAGS) -o histanal $(HSTOBJS) $(LIBS) $(LIBGECOS) X rm -f cuberank ; ln histanal cuberank X Xcubestat: $(STTOBJS) X cc $(LDFLAGS) -o cubestat $(STTOBJS) X X Xcubeserv1.o: cubeserv1.c cubes.h Makefile X cc $(CFLAGS) $(SRVFLAGS) -c cubeserv1.c X Xcubes.o: cubes.c cubes.h Makefile X cc $(CFLAGS) $(CLIFLAGS) -c cubes.c X Xhistanal.o: histanal.c cubes.h Makefile X cc $(CFLAGS) $(HANFLAGS) -c histanal.c X Xmoniker.o: moniker.c cubes.h Makefile X cc $(CFLAGS) $(MONFLAGS) -c moniker.c X Xfullname.o: fullname.c cubes.h Makefile X cc $(CFLAGS) $(GECOS) -c fullname.c X X$(SRVOBJS): cubes.h X$(CLIOBJS): cubes.h X$(AVGOBJS): cubes.h X$(HSTOBJS): cubes.h X$(STTOBJS): cubes.h X X X# we must have a history file, but we need build it only once X$(HISTFILE): Makefile X touch $(HISTFILE) X chown $(OWNER) $(HISTFILE) X chgrp $(GROUP) $(HISTFILE) X chmod 644 $(HISTFILE) X X# we must have a monikers file, but we need build it only once X$(MONFILE): Makefile X touch $(MONFILE) X chown $(OWNER) $(MONFILE) X chgrp $(GROUP) $(MONFILE) X chmod 644 $(MONFILE) X X X$(MANDIR)/cubes.6: cubes.6 X install -c -m 644 cubes.6 $(MANDIR) X X$(MANDIR)/cubes.long.6: cubes.long.6 X install -c -m 644 cubes.long.6 $(MANDIR) X X$(MANDIR)/cubestat.6: cubestat.6 X install -c -m 644 cubestat.6 $(MANDIR) X X$(MANDIR)/cuberank.6: cuberank.6 X install -c -m 644 cuberank.6 $(MANDIR) X X$(MANDIR)/cubeserver.6: cubeserver.6 X install -c -m 644 cubeserver.6 $(MANDIR) X X Xclean: X rm -f *.o cubes cubeserver cuberank histanal cubestat avg cubes.shar* X Xnewsdist: X makekit -p -s50k -ncubes README cube*.6 Makefile *.[ch] *.sh X Xmaildist: X shar README cube*.6 Makefile *.[ch] *.sh >cubes.shar X package cubes.shar 350 END_OF_FILE if test 4919 -ne `wc -c <'Makefile'`; then echo shar: \"'Makefile'\" unpacked with wrong size! fi # end of 'Makefile' fi if test -f 'avg.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'avg.c'\" else echo shar: Extracting \"'avg.c'\" \(5359 characters\) sed "s/^X//" >'avg.c' <<'END_OF_FILE' X/* vi:set sw=4 ts=4: */ X#ifndef lint Xstatic char sccsid[] = "@(#)avg.c 5.1 (G.M. Paris) 89/01/22"; X#endif lint X X/* X** X** cubes 5.1 Copyright 1989 Gregory M. Paris X** Permission granted to redistribute on a no charge basis. X** All other rights are reserved. X** X*/ X X#include <stdio.h> X#include "cubes.h" X Xboolean jokermode = False; X Xextern int optind; Xextern int opterr; Xextern char *optarg; Xextern long atol(); X X#define ROLLS 1000000L /* one million trials */ X Xenum t_c { X T_AOK, /* 5 /* all of a kind */ X T_STR, /* 5 /* straight */ X T_ASMSTR, /* 5 /* assembled straight */ X T_4OK1S, /* 5 /* four of a kind w/ one single */ X T_SMSTR1S, /* 5 /* small straight w/ one single */ X T_3OK2S, /* 5 /* three of a kind w/ two singles */ X T_5S, /* 5 /* five singles */ X T_4OK, /* 4 /* four of a kind */ X T_SMSTR, /* 4 /* small straight */ X T_3OK1S, /* 4 /* three of a kind w/one single */ X T_4S, /* 4 /* four singles */ X T_3OK, /* 3 /* three of a kind */ X T_3S, /* 3 /* three singles */ X T_2S, /* 2 /* two singles */ X T_1S, /* 1 /* one single */ X T_ZIP, /* 0 /* nothing */ X T_SIZE X}; X Xstatic char *t_name[] = { X "all of a kind", X "straight", X "assembled straight", X "four of a kind w/ one single", X "small straight w/ one single", X "three of a kind w/ two singles", X "five singles", X "four of a kind", X "small straight", X "three of a kind w/one single", X "four singles", X "three of a kind", X "three singles", X "two singles", X "one single", X "nothing", X "" X}; X Xmain(ac, av) Xchar *av[]; X{ X register diceset *pd; X register enum t_c t; X register int d, singles, c, r; X diceset dice; X long cnt[(int)T_SIZE]; X long pts[(int)T_SIZE]; X long tpts; X long rolls = ROLLS; X boolean aces_are_fives = False; X int haces = 0; X int held = 0; X X opterr = 0; X while((c = getopt(ac, av, "jfa:h:r:")) >= 0) { X switch(c) { X case 'j': /* toggle jokermode */ X jokermode = (jokermode == True) ? False : True; X break; X case 'f': /* toggle aces_are_fives */ X aces_are_fives = aces_are_fives == True ? False : True; X break; X case 'a': /* number of aces held */ X if((haces = atoi(optarg)) < 0 || haces >= NDICE) { X fprintf(stderr, X "avg: aces must be in range 0 to %d\n", NDICE-1); X exit(1); X } X break; X case 'h': /* number of generic dice held */ X if((held = atoi(optarg)) < 0 || held >= NDICE) { X fprintf(stderr, X "avg: held must be in range 0 to %d\n", NDICE-1); X exit(1); X } X break; X case 'r': /* number of trials */ X if((rolls = atol(optarg)) <= 0) { X fprintf(stderr, "avg: rolls must be positive\n"); X exit(1); X } X break; X default: X fprintf(stderr, X "usage -- avg [-j] [-r rolls] [[-f] -a aces] [-h held]\n"); X exit(1); X } X } X X if(haces + held >= NDICE) { X fprintf(stderr, "avg: aces plus held must be less than %d\n", NDICE); X exit(1); X } X X /* X ** Initialize. X */ X irandom(); X pd = &dice; X for(c = 0;c < (int)T_SIZE;++c) X cnt[c] = pts[c] = 0; X X /* X ** Roll and tally. X */ X for(r = 0;r < rolls;++r) { X initdice(pd); X if(aces_are_fives == True) { X for(d = 0;d < haces;++d) { X pd->d_stat[d] = Held, pd->d_comb[d] = Previous; X pd->d_face[d] = FIVE; X } X } else { X for(d = 0;d < haces;++d) { X pd->d_stat[d] = Held, pd->d_comb[d] = Previous; X pd->d_face[d] = ACE; X } X } X for(;d < haces + held;++d) { X pd->d_stat[d] = Held, pd->d_comb[d] = Previous; X pd->d_face[d] = BADFACE; X } X X rolldice(pd); X evaluate(pd); X X /* X ** Count singles. X */ X switch(pd->d_best) { X case All_of_a_kind: X case Straight: X case Asm_straight: X singles = 0; X break; X default: X for(singles = d = 0;d < NDICE;++d) { X switch(pd->d_comb[d]) { X case Ace: X case Five: X case Joker: X ++singles; X break; X default: X break; X } X } X break; X } X X /* X ** Figure out which tallied combination this is. X */ X switch(pd->d_best) { X default: continue; X case Nothing: t = T_ZIP; break; X case All_of_a_kind: t = T_AOK; break; X case Straight: t = T_STR; break; X case Asm_straight: t = T_ASMSTR; break; X case Four_of_a_kind:t = singles ? T_4OK1S : T_4OK; break; X case Small_straight:t = singles ? T_SMSTR1S : T_SMSTR; break; X case Three_of_a_kind: X switch(singles) { X case 2: t = T_3OK2S; break; X case 1: t = T_3OK1S; break; X case 0: t = T_3OK; break; X } X break; X case Ace: X case Five: X case Joker: X switch(singles) { X case 5: t = T_5S; break; X case 4: t = T_4S; break; X case 3: t = T_3S; break; X case 2: t = T_2S; break; X case 1: t = T_1S; break; X } X break; X } X X /* X ** The value of d_pts_roll is taken as the expectation value of the roll. X ** In the case of All_of_a_kind and Asm_straight, the value must be corrected X ** by subtracting the value of previously held dice. X */ X scoredice(pd); X if(t == T_AOK || t == T_ASMSTR) X pd->d_pts_roll -= haces * (aces_are_fives==True ? P_FIVE : P_ACE); X pts[(int)t] += pd->d_pts_roll; X ++cnt[(int)t]; X } X X /* X ** Print a summary. X */ X tpts = 0; X printf("%-40s %6s %6s %8s\n", X jokermode==True ? "Combination (with Jokers)" : "Combination (no Jokers)", X "Ptsper", "Expect", "Count"); X for(c = 0;c < (int)T_SIZE;++c) { X if(cnt[c] != 0) { X tpts += pts[c]; X printf("%-40s %6ld %6ld %8ld\n", X t_name[c], pts[c] / cnt[c], pts[c] / rolls, cnt[c]); X } X } X printf("%-40s %6s %6ld %8ld\n", "Total", "", tpts / rolls, rolls); X X exit(0); X} END_OF_FILE if test 5359 -ne `wc -c <'avg.c'`; then echo shar: \"'avg.c'\" unpacked with wrong size! fi # end of 'avg.c' fi if test -f 'cubeorder.sh' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'cubeorder.sh'\" else echo shar: Extracting \"'cubeorder.sh'\" \(1021 characters\) sed "s/^X//" >'cubeorder.sh' <<'END_OF_FILE' X: ksh or sh X# vi:set sw=4 ts=4 X# cubeorder: sort players in temperament/strategy order X XPATH=/bin:/usr/games X Xumask 066 Xtmp=/tmp/cubeorder.$$ Xtrap "rm -f $tmp;exit 1" 1 2 3 15 X Xrm -f $tmp Xecho "BEGIN {" > $tmp X Xcuberank -T | awk ' X BEGIN { X n = 1 X } X $1 ~ /[0-9]/ { X printf("\ttemp[%d]=\"%s\"\n", n, $2) X printf("\tthdr[%d]=\"%s\"\n", n, $0) X ++n; X } X END { X printf("\ttemps=%d\n", n) X } X' >> $tmp X Xcuberank -S | awk ' X BEGIN { X n = 1 X } X $1 ~ /[0-9]/ { X printf("\tstrat[%d]=\"%s\"\n", n, $2) X ++n X } X END { X printf("\tstrats=%d\n", n) X } X' >> $tmp X Xcat >> $tmp <<\ENDCAT X} X$1 !~ /[0-9]/ { X hdr = $0 X next X} X{ X nam = substr($9, 1, 3) substr($10, 1, 3) X if(list[nam] == "") X list[nam] = $0 X else X list[nam] = list[nam] "\n" $0 X} XEND { X for(t = 1;t < temps;++t) { X print hdr X for(s = 1;s < strats;++s) { X nam = substr(temp[t], 1, 3) substr(strat[s], 1, 3) X if(list[nam] != "") X print list[nam] X } X print thdr[t] X print "" X } X} XENDCAT X Xcuberank -sP | awk -f $tmp | sed -e 's/_/ /g' X Xrm -f $tmp Xexit 0 END_OF_FILE if test 1021 -ne `wc -c <'cubeorder.sh'`; then echo shar: \"'cubeorder.sh'\" unpacked with wrong size! fi chmod +x 'cubeorder.sh' # end of 'cubeorder.sh' fi if test -f 'cuberank.6' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'cuberank.6'\" else echo shar: Extracting \"'cuberank.6'\" \(5375 characters\) sed "s/^X//" >'cuberank.6' <<'END_OF_FILE' X.TH CUBERANK 6 "cubes 5.1" GMP "UNIX Gaming Manual" X.SH NAME Xcuberank \- cubes player rankings and statistics X.\" X.\" sccsid: @(#)cuberank.6 5.1 (G.M. Paris) 89/01/22 X.\" X.\" X.\" X.\" cubes 5.1 Copyright 1988 Gregory M. Paris X.\" Permission granted to redistribute on a no charge basis. X.\" All other rights are reserved. X.\" X.\" X.SH SYNOPSIS X.B cuberank X[ X.B \-ahlsuCLPRST X] [ X.B \-n rng X[ X.B \-p plr X]] [ X.B \-g gms X] [ X.B plr ... X] X.SH OVERVIEW XThe X.I cuberank Xprogram analyzes the X.IR cubes (6) Xscore file and prints statistics about the players. XThe various command line options allow the user Xto affect which statistics the program displays Xand which players the program provides information about. X.PP XAlthough useful in and of itself, Xcombining multiple calls of X.I cuberank Xwith pipes to X.IR sed (1) Xand/or X.IR awk (1), Xcan provide more concise summaries of player ranking information. XThe shell script /usr/games/scr provides one such summary, Xwhich can be used as is, Xor as an example for your own summary script. X.PP X.SH OUTPUT XDepending on the set of command line options specified, X.I cuberank Xwill produce from seven to twelve columns of information Xabout a selected subset of players who have played X.I cubes Xon this system. XThe columns are defined as follows. X.PP X.IP Heading 12 XDescription X.IP Up Xup next number (displayed using the X.B \-u Xoption) X.IP ## Xthe player's rank (1 being the top rank) X.IP Player Xthe name of the player X.IP GP Xthe number of games played X.IP LG Xthe last game the player played in X(displayed using the X.B \-l Xoption) X.IP WinRt Xwin rate (wins / games played) X.IP GamPt Xaverage points per game (total points / games) X.IP TnPt Xaverage points per turn (sum of turn averages / games) X.IP WgtPt Xweighted points derived from X.BR WinRt , X.BR GamPt , Xand X.BR TnPt X.IP Pr Xthe player's game type preference: X.B \- Xfor no preference, X.B S Xfor Standard, X.B B Xfor Blitz, X.B FS Xfor Forced Standard, X.B FB Xfor Forced Blitz, and X.B ? Xfor fickle X(displayed using the X.B \-P Xoption) X.IP Tmp Xthe three character abbreviation for the player's temperament, Xwhich is the roll-or-hold decision function used by this player X(displayed using the X.B \-P Xoption) X.IP Str Xthe three character abbreviation for the player's strategy, Xwhich is the the die-discarding function used by this player X(displayed using the X.B \-P Xoption) X.PP XThe ranking order is based on the weighted point value, Xso that the player with the highest weighted point value is the Xhighest ranked player (number one). XThe weighted point value is determined using the following formula. X.IP X.B WgtPt X= 1000 * X.B WinRt X+ X.B GamPt X+ X.B TnPt X.PP XThe largest value in each of the X.BR WinRt , X.BR GamPt , X.BR TnPt , Xand X.BR WgtPt Xcolumns is marked with an asterisk. X.SH "COMMAND LINE OPTIONS" XSeveral command line options are provided to alter the output produced by X.IR cuberank . X.IP Option 12 XDescription X.IP \-a XDisplay ``ancient'' records, where ancient records are those Xcorresponding to players that haven't played a game Xin as many games as there are players in the score file. X.IP \-g\ count XTell only about players that have played in the last X.B count Xgames. X.IP \-h XProduce information about human players only. X.IP \-l XDisplay the game number of the last game each player played. X.IP \-n\ range XProduce information only about players ranked within plus or minus X.B range Xof your ranking. X.IP \-p\ plr XUse X.B plr Xas the center for the X.B \-n range Xoption. X.IP \-s XChange spaces in player names to underscores. X(Allows easier X.IR awk ing Xof X.I cuberank Xoutput.) X.IP \-u XList computer players only, in order of decreasing likelihood Xof playing in the next game. X(Due to the random factors involved, Xthere's no guarantee that players at the top of the list will be Xin the next game.) X.IP \-L XDisplay X.RB `` Lifetime '' Xvalues for X.BR WinRt , X.BR GamPt , X.BR TnPt , Xand X.BR WgtPt . XThese values are representative of the complete history of games Xplayed by each player. X.IP \-R XDisplay X.RB `` Recent '' Xvalues for X.BR WinRt , X.BR GamPt , X.BR TnPt , Xand X.BR WgtPt . X.B Recent Xvalues are computed using a moving average with a window of twenty-five games. XThus, these values are representative of each player's recent performance. X.IP \-C XDisplay X.RB `` Combined '' Xvalues for X.BR WinRt , X.BR GamPt , X.BR TnPt , Xand X.BR WgtPt . X.B Combined Xvalues are derived from the mean of the X.B Recent Xand X.B Lifetime Xvalues. X(This is the default.) X.IP \-P XDisplay the player's ``personality.'' XThis option causes the X.BR Pr , X.BR Tmp , Xand X.B Str Xcolumns to be produced. X.IP \-S XTabulate and display statistics for the strategies Xemployed by the players. XThe tabulated values correspond to the subset of Xplayers selected by any other command line options. X.IP \-T XTabulate and display statistics for the temperaments Xof the players. XThe tabulated values correspond to the subset of Xplayers selected by any other command line options. X.IP plr\ ... XRestrict output to that corresponding to the named players. X.PP XTwo other commonly desired options, Xto print the top or bottom of the rankings, Xare not provided, Xas they can be had as easily using the X.IR head (1) Xand X.IR tail (1) Xutilities. X.SH FILES X.ta 3.5i X.nf X/usr/games/lib/cubes.hist the score file X/usr/games/scr summarize cuberank script X.fi X.SH AUTHOR XGreg Paris <gmp@rayssd.ray.com> X.SH "SEE ALSO" Xcubes(6), awk(1), head(1), sed(1), tail(1) END_OF_FILE if test 5375 -ne `wc -c <'cuberank.6'`; then echo shar: \"'cuberank.6'\" unpacked with wrong size! fi # end of 'cuberank.6' fi if test -f 'cubes.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'cubes.h'\" else echo shar: Extracting \"'cubes.h'\" \(12208 characters\) sed "s/^X//" >'cubes.h' <<'END_OF_FILE' X/* vi:set sw=4 ts=4: */ X/* X** sccsid: @(#)cubes.h 5.1 (G.M. Paris) 89/01/22 X*/ X X/* X** X** cubes 5.1 Copyright 1989 Gregory M. Paris X** Permission granted to redistribute on a no charge basis. X** All other rights are reserved. X** X*/ X X/* X** If you don't want Four_of_a_kind or Small_straight, then comment these out. X** Unfortunately, you'll have to recalculate the values in risktbl[] if you do. X** The existence of Jokers is controlled by a cubeserver command line option. X*/ X#define FOUR 4 /* how many in a four of a kind (if defined) */ X#define SMSTR 4 /* number of dice in small straight (if def) */ X#define ASMSTR 5 /* number of dice in assembled straight (if def) */ X X/* X** Although you could change any of the following parameters, the nature of X** the game would be altered. Also, some things like 5o'kind are hard coded X** in places and would not change automatically. Best to leave be. X*/ X#define SIDES 6 /* six sided dice */ X#define NDICE 5 /* number of dice in set */ X#define ONBOARD 500 /* turn score needed to get on scoreboard */ X#define OFFBOARD 500 /* turn score needed to cross WINSCORE thresh */ X#define WINSCORE 10000 /* minimum score needed to win in Standard game */ X#define BLITZSCORE 7500 /* minimum score needed to win in Blitz game */ X#define WINMARGIN 250 /* winner must best others by this margin */ X X/* X** These values are the basis for scoring. Again, if you change them, the X** play of the game will be altered. Leave them as they are. X*/ X#define P_ACEMULT 10 /* ace is worth disproportionate amount */ X#define P_AOKMULT 300 /* multiplier for all of a kind */ X#define P_STRAIGHT 1500 /* points for straight */ X#define P_ASMSTR 750 /* points for assembled straight */ X#define P_4OKMULT 200 /* multiplier for three of a kind */ X#define P_SMSTR 400 /* points for a small straight */ X#define P_3OKMULT 100 /* multiplier for three of a kind */ X#define P_ACE 100 /* points for single ace */ X#define P_FIVE 50 /* points for single five */ X#define P_JOKER 0 /* value of single Jokers */ X#define P_JOKERMULT 30 /* <n>o'kind multiplier for Jokers */ X X/* X** The following defines are just symbolic values for numbers. X*/ X#define BADFACE 0 /* impossible die face */ X#define ACE 1 /* an ACE is a one, a scoring die */ X#define DEUCE 2 /* an DEUCE is a two, the most worthless die */ X#define THREE 3 /* how many in a Three_of_a_kind or the face name */ X#define FIVE 5 /* FIVE is five, a scoring die */ X#define JOKER 9 /* an imphysical die face and scoring die */ X#define MESGLEN 128 /* length of message buffer */ X#define NAMELEN 64 /* player name buffer length */ X#define IDLEN 64 /* player identity buffer length */ X#define DISPLEN 18 /* field width in client name display */ X#define COMP 0 /* computer starts as player zero */ X#define PLAYERS 10 /* max players (client score window limits) */ X#define MINPLR 4 /* min players at game begining */ X#define MINCOMP 2 /* min computers at game beginning */ X#define WRITETIMO 20 /* timeout on socket writes */ X#define READTIMO 60 /* timeout on socket reads */ X#define MAXTIMO 3 /* too many timeouts -- goodbye! */ X X/* X** The ANCIENT value is used to prune old records from the history. X** The two credit values give additional grace to players as a multiplier X** of the number of games played. X*/ X#define ANCIENT ((long)(nhist + 1)) /* depends on number of players */ X#define ANALCREDIT 0 /* games played credit in histanal */ X#define WRITECREDIT 5 /* games played credit in histwrite */ X X/* X** To mark asynchronous requests, we prepend each with ASYNCMARK. X** It should not be a character that would normally be typed. X*/ X#define ASYNCMARK '\1' /* control-A */ X X/* X** Message numbers. Defined as enum so that we can keep them X** sequential without much trouble. This allows the dispatching X** function in the client to be faster, since we can avoid doing X** a linear search of the action table by using a function array. XXXX We assume that enums are ints for use in sprintf() calls. X*/ X#define M_BASE 100 /* lowest message number */ Xtypedef enum { X M_NOOP = M_BASE, /* no operation (usually heartbeat) */ X M_INFO, /* informational or status messages */ X M_HELP, /* help messages */ X M_DICE, /* complete dice status */ X M_PARM, /* game parameters */ X M_PLAY, /* play-by-play on other players */ X M_HELO, /* hello message */ X M_DOWN, /* shutdown message */ X M_RQID, /* id request */ X M_WORP, /* watch or play? */ X M_SORP, /* wait (spider) or play? */ X M_ACTV, /* you are an active player */ X M_AUTO, /* you are on autopilot */ X M_WAIT, /* you are waiting to be added */ X M_VOYR, /* you are now a voyeur */ X M_SPDR, /* you are now a spider */ X M_TURN, /* Player %d, ... up with %d points. */ X M_NWIN, /* game over, no winner */ X M_OVER, /* Player %d has won the game! */ X M_RANK, /* player rank at end of game */ X M_CPLR, /* clear all players */ X M_UARE, /* you are player %d */ X M_PNUM, /* player %d %s */ X M_FARE, /* farewell %d %s */ X M_NOBS, /* %d observer[s] */ X M_MSCO, /* You now have %d points. */ X M_OSCO, /* Player %d now has %d points. */ X M_ANOG, /* play another game? */ X M_RFST, /* Ready to roll? */ X M_KEEP, /* %d points: */ X M_ARGE, /* argument error */ X M_BADM /* bad message */ X} m_num; X#define M_LAST (int)M_BADM /* highest message number */ X X/* X** Definitions for status queries. For now, only one query X** type, and only two status responses are supported. X*/ X#define STATLEN 512 /* max length of status response */ X#define Q_ROSTER '\1' /* query: current player roster */ X#define S_IDLE '\1' /* status: idle */ X#define S_ROSTER '\2' /* status: current player roster */ X#define S_UNRECOG '\177' /* status: unrecognized query */ X X/* X** Some stuff for converting numbers to names. Probably should be elsewhere. X*/ Xextern char *numnames[][2]; X#define NUMBER(n) (numnames[n][0]) X#ifdef lint X#define FACE(show,ndice) (numnames[show][ndice]) /* fake to shut up lint */ X#else lint X#define FACE(show,ndice) (numnames[show][(ndice)!=1]) X#endif lint X X/* X** boolean: remind me never to do this again X*/ Xtypedef enum { False, True } boolean; X X/* X** diestat: the four states a die can be in X*/ Xtypedef enum { Free, Held, Rolled, Taken } diestat; X X/* X** combination: names for all scoring combinations X*/ Xtypedef enum { X Previous = -1, Nothing, Joker, Five, Ace, Three_of_a_kind, X Small_straight, Four_of_a_kind, Asm_straight, Straight, All_of_a_kind X} combination; X X/* X** Currently, defining DESC does nothing useful. X*/ X/*#define DESC 1 /* scoring description (future use) */ X X#ifdef DESC X/* X** scoredesc: complete description of a scoring combination X*/ Xtypedef struct { X combination sc_comb; /* the type of combination */ X short sc_num; /* how many of this combination */ X short sc_face; /* face value for N_of_a_kind */ X} scoredesc; X#endif DESC X X/* X** diceset: structure for tracking status of all dice X*/ Xtypedef struct { X int d_face[NDICE]; /* number showing on each die */ X diestat d_stat[NDICE]; /* status of each die */ X combination d_comb[NDICE]; /* die's scoring combination */ X#ifdef DESC X scoredesc d_desc[NDICE]; /* list of combinations scored */ X#endif DESC X combination d_best; /* best combination scored */ X boolean d_again; /* true if rolling again */ X int d_rolling; /* number of dice rolling */ X int d_pts_roll; /* points due to last roll */ X int d_pts_dice; /* points by this set of NDICE */ X int d_pts_turn; /* points accumulated this turn */ X int d_pts_max; /* max points showing this turn */ X char d_mesg[MESGLEN]; /* status message */ X} diceset; X X/* X** winpref: player game type preference X*/ Xtypedef enum { X Nopref, /* don't care */ X Standard, /* game to WINSCORE */ X Blitz, /* game to BLITZSCORE */ X Fickle, /* for computer use */ X Fstand, /* Standard or quit */ X Fblitz, /* Blitz or quit */ X} winpref; X X/* X** blitzmode: when the server will play Blitz games X*/ Xtypedef enum { X Noblitz, /* never to be played */ X Onrequest, /* only when requested */ X Workhours, /* default during working hours */ X Enforced, /* enforced during working hours */ X} blitzmode; X X/* X** cstat: player/connection status X*/ Xtypedef enum { X Inactive, /* no player */ X Watching, /* human voyeur */ X Waiting, /* human waiting to get in */ X Spider, /* human waiting for another human */ X Active, /* active human player */ X Computer, /* active computer player */ X} cstat; X X/* X** strategy: description of a computer player strategy X*/ Xtypedef struct { X int (*s_func)(); /* strategy function */ X char *s_name; /* name of strategy */ X} strategy; X X/* X** temper: description of a computer player temperament X*/ Xtypedef struct { X boolean (*t_func)(); /* temperament function */ X char *t_name; /* name of temperament */ X} temper; X X/* X** computer: complete description of a computer player X*/ Xtypedef struct { X char *c_name; /* computer player name */ X strategy *c_strategy; /* pointer into strategy table */ X temper *c_temper; /* pointer into temperament table */ X winpref c_pref; /* gametype preference */ X} computer; X X/* X** player: player/connection status X*/ Xtypedef struct { X cstat p_stat; /* connection status */ X int p_fd; /* communications socket */ X int p_timeouts; /* number of timeouts */ X int p_score; /* player score */ X int p_squander; /* points rolled away */ X int p_mood; /* computer mood value */ X winpref p_pref; /* winscore preference */ X boolean p_onboard; /* True if player on board */ X computer *p_computer; /* pointer into computer table */ X char p_name[NAMELEN]; /* player name */ X char p_id[IDLEN]; /* "unique" player id */ X} player; X X/* X** Computer moods have no meaning other than that defined X** by each temperament that uses the p_mood value. X*/ X#define NOMOOD 0 /* no mood selected */ X#define MAXMOOD 5 /* moods 1 through MAXMOOD */ X X/* X** graphtype: type of graphics the terminal supports X*/ Xtypedef enum { X Nographics, Digital, Zenith, X} graphtype; X X/* X** history: player scoring history X*/ X#define H_MVWINMULT 10000L /* to avoid floating point stuff */ Xtypedef struct { X long h_points; /* lifetime total number of points */ X long h_avgturn; /* lifetime average points per turn */ X long h_wins; /* lifetime number of games won */ X long h_games; /* lifetime number of games played */ X long h_mvpoints; /* moving sum of game points */ X long h_mvavgturn; /* moving sum of avg points per turn */ X long h_mvwins; /* mov sum of games won times H_MVWINMULT */ X long h_mvgames; /* games used to calculate h_mv values */ X long h_lastgame; /* last game played in */ X long h_weight; /* weighted value of record */ X long h_rank; /* ranking based on weight */ X computer *h_computer; /* pointer into computer table */ X char h_id[IDLEN]; /* "unique" player id */ X} history; X X/* X** ptstype: history points type X*/ Xtypedef enum { Lifetime, Recent, Combined } ptstype; X X/* X** risk: rolling risks/expectations X*/ Xtypedef struct { X double r_p_any; /* probability of scoring anything (assumes mix) */ X double r_p_all; /* probability of scoring all (assumes mix) */ X double r_p_aok; /* prob. of completing All_of_a_kind in non-scoring */ X int r_e_mix; /* <rolled> with a mix of held dice */ X int r_e_aces; /* <rolled> with held dice all aces (no 3o'kind) */ X int r_e_fives; /* <rolled> with held dice all fives (no 3o'kind) */ X int r_e_jokers; /* <rolled> with held dice all jokers (no 3o'kind) */ X} risk; X X/* X** enterlate: what to do about a game in progress or about waiting X*/ Xtypedef enum { X Ask, Watch, Play, Wait X} enterlate; X X/* X** Definitions for convenient use of select(). X*/ X#ifndef FD_ZERO X/* XXXX: This system is missing the FD_ macros for select, so it's XXXX: probably a 4.2BSDish system. That means that the fd_set XXXX: type is probably just a single int, so just fake it here. X*/ X#define FD_ZERO(p) ((p)->fds_bits[0] = 0) X#define FD_SET(n,p) ((p)->fds_bits[0] |= 1L << (n)) X#define FD_ISSET(n,p) (((p)->fds_bits[0] & (1L << (n))) != 0) X#endif FD_ZERO X#define NOSEL ((fd_set *)0) X#define HANG ((struct timeval *)0) END_OF_FILE if test 12208 -ne `wc -c <'cubes.h'`; then echo shar: \"'cubes.h'\" unpacked with wrong size! fi # end of 'cubes.h' fi if test -f 'cubeserver.6' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'cubeserver.6'\" else echo shar: Extracting \"'cubeserver.6'\" \(5480 characters\) sed "s/^X//" >'cubeserver.6' <<'END_OF_FILE' X.TH CUBESERVER 6 "cubes 5.1" GMP "UNIX Gaming Manual" X.SH NAME Xcubeserver \- cubes dice game service X.\" X.\" sccsid: @(#)cubeserver.6 5.1 (G.M. Paris) 89/01/22 X.\" X.\" X.\" X.\" cubes 5.1 Copyright 1988 Gregory M. Paris X.\" Permission granted to redistribute on a no charge basis. X.\" All other rights are reserved. X.\" X.\" X.SH SYNOPSIS X.B cubeserver X[ X.B \-j X] [ X.BR \-b { nrwe } X] X.SH OVERVIEW XThe X.I cubeserver Xis the program that provides the X.IR cubes Xgame service. XThis manual page is intended for games administrators. XPotential X.I cubes Xplayers should see the manual pages for X.IR cubes , X.IR cuberank , Xand X.IR cubestat Xto find out how to play the game. X.SH "FILE MODES AND OWNERSHIPS" XThe X.I cubeserver Xis meant to be run setuid to an unprivileged daemon account, often X.IR gdaemon . XThe files used by the X.I cubeserver Xare assumed to exist, have the same ownership as the executable, Xand have permissions mode of 644, 640, or 600. XThe Makefile supplied with the X.I cubes Xdistribution should create all needed files with appropriate Xownership and permissions. X.SH "UNIX DOMAIN CUBES SERVICE" XThe X.I cubeserver Xcan be configured to provide X.I cubes Xservice in the X.B UNIX Xdomain. XThis service can be provided in addition to, Xor as an alternative to the X.B INET Xdomain service (described below). XAt least one of the services must be provided, Xor the server will not run. X.PP XThe X.B UNIX Xdomain service allows connections from clients only on the local system, Xand could possibly be more efficient than the X.B INET Xservice. XTo configure the server to provide service in this domain, Xit must be compiled with the X.B \-DUNIXSOCK=pathname Xoption, where X.B pathname Xis the name of the rendezvous socket. X(The client program also must be compiled with this option.) X.SH "INET DOMAIN CUBES SERVICE" XThe X.I cubeserver Xcan be configured to provide X.I cubes Xservice in the X.B INET Xdomain, Xallowing the server to be accessed from remote systems. XTo provide this networked service, Xthe server must be compiled with the X.B \-DINETSOCK Xoption and the X.I cubes Xservice must be made a ``well known'' service. X.PP XMaking the X.I cubes Xservice well known Xusually means adding an entry to the file /etc/services X(see X.IR services (5)). X(Note that the entry should be added to the services file on every Xsystem upon which the client program, X.IR cubes , Xis to be run, not just on the system on which the server is to be run.)\ XThe entry is for the TCP socket that the server uses to communicate Xwith its clients during game play. XThe port number chosen must be greater than 1024 Xso that the server can run as an unprivileged user. XAlthough not officially registered in any way, Xthe following entry is suggested. X.PP X.DT X.nf X.ft B X cube 3840/tcp cubes X.fi X.ft P X.SH "CUBES STATUS SERVICE" XIf another well known service is defined, namely the X.I cubestat Xservice, the server will listen on an X.B INET Xdomain UDP socket for status requests generated by the X.I cubestat Xprogram. XSince the TCP and UDP port number spaces are separate, Xit is reasonable to use the same port number for both sockets. X(Remember, the port number chosen must be greater than 1024 Xso that the server can run as an unprivileged user.)\ XAgain, though not officially registered in any way, Xthe following entry is suggested. X.PP X.DT X.nf X.ft B X cubestat 3840/udp cubestatus X.fi X.ft P X.PP XThe current version of the server does not provide status service in the X.B UNIX Xdomain, regardless of compile time options. X.SH "STARTING THE SERVER" XNormally, the X.I cubeserver Xwill be started automatically on system boot Xby placing the appropriate line in the file /etc/rc.local, Xor possibly in another file where similar daemons are started. XAlternatively, it is possible to start the server via a program like X.IR cron . XFor this purpose, Xwhen the server is started Xit prints its process id on the standard output. XThis pid could be saved in a file and be used to turn the daemon Xoff at a later time, Xagain using X.IR cron . XTo kill the server immediately, Xsend it a SIGTERM. XMore politely, killing the server with SIGHUP Xcauses it to exit when any game in progress finishes. X.PP XThere are two command line options for X.IR cubeserver . X.PP XThe X.B \-j Xoption allows the server to occasionally play the game of X.I cubes Xwith dice that have jokers on them. XWithout this option, Xthe game is always played with normal six-sided dice. X.PP XThe X.BR \-b < when > Xoption allows specifying when the server will play the game of X.I cubes Xin Blitz mode (games end at 7500 rather than 10000 points). XThe values of X.RB ` n ', X.RB ` r ', X.RB ` w ', Xand X.RB ` e ' Xtell the server to play in Blitz mode Xnever, on request, default during working hours, Xand enforced during working hours respectively. XThe default is X.RB ` e '. X.SH FILES X.ta 3.2i X.nf X/usr/games/lib/cubeserver the cubeserver executable X/usr/games/lib/cubes.hist the cubes score file X/usr/games/lib/cubes.monikers names for the chamelion X.fi X.PP XThe cubes.monikers file is a record of names selected by Xhuman players for use by the chamelion player. XThis file will grow without bound, Xso it might be a good idea to check it on occasion. XA good idea anyway, since X.I cubeserver Xdoes not judge the acceptability of names before using them. XThe program has a short list of names compiled in, Xso you can avoid problems with this file by linking it to /dev/null. X.DT X.SH "SEE ALSO" Xcubes(6), cuberank(6), cubestat(6), services(5), rc(8), cron(8) X.SH AUTHOR XGreg Paris <gmp@rayssd.ray.com> END_OF_FILE if test 5480 -ne `wc -c <'cubeserver.6'`; then echo shar: \"'cubeserver.6'\" unpacked with wrong size! fi # end of 'cubeserver.6' fi if test -f 'histconv.sh' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'histconv.sh'\" else echo shar: Extracting \"'histconv.sh'\" \(774 characters\) sed "s/^X//" >'histconv.sh' <<'END_OF_FILE' X#! /bin/sh X# X# This script is for converting cubes4.1 style history file to cubes5.1 style. X# You must use this script if you were running cubes4.1 and wish to keep X# the players' records intact. X# Xawk ' XBEGIN { X MVGAMES = 25; X} X{ X split($1, x, ";"); games=x[1]; lastgame=x[2]; X if(games == 0) next; X if(games < MVGAMES) mvgames = games; X else mvgames = MVGAMES; X X wins=$2; points=$3; avgturn=$4; X X name=$5; X for(n = 6;n <= NF;++n) X name = name " " $n; X X mvwins = (10000 * wins * mvgames) / games; X mvpoints = (points * mvgames) / games; X mvavgturn = (avgturn * mvgames) / games; X X printf("L %5d %5d %10d %10d %6d %s\n", games, wins, points, avgturn, lastgame, name); X printf("M %5d %5d %10d %10d %6d %s\n", mvgames, mvwins, mvpoints, mvavgturn, lastgame, name); X} X' $1 END_OF_FILE if test 774 -ne `wc -c <'histconv.sh'`; then echo shar: \"'histconv.sh'\" unpacked with wrong size! fi chmod +x 'histconv.sh' # end of 'histconv.sh' fi if test -f 'random.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'random.c'\" else echo shar: Extracting \"'random.c'\" \(3095 characters\) sed "s/^X//" >'random.c' <<'END_OF_FILE' X/* vi:set sw=4 ts=4: */ X#ifndef lint Xstatic char sccsid[] = "@(#)random.c 5.1 (G.M. Paris) 89/01/22"; X#endif lint X X/* X** X** cubes 5.1 Copyright 1989 Gregory M. Paris X** Permission granted to redistribute on a no charge basis. X** All other rights are reserved. X** X*/ X X#include <sys/types.h> X#include <sys/time.h> X#include "cubes.h" X Xextern boolean jokermode; Xextern char *initstate(); Xextern long random(); Xextern time_t time(); X Xstatic long diestate[3][256 / sizeof(long)]; /* for die rolls */ Xstatic long numstate[256 / sizeof(long)]; /* for random numbers */ X X#define RANDOM() (int)((unsigned)random() >> 1) /* XXX: ensure non-neg? */ X X/* X** irandom: initialize random number generators X*/ Xirandom() X{ X struct timeval tv; X struct timezone tz; X register unsigned n; X int nstate = 0; X X /* X ** Initialize first die rolling state. X */ X (void) gettimeofday(&tv, &tz); X n = (tv.tv_sec << 8) + ((unsigned)tv.tv_usec >> 8); X (void) initstate(n, diestate[nstate++], sizeof diestate[0]); X for(n %= 49;n != 0;--n) X (void) random(); X X /* X ** Initialize random number state and second die rolling state. X */ X (void) gettimeofday(&tv, &tz); X n = ((tv.tv_sec << 16) | ((unsigned)tv.tv_usec >> 16)) + getpid(); X (void) initstate(n, numstate, sizeof numstate); X for(n %= 17;n != 0;--n) X (void) random(); X n = (unsigned)(random() + 1); /* using numstate */ X (void) initstate(n, diestate[nstate++], sizeof diestate[0]); X for(n %= 13;n != 0;--n) X (void) random(); X X /* X ** Initialize third die rolling state. X */ X (void) gettimeofday(&tv, &tz); X n = (tv.tv_sec << 4) ^ ((unsigned)tv.tv_usec >> 4); X (void) initstate(n, diestate[nstate++], sizeof diestate[0]); X for(n %= 27;n != 0;--n) X (void) random(); X} X X/* X** dieroll: X** if jokermode is true X** roll a trick six-sided die which may show a JOKER on X** any face every once in thirteen rolls X** else X** roll a regular six-sided die X*/ Xdieroll() X{ X static which = 0; X X#define THIRTEEN (2 * SIDES + 1) X X /* X ** We use three random number states for the dice because it turns out X ** that the RNG is not good for producing random *strings* of numbers. X ** This method does seem to increase randomness for the combinations X ** involving three to five dice. Maybe we should use NDICE states, X ** but how do we ensure that our seeds are different enough? X */ X (void) setstate(diestate[which++ % 3]); X X if(jokermode == True) { X int s; X X if((s = RANDOM() % THIRTEEN) == THIRTEEN - 1) X return JOKER; X return s % SIDES + 1; X } X X return RANDOM() % SIDES + 1; X X#undef THIRTEEN X} X X/* X** randint: return a random integer from 1 to n X*/ Xrandint(n) X{ X if(n <= 1) X return 1; X (void) setstate(numstate); X return RANDOM() % n + 1; X} X X/* X** hesitate: random hesitation in the range minv to maxv milliseconds XXXX No checking of arguments is done. X*/ Xhesitate(minv, maxv) Xlong minv, maxv; X{ X long diff, t; X struct timeval tv; X X if((diff = maxv - minv) <= 1) X t = minv; X else { X (void) setstate(numstate); X t = random() % diff + minv; X } X X tv.tv_sec = t / 1000; X tv.tv_usec = (t % 1000) * 1000; X (void) select(32, NOSEL, NOSEL, NOSEL, &tv); X} END_OF_FILE if test 3095 -ne `wc -c <'random.c'`; then echo shar: \"'random.c'\" unpacked with wrong size! fi # end of 'random.c' fi echo shar: End of archive 8 \(of 8\). cp /dev/null ark8isdone MISSING="" for I in 1 2 3 4 5 6 7 8 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 8 archives. rm -f ark[1-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0