pkg://yahtzee-1.0-188.src.rpm:41462/colour-yahtzee.tar.gz
info downloads
colour-yahtzee/ 40755 0 0 0 6045011535 12011 5 ustar root root colour-yahtzee/Makefile 100644 0 0 340 6044605115 13525 0 ustar root root CFLAGS =
OBJ = computer.o main.o
LIBS = -lncurses -ltermcap
BIN = yahtzee
CFLAGS = -O2 -I/usr/include/ncurses
$(BIN): $(OBJ)
cc -o $@ $(OBJ) -lncurses -ltermcap
clean:
rm -f $(OBJ) $(BIN)
$(OBJ): yahtzee.h config.h
colour-yahtzee/README 100644 0 0 1161 6045011535 12765 0 ustar root root
Y A H T Z E E
This is Zorst's old Yahtzee game for Unix after a facelift and a few
fixes. It started when I noticed that there is a small security hole
in the standard Linux version (because it predates a working rename())
it uses system() to run mv. Thus if setuid games it can be used to get
access as games.
I fixed this by putting the rename back. The old one blew up with ^Z so
I switched to ncurses. Finally since it was ncurses I added colour to
the entire game.
The gameplay/logic hasn't changed a line - proof that its the game play
that counts not the flash graphics.
Alan
Zorst's readme is in README.old
colour-yahtzee/computer.c 100644 0 0 27634 6044605116 14147 0 ustar root root #include <stdio.h>
#include <string.h>
#include "yahtzee.h"
/*
* (c)1992 by orest zborowski
*/
/*
** if defined, DEBUG will cause the computer to print out a bunch of
** information as its trying to decide what to do with its rolls
#define DEBUG
*/
extern int num_players;
extern Player players[];
extern int dice_values[];
#ifdef DEBUG
static char *upper_headers[NUM_UPPER] =
{
"(a) 1",
"(b) 2",
"(c) 3",
"(d) 4",
"(e) 5",
"(f) 6"
};
static char *lower_headers[NUM_LOWER] =
{
"(g) 3 of a Kind",
"(h) 4 of a Kind",
"(i) Full House",
"(j) Small Straight",
"(k) Large Straight",
"(l) Yahtzee",
"(m) Chance",
};
#endif
static int numrolls = 0;
/*
** questions are:
** 0: none
** 1: "what dice to roll again?"
** 2: "where do you want to put that?"
*/
static struct
{
int value;
char rerolls[20];
} bc_table[NUM_FIELDS];
/*
** depending on the dice rolls, we fill in the choice table. if
** for a particular choice the rolls are good, we put an appropriate
** value in the table. we also give which die need to be rerolled.
**
** basically, the value system is based off the highest score possible
** rolling the dice - all 6 (6 x 5 = 30). so the best any of the upper
** ranks can get is 30.
*/
static int throwaway[NUM_FIELDS] =
{
4, /* 1 */
3, /* 2 */
2, /* 3 */
2, /* 4 */
1, /* 5 */
1, /* 6 */
3, /* 3 of a kind */
5, /* 4 of a kind */
4, /* Full House */
3, /* Small straight */
5, /* Large straight */
4, /* Yahtzee */
0, /* Chance */
};
void
build_table(int player)
{
int i;
int j;
int k;
int d;
int d2;
int overflow;
char foo[10];
#ifdef DEBUG
char fred[1024];
#endif
++numrolls;
for (i = 0; i < NUM_FIELDS; ++i)
{
if (players[player].used[i])
bc_table[i].value = -99;
else
bc_table[i].value = throwaway[i];
strcpy(bc_table[i].rerolls, "1 2 3 4 5");
}
/*
** HANDLING UPPER SLOTS
*/
/*
** first, we calculate the overflow of the upper ranks. that is, we
** count all the points we have left over from our 3-of-all rule
** if we get 3 of all in the upper ranks, we get a bonus, so if
** we get 4 of something, that means a lower roll may be acceptable,
** as long as we remain in the running for a bonus. overflow can
** be negative as well, in which case throwaway rolls are not
** encouraged, and a high roll will get a nice boost
*/
overflow = 0;
for (i = 0; i < NUM_UPPER; ++i)
{
if (players[player].used[i])
continue;
overflow += (count(i+1) - 3) * (i+1);
}
for (i = 0; i < NUM_UPPER; ++i)
{
if (players[player].used[i])
continue;
bc_table[i].rerolls[0] = '\0';
for (d = 0; d < 5; ++d)
{
if (dice_values[d] != i + 1)
{
sprintf(foo, "%d ", d + 1);
strcat(bc_table[i].rerolls, foo);
}
}
/*
** ok. now we set a base value on the roll based on its count and
** how much it is worth to us.
*/
bc_table[i].value = count(i+1) * 8;
/*
** we have to play games with the bonus.
** if we already have a bonus, then all free slots are candidates for
** throwing away - we only do this when there are no more rolls
** if this would get us a bonus, we make it very attractive
**
** if we get 3 of everything on the top, we get a bonus. so...
** if we have more than 3, we make the choice more attractive.
** if less than 3, we make it less attractive.
** if our overflow (any that are more than 3, summed up) covers up
** our lack (if we only have 2, and there were 4 6's), we
** dont penalize ourselves as much (since we're still in the
** running for a bonus)
*/
if (upper_total(player) >= 63)
{
if (numrolls > 2)
bc_table[i].value += 10;
}
else if (upper_total(player) + count(i+1) * (i+1) >= 63)
{
bc_table[i].value += 35;
}
if (count(i+1) < 3)
{
if (overflow < (3 - count(i+1)) * (i+1))
bc_table[i].value -= (3 - count(i+1)) * 2;
}
else if (count(i+1) > 3)
{
bc_table[i].value += (count(i+1) - 3) * 2;
}
}
/*
** HANDLING LOWER SLOTS
*/
/*
** first, we look for potential. these values will be larger than the
** single rolls but less than the made rolls (or those with higher value)
**
** we also do such thinking only if we're not supposed to be looking just
** for the best combinations...
*/
if (numrolls < 3)
{
/*
** searching for large straight... here we chicken out and only look at
** runs which might have possibilities
*/
if (!players[player].used[H_LS])
{
for (i = 4; i > 0; --i)
{
d2 = find_straight(i, 0);
if (d2 == 0)
continue;
bc_table[H_LS].value = (40 * i) / 5;
bc_table[H_LS].rerolls[0] = '\0';
for (d = 1; d < 7; ++d)
{
if (count(d) > 0)
{
if (d < d2 || d >= d2 + i)
k = count(d);
else
k = count(d) - 1;
if (k < 1)
continue;
for (j = 0; j < 5; ++j)
{
if (dice_values[j]!=d)
continue;
sprintf(foo, "%d ",
j + 1);
strcat(
bc_table[H_LS].rerolls,
foo);
if (!--k)
break;
}
}
}
break;
}
}
/*
** searching for small straight... here we chicken out and only look at
** runs which might have possibilities
*/
if (!players[player].used[H_SS])
{
for (i = 3; i > 0; --i)
{
d2 = find_straight(i, 0);
if (d2 == 0)
continue;
bc_table[H_SS].value = (30 * i) / 4;
bc_table[H_SS].rerolls[0] = '\0';
for (d = 1; d < 7; ++d)
{
if (count(d) > 0)
{
if (d < d2 || d >= d2 + i)
k = count(d);
else
k = count(d) - 1;
if (k < 1)
continue;
for (j = 0; j < 5; ++j)
{
if (dice_values[j]!=d)
continue;
sprintf(foo, "%d ",
j + 1);
strcat(
bc_table[H_SS].rerolls,
foo);
if (!--k)
break;
}
}
}
break;
}
}
/*
** searching for 3 of a kind
*/
if (!players[player].used[H_3])
{
for (i = 2; i > 0; --i)
{
for (d = 6; d > 0; --d)
{
if (count(d) >= i)
break;
}
if (d == 0)
continue;
bc_table[H_3].rerolls[0] = '\0';
bc_table[H_3].value = (d * i);
for (j = 0; j < 5; ++j)
if (dice_values[j] != d)
{
sprintf(foo, "%d ", j + 1);
strcat(bc_table[H_3].rerolls,
foo);
}
break;
}
}
/*
** searching for 4 of a kind
*/
if (!players[player].used[H_4])
{
for (i = 3; i > 0; --i)
{
for (d = 6; d > 0; --d)
{
if (count(d) >= i)
break;
}
if (d == 0)
continue;
bc_table[H_4].value = (d * i);
bc_table[H_4].rerolls[0] = '\0';
for (j = 0; j < 5; ++j)
if (dice_values[j] != d)
{
sprintf(foo, "%d ", j + 1);
strcat(bc_table[H_4].rerolls,
foo);
}
break;
}
}
/*
** searching for yahtzee... we can't set the potential value too high
** because if we fail, the value will be no better than 4 of a kind (or so)
** so, we make scoring the same as for 3-4 of a kind (this is 5 of a kind!)
*/
if (!players[player].used[H_YA])
{
for (i = 4; i > 0; --i)
{
for (d = 6; d > 0; --d)
{
if (count(d) >= i)
break;
}
if (d == 0)
continue;
bc_table[H_YA].value = (d * i);
bc_table[H_YA].rerolls[0] = '\0';
for (j = 0; j < 5; ++j)
if (dice_values[j] != d)
{
sprintf(foo, "%d ", j + 1);
strcat(bc_table[H_YA].rerolls,
foo);
}
break;
}
}
/*
** searching for full house
*/
if (!players[player].used[H_FH])
{
for (i = 4; i > 0; --i)
{
d = find_n_of_a_kind(i, 0);
if (d == 0)
continue;
for (j = i; j > 0; --j)
{
d2 = find_n_of_a_kind(j, d);
if (d2 > 0)
break;
}
if (j == 0)
continue;
bc_table[H_FH].rerolls[0] = '\0';
bc_table[H_FH].value = (i * 24 + j * 36) / 6;
for (i = 0; i < 5; ++i)
{
if (dice_values[i] != d &&
dice_values[i] != d2)
{
sprintf(foo, "%d ", i + 1);
strcat(bc_table[H_FH].rerolls,
foo);
}
}
break;
}
}
}
/*
** now we look hard at what we got
*/
if (!players[player].used[H_SS] && find_straight(4, 0, 0))
{
d = find_straight(4, 0, 0);
for (i = 0; i < 5; ++i)
if (count(dice_values[i]) > 1 ||
dice_values[i] < d || dice_values[i] > d + 3)
{
sprintf(bc_table[H_SS].rerolls, "%d", i + 1);
break;
}
bc_table[H_SS].value = 30;
}
if (!players[player].used[H_LS] && find_straight(5, 0, 0))
{
bc_table[H_LS].value = 40;
bc_table[H_LS].rerolls[0] = '\0';
}
if (!players[player].used[H_CH] && numrolls > 2)
{
bc_table[H_CH].value = add_dice();
if (bc_table[H_CH].value < 20)
bc_table[H_CH].value /= 2;
bc_table[H_CH].rerolls[0] = '\0';
for (i = 0; i < 5; ++i)
if (dice_values[i] < 4)
{
sprintf(foo, "%d ", i + 1);
strcat(bc_table[H_CH].rerolls, foo);
}
}
if (!players[player].used[H_FH])
{
d = find_n_of_a_kind(3, 0);
if (d != 0)
{
if (find_n_of_a_kind(2, d))
{
bc_table[H_FH].value = 25;
bc_table[H_FH].rerolls[0] = '\0';
}
}
}
if (!players[player].used[H_3])
{
d = find_n_of_a_kind(3, 0);
if (d != 0)
{
bc_table[H_3].value = add_dice();
bc_table[H_3].rerolls[0] = '\0';
for (i = 0; i < 5; ++i)
if (d != dice_values[i])
{
sprintf(foo, "%d ", i + 1);
strcat(bc_table[H_3].rerolls, foo);
}
}
}
if (!players[player].used[H_4])
{
d = find_n_of_a_kind(4, 0);
if (d != 0)
{
/*
** there will be a tie between 3 of a kind and 4 of a kind. we add 1
** to break the tie in favor of 4 of a kind
*/
bc_table[H_4].value = add_dice() + 1;
bc_table[H_4].rerolls[0] = '\0';
for (i = 0; i < 5; ++i)
if (d != dice_values[i])
{
sprintf(foo, "%d ", i + 1);
strcat(bc_table[H_4].rerolls, foo);
}
}
}
if (find_n_of_a_kind(5, 0))
{
if (players[player].used[H_YA] &&
players[player].score[H_YA] == 0)
bc_table[H_YA].value = -99; /* scratch */
else
bc_table[H_YA].value = 150; /* so he will use it! */
}
#ifdef DEBUG
for (i = 0; i < NUM_FIELDS; ++i)
{
sprintf(fred, "%s : VALUE = %d REROLLS='%s'",
(i < NUM_UPPER) ? upper_headers[i] : lower_headers[i - NUM_UPPER],
bc_table[i].value, bc_table[i].rerolls);
query(-1, 0, fred, foo, sizeof(foo));
}
#endif
}
void
bc_1(int player, char *buf, int bufsiz)
{
int i;
int best;
int bestv;
#ifdef DEBUG
char fred[1024];
#endif
build_table(player);
best = 0;
bestv = -99;
for (i = NUM_FIELDS-1; i >= 0; --i)
if (bc_table[i].value >= bestv)
{
best = i;
bestv = bc_table[i].value;
}
#ifdef DEBUG
sprintf(fred, "<<BEST>> %s : VALUE = %d REROLLS='%s'",
(best < NUM_UPPER) ? upper_headers[best] : lower_headers[best - NUM_UPPER],
bc_table[best].value, bc_table[best].rerolls);
query(-1, 0, fred, fred, sizeof(fred));
#endif
strcpy(buf, bc_table[best].rerolls);
}
/*
** what we do here is generate a table of all the choices then choose
** the highest value one. in case of a tie, we go for the lower choice
** cause higher choices tend to be easier to better
*/
void
bc_2(int player, char *buf, int bufsiz)
{
int i;
int best;
int bestv;
#ifdef DEBUG
char fred[1024];
#endif
numrolls = 2; /* in case skipped middle */
build_table(player);
numrolls = 0; /* for next time */
best = 0;
bestv = -99;
for (i = NUM_FIELDS-1; i >= 0; --i)
if (player % 2)
{
if (bc_table[i].value > bestv)
{
best = i;
bestv = bc_table[i].value;
}
}
else
{
if (bc_table[i].value >= bestv)
{
best = i;
bestv = bc_table[i].value;
}
}
#ifdef DEBUG
sprintf(fred, "<<BEST>> %s : VALUE = %d REROLLS='%s'",
(best < NUM_UPPER) ? upper_headers[best] : lower_headers[best - NUM_UPPER],
bc_table[best].value, bc_table[best].rerolls);
query(-1, 0, fred, fred, sizeof(fred));
#endif
sprintf(buf, "%c", best + 'a');
}
void
be_computer(int player, int question, char *buf, int bufsiz)
{
*buf = '\0';
switch(question)
{
case 1:
bc_1(player, buf, bufsiz);
break;
case 2:
bc_2(player, buf, bufsiz);
break;
default:
strcpy(buf, "Huh?");
break;
}
}
colour-yahtzee/config.h 100644 0 0 606 6044605116 13511 0 ustar root root #ifndef _config_H_
#define _config_H_
#define SCOREDIR "/usr/games"
#define SCOREFNAME "yahtzee.sco" /* must allow .L extension */
#define NUM_TOP_PLAYERS 10
#define COMPUTER_DELAY 4 /* sec */
#if A
/*
your linux either:
a) has no rename, or
b) can't rename regular files if newname exists
*/
#define HAS_RENAME /* comment out if you don't */
#endif
#endif /* _config_H_ */
colour-yahtzee/README.old 100644 0 0 756 6044605115 13535 0 ustar root root the game of yahtzee for linux (and other) flavors of un*x.
the file config.h contains some parameters you may wish to change.
use "yahtzee -h" to see the options available.
it is very simple as it was written a long time ago, but it is still
enjoyable.
it requires the curses library (with my patch for the missing function)
it could use the new rename system call, but it has a bug in that it
doesn't allow the rename of an old file to a new file where the new file
already exists.
zorst
colour-yahtzee/main.c 100644 0 0 53011 6044605116 13221 0 ustar root root #include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <signal.h>
#include <ncurses/ncurses.h>
#include <stdarg.h>
#include "yahtzee.h"
/*
* (c)1992 by orest zborowski
*/
static char *header = "Yahtzee Version 1.00 (c)1992 by zorst";
extern errno;
#define NUM_ROLLS 3
static char *upper_headers[NUM_UPPER] =
{
"(a) 1 [total of 1s]",
"(b) 2 [total of 2s]",
"(c) 3 [total of 3s]",
"(d) 4 [total of 4s]",
"(e) 5 [total of 5s]",
"(f) 6 [total of 6s]"
};
static char *lower_headers[NUM_LOWER] =
{
"(g) 3 of a Knd [total]",
"(h) 4 of a Knd [total]",
"(i) Full House [25]",
"(j) Sm Straight [30]",
"(k) Lg Straight [40]",
"(l) Yahtzee [50]",
"(m) Chance [total]",
};
int dice_values[5];
static char *dice[6][4] =
{
"",
" ",
" o ",
" ",
"",
"o ",
" ",
" o",
"",
"o ",
" o ",
" o",
"",
"o o",
" ",
"o o",
"",
"o o",
" o ",
"o o",
"",
"o o",
"o o",
"o o",
};
Player players[MAX_NUMBER_OF_PLAYERS];
int num_players;
static int longest_header;
int dodelay = 0;
int numlines;
init(void)
{
int i;
int j;
num_players = 0;
srand(getpid());
for (i = 0; i < MAX_NUMBER_OF_PLAYERS; ++i)
{
players[i].name[0] = '\0';
players[i].finished = 0;
players[i].comp = 0;
for (j = 0; j < NUM_FIELDS; ++j)
{
players[i].score[j] = 0;
players[i].used[j] = 0;
}
}
for (i = 0; i < NUM_UPPER; ++i)
if (strlen(upper_headers[i]) > longest_header)
longest_header = strlen(upper_headers[i]);
for (i = 0; i < NUM_LOWER; ++i)
if (strlen(lower_headers[i]) > longest_header)
longest_header = strlen(lower_headers[i]);
srand(getpid());
}
static void fill_box(int x,int y, int h, int w)
{
int dx,dy;
for(dy=y; dy<y+h; dy++)
{
for(dx=x;dx<x+w;dx++)
{
mvaddch(dx,dy,' ');
}
}
}
/*
** SCREEN ORGANIZATION:
** line 0: version header
** line 1: -----------
** line 2: edit window
** line 3: -----------
** line 4: player names
** line 5-10 upper bank
** line 11: upper total
** line 12: Bonus
** line 13-19: lower bank
** line 20: lower total
** line 21: total
*/
setup_screen(void)
{
int i;
initscr();
if (LINES < 23)
abort("Not enough lines on the terminal");
numlines = LINES;
if(has_colors())
{
start_color();
init_pair(COLOR_WHITE, COLOR_BLACK, COLOR_WHITE);
init_pair(COLOR_GREEN, COLOR_BLACK, COLOR_GREEN);
init_pair(COLOR_YELLOW, COLOR_WHITE, COLOR_GREEN);
init_pair(COLOR_RED, COLOR_WHITE, COLOR_RED);
}
clear();
wattron(stdscr, COLOR_PAIR(COLOR_GREEN));
fill_box(0,0,COLS,LINES);
mvaddstr(0, 9, header);
move(1, 9);
for (i = 9; i < COLS; ++i)
addch(ACS_HLINE);
refresh();
}
yend(void)
{
attron(0);
move(0, 0);
clear();
refresh();
endwin();
}
abort(char *msg)
{
yend();
putchar('\n');
printf(msg);
putchar('\n');
exit(1);
}
say(char *fmt, ...)
{
va_list ap;
char buf[200];
va_start(ap, fmt);
vsprintf(buf, fmt, ap);
va_end(ap);
fill_box(2,10,COLS-10,1);
mvaddstr(2, 10, buf);
refresh();
}
/*
** we have a trick in here - we will accept a '?' as the first character of
** a human answer. in that case, we ask the computer for the die to roll
** or the place to put it. then the human can decide what to do.
*/
void
query(int player, int question, char *prompt, char *ans, int len)
{
int i;
char c;
int xpos;
char foo[2];
xpos = 10 + strlen(prompt);
if (player >= 0 && players[player].comp) /* for the computer */
{
fill_box(2,10,COLS-10,1);
mvaddstr(2, 10, prompt);
be_computer(player, question, ans, len);
mvaddstr(2, xpos, ans);
refresh();
if (dodelay)
sleep(COMPUTER_DELAY); /* let person read it */
return;
}
for (;;)
{
cbreak();
noecho();
fill_box(2,10,COLS-10,1);
mvaddstr(2, 10, prompt);
refresh();
i = 0;
for (;;)
{
c = getch();
if (c == '\b' || c == 0x7f)
{
if (i == 0)
continue;
--i;
--xpos;
mvaddch(2, xpos, ' ');
move(2, xpos);
}
else if (c == 10 || c == 13)
break;
else
{
if (i == len)
write(1, "\007", 1);
else
{
addch(c);
ans[i] = c;
++xpos;
++i;
}
}
refresh();
}
ans[i] = '\0';
echo();
nocbreak();
if (ans[0] != '?')
break;
/*
** let the computer decide and then we can put that up for the human to
** read
*/
be_computer(player, question, ans, len);
query(-1, 0, ans, foo, sizeof(foo));
}
}
int
raw_roll_dice(void)
{
return((rand() % 6) + 1);
}
int
roll_dice(int num)
{
int val;
int i;
int j;
if (num < 1 || num > 5)
abort("Bad dice loc passed");
attron(COLOR_PAIR(COLOR_GREEN));
for (j = 0; j < 1; ++j)
{
/*
val = (random() % 6) + 1;
*/
val = raw_roll_dice();
for (i = 0; i < 4; ++i)
{
move(((num - 1) * 4) + i, 0);
if (i == 2)
printw("%d", num);
else
addch(' ');
attroff(COLOR_PAIR(COLOR_GREEN));
attron(COLOR_PAIR(COLOR_WHITE));
if(i==0)
{
if(num==1)
addch(ACS_ULCORNER);
else
addch(ACS_LTEE);
addch(ACS_HLINE);
addch(ACS_HLINE);
addch(ACS_HLINE);
addch(ACS_HLINE);
addch(ACS_HLINE);
if(num==1)
addch(ACS_URCORNER);
else
addch(ACS_RTEE);
}
else
{
addch(ACS_VLINE);
addstr(dice[val - 1][i]);
addch(ACS_VLINE);
}
attroff(COLOR_PAIR(COLOR_WHITE));
attron(COLOR_PAIR(COLOR_GREEN));
}
if (num == 5) /* put the last +---+ tail */
{
mvaddch(20, 0, ' ');
attroff(COLOR_PAIR(COLOR_GREEN));
attron(COLOR_PAIR(COLOR_WHITE));
addch(ACS_LLCORNER);
addch(ACS_HLINE);
addch(ACS_HLINE);
addch(ACS_HLINE);
addch(ACS_HLINE);
addch(ACS_HLINE);
addch(ACS_LRCORNER);
attroff(COLOR_PAIR(COLOR_WHITE));
attron(COLOR_PAIR(COLOR_GREEN));
}
}
refresh();
return (val);
}
int
upper_total(int num)
{
int val;
int i;
val = 0;
for (i = 0; i < NUM_UPPER; ++i)
val += players[num].score[i];
return (val);
}
int
lower_total(int num)
{
int val;
int i;
val = 0;
for (i = 0; i < NUM_LOWER; ++i)
val += players[num].score[i + NUM_UPPER];
return (val);
}
int
total_score(int num)
{
int upper_tot;
int lower_tot;
int i;
upper_tot = 0;
lower_tot = 0;
lower_tot = lower_total(num);
upper_tot = upper_total(num);
if (upper_tot >= 63)
upper_tot += 35;
return (upper_tot + lower_tot);
}
void
show_player(int num, int field)
{
int i;
int line;
int upper_tot;
int lower_tot;
int xpos;
xpos = 10 + longest_header + (num * MAX_NAME_LENGTH);
for (i = 0; i < NUM_FIELDS; ++i)
{
if (i == field || field == -1)
{
line = 5 + i;
if (i >= NUM_UPPER)
line += 2;
move(line, xpos);
if (players[num].used[i])
printw(" %4d", players[num].score[i]);
else
addstr(" ");
}
}
upper_tot = upper_total(num);
lower_tot = lower_total(num);
move(12, xpos);
if (upper_tot >= 63)
{
printw("+%4d", 35);
upper_tot += 35;
}
else
addstr(" ");
mvprintw(11, xpos, "(%4d)", upper_tot);
mvprintw(20, xpos, "(%4d)", lower_tot);
mvprintw(21, xpos, "[%4d]", upper_tot + lower_tot);
refresh();
}
void
setup_board(void)
{
int i;
int j;
move(3, 9);
for (i = 9; i < COLS; ++i)
addch(ACS_HLINE);
for (i = 0; i < NUM_UPPER; ++i)
mvaddstr(i+5, 9, upper_headers[i]);
move(11, 9);
attron(A_UNDERLINE|COLOR_PAIR(COLOR_YELLOW));
addstr(" Upper Total");
move(12, 9);
addstr(" Bonus");
attroff(A_UNDERLINE|COLOR_PAIR(COLOR_YELLOW));
attron(COLOR_PAIR(COLOR_GREEN));
for (i = 0; i < NUM_LOWER; ++i)
mvaddstr(i+13, 9, lower_headers[i]);
move(20, 9);
attron(A_UNDERLINE|COLOR_PAIR(COLOR_YELLOW));
addstr(" Lower Total");
move(21, 9);
addstr(" Grand Total");
attroff(A_UNDERLINE|COLOR_PAIR(COLOR_YELLOW));
attron(COLOR_PAIR(COLOR_GREEN));
for (j = 0; j < num_players; ++j)
{
for (i = 4; i < 22; ++i)
mvaddch(i, 9 + longest_header + (j * MAX_NAME_LENGTH),
ACS_VLINE);
}
for (i = 0; i < num_players; ++i)
{
mvaddstr(4, 10 + longest_header + (i * MAX_NAME_LENGTH),
players[i].name);
show_player(i, -1);
}
refresh();
}
int
count(int val)
{
int i;
int num;
num = 0;
for (i = 0; i < 5; ++i)
if (dice_values[i] == val)
++num;
return (num);
}
int
find_n_of_a_kind(int n, int but_not)
{
int val;
int i;
int j;
for (i = 0; i < 5; ++i)
{
if (dice_values[i] == but_not)
continue;
if (count(dice_values[i]) >= n)
return (dice_values[i]);
}
return (0);
}
int
find_straight(int run, int notstart, int notrun)
{
int i;
int j;
for (i = 1; i < 7; ++i)
{
if (i >= notstart && i < notstart + notrun)
continue;
for (j = 0; j < run; ++j)
if (!count(i + j))
break;
if (j == run)
return (i);
}
return (0);
}
int
find_yahtzee(void)
{
int i;
for (i = 1; i < 7; ++i)
if (count(i) == 5)
return (i);
return (0);
}
int
add_dice(void)
{
int i;
int val;
val = 0;
for (i = 0; i < 5; ++i)
val += dice_values[i];
return (val);
}
int
showoff(int p, short so)
{
move(4, 10 + longest_header + (p * MAX_NAME_LENGTH));
if (so)
{
attroff(COLOR_PAIR(COLOR_GREEN));
attron(A_STANDOUT);
}
else
attron(COLOR_PAIR(COLOR_GREEN));
addstr(players[p].name);
if (so)
{
attroff(A_STANDOUT);
attron(COLOR_PAIR(COLOR_GREEN));
}
refresh();
}
void
handle_play(int player)
{
int i;
char buf[50];
char *cp;
char *num;
int done;
int field;
int dummy;
int numroll;
if (players[player].finished) /* all finished */
return;
showoff(player, 1);
say("Rolling for %s", players[player].name);
for (i = 1; i < 6; ++i)
dice_values[i - 1] = roll_dice(i);
for (numroll = 1; numroll < NUM_ROLLS; ++numroll)
{
query(player, 1, "What dice to roll again (<RETURN> for none)? ",
buf, sizeof(buf));
cp = buf;
if (*cp == '\0')
break;
done = 0;
for (;;)
{
num = cp;
while (*cp != '\0' && *cp != ',' && *cp != '\t' && *cp != ' ')
++cp;
if (*cp == '\0')
done = 1;
*cp++ = '\0';
i = atoi(num);
if (i >= 1 && i <= 5)
dice_values[i - 1] = roll_dice(i);
if (done)
break;
}
}
query(player, 2, "Where do you want to put that? ", buf, sizeof(buf));
done = 0;
for (;;)
{
if (buf[0] < 'a' || buf[0] > 'm')
{
query(player, 2, "No good! Where do you want to put that? ",
buf, sizeof(buf));
continue;
}
field = buf[0] - 'a';
switch(field)
{
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
if (players[player].used[field])
{
query(player, 2, "Already used! Where do you want to put that? ",
buf, sizeof(buf));
break;
}
players[player].used[field] = 1;
players[player].score[field] =
count(field + 1) * (field + 1);
done = 1;
show_player(player, field);
break;
case 6:
if (players[player].used[field])
{
query(player, 2, "Already used! Where do you want to put that? ",
buf, sizeof(buf));
break;
}
players[player].used[field] = 1;
if (find_n_of_a_kind(3, 0))
players[player].score[field] =
add_dice();
show_player(player, field);
done = 1;
break;
case 7:
if (players[player].used[field])
{
query(player, 2, "Already used! Where do you want to put that? ",
buf, sizeof(buf));
break;
}
players[player].used[field] = 1;
if (find_n_of_a_kind(4, 0))
players[player].score[field] =
add_dice();
show_player(player, field);
done = 1;
break;
case 8:
if (players[player].used[field])
{
query(player, 2, "Already used! Where do you want to put that? ",
buf, sizeof(buf));
break;
}
players[player].used[field] = 1;
dummy = find_n_of_a_kind(3, 0);
if (dummy != 0)
{
if (find_n_of_a_kind(2, dummy))
players[player].score[field] =
25;
}
show_player(player, field);
done = 1;
break;
case 9:
if (players[player].used[field])
{
query(player, 2, "Already used! Where do you want to put that? ",
buf, sizeof(buf));
break;
}
players[player].used[field] = 1;
if (find_straight(4, 0, 0))
players[player].score[field] = 30;
show_player(player, field);
done = 1;
break;
case 10:
if (players[player].used[field])
{
query(player, 2, "Already used! Where do you want to put that? ",
buf, sizeof(buf));
break;
}
players[player].used[field] = 1;
if (find_straight(5, 0, 0))
players[player].score[field] = 40;
show_player(player, field);
done = 1;
break;
case 11:
/*
** if the player scratched, the score for that field will be 0.
** in that case, we don't allow it to be used any more.
*/
if ((players[player].score[field] == 0 ||
!find_yahtzee()) &&
players[player].used[field] == 1)
{
query(player, 2, "Already used! (he he) Where do you want to put that? ",
buf, sizeof(buf));
break;
}
if (find_yahtzee())
players[player].score[field] += 50;
players[player].used[field] = 1;
show_player(player, field);
done = 1;
break;
case 12:
if (players[player].used[field])
{
query(player, 2, "Already used! Where do you want to put that? ",
buf, sizeof(buf));
break;
}
players[player].used[field] = 1;
players[player].score[field] = add_dice();
show_player(player, field);
done = 1;
break;
}
if (done)
break;
}
showoff(player, 0);
for (i = 0; i < NUM_FIELDS; ++i)
if (!players[player].used[i])
return;
players[player].finished = 1;
}
void
play(void)
{
int i;
int topscore;
int winner;
for (;;)
{
for (i = 0; i < num_players; ++i)
handle_play(i);
for (i = 0; i < num_players; ++i)
if (!players[i].finished)
break;
if (i == num_players)
break;
}
topscore = -1;
for (i = 0; i < num_players; ++i)
if (total_score(i) > topscore)
{
topscore = total_score(i);
winner = i;
}
say("The winner is %s", players[winner].name);
}
#define L_LOCK 0
#define L_UNLOCK 1
void
lock(char *fname, int type)
{
char lockfile[200];
struct stat statbuf;
int i;
FILE *fp;
strcpy(lockfile, fname);
strcat(lockfile, ".L");
if (type == L_LOCK)
{
for (i = 1; ;++i)
{
stat(lockfile, &statbuf);
if (errno == ENOENT)
break;
say("Waiting for lock... (%d)", i);
sleep(1);
}
fp = fopen(lockfile, "w");
fclose(fp);
}
else
{
unlink(lockfile);
}
}
static int
write_score(FILE *fp, char *name, char *date, int score)
{
return fprintf(fp, "%s\001%s\001%d\n", name, date, score);
}
static int
read_score(FILE *fp, char *name, char *date, int *score)
{
char buf[200];
char *sb, *se;
if (!fgets(buf, sizeof(buf), fp))
return -1;
if (!(se = strchr(buf, '\001')))
return -1;
*se++ = '\0';
strcpy(name, buf);
if ((sb = se) > buf + sizeof(buf))
return -1;
if (!(se = strchr(sb, '\001')))
return -1;
*se++ = '\0';
strcpy(date, sb);
if ((sb = se) > buf + sizeof(buf))
return -1;
if (!(se = strchr(sb, '\n')))
return -1;
*se = '\0';
*score = atoi(sb);
return 0;
}
/*
** we keep track of the top nnn persons.
*/
void
update_scorefile(void)
{
FILE *fp;
FILE *tp;
char scorefile[200];
char tmpfile[100];
int numtop;
int nump;
int j;
char name[20];
char date[30];
char *curdate;
int score;
int topscore;
int tmptop;
long clock;
char scall[100];
sprintf(tmpfile, "%s/y.%x", SCOREDIR, getpid());
sprintf(scorefile, "%s/%s", SCOREDIR, SCOREFNAME);
clock = time(0);
curdate = (char *) ctime(&clock);
if (strchr(curdate, '\n'))
*strchr(curdate, '\n') = '\0';
if ((tp = fopen(tmpfile, "w")) == NULL)
{
say("Can't update score file.");
return;
}
lock(scorefile, L_LOCK);
fp = fopen(scorefile, "r");
for (j = 0; j < num_players; ++j)
players[j].finished = -1;
numtop = 0;
nump = 0;
topscore = 99999;
for (;;)
{
/*
** get the next entry from the score file. if there isn't any, then
** we set the score to beat to -99 (everyone playing can beat it)
*/
if (fp == NULL || read_score(fp, name, date, &score))
score = -99;
/*
** now, we search through all players to find out which ones have scores
** higher than the one read (but less than topscore). these will get
** saved before the read entry does. now, we only do this if all players
** haven't been accounted for.
*/
for (; nump != num_players;)
{
tmptop = -99;
for (j = 0; j < num_players; ++j)
if (total_score(j) > tmptop &&
total_score(j) < topscore)
{
tmptop = total_score(j);
}
if (tmptop == -99) /* everybody better */
break;
if (tmptop > score)
{
topscore = tmptop;
for (j = 0; j < num_players; ++j)
if (total_score(j) == tmptop)
{
if (numtop >= NUM_TOP_PLAYERS)
break;
write_score(tp,
players[j].name, curdate,
tmptop);
players[j].finished = numtop;
++nump;
++numtop;
}
}
else
break;
}
if (score != -99 && numtop < NUM_TOP_PLAYERS)
{
write_score(tp, name, date, score);
++numtop;
}
/*
** if we processed all top slots or processed all players (and there
** was no score to beat), we stop.
*/
if (numtop == NUM_TOP_PLAYERS ||
(nump == num_players && score == -99))
break;
}
fclose(tp);
if (fp)
fclose(fp);
#ifdef HAS_RENAME
if (rename(tmpfile, scorefile))
{
say("rename failed!");
unlink(tmpfile);
}
#else
sprintf(scall, "mv %s %s", tmpfile, scorefile);
system(scall);
#endif
lock(scorefile, L_UNLOCK);
}
void
show_top_scores(void)
{
FILE *fp;
char scorefile[200];
int i, j, k, score;
char stuff[1024];
char name[32], date[32];
attron(COLOR_PAIR(COLOR_RED));
fill_box(0,0,COLS,LINES);
attroff(COLOR_PAIR(COLOR_RED));
attron(COLOR_PAIR(COLOR_WHITE));
fill_box(0,0,COLS,1);
move(0,(COLS-strlen("Yahtzee Top Scores"))/2);
addstr("Yahtzee Top Scores");
attroff(COLOR_PAIR(COLOR_WHITE));
sprintf(scorefile, "%s/%s", SCOREDIR, SCOREFNAME);
if ((fp = fopen(scorefile, "r")) == NULL)
{
yend();
printf("Can't get at score file.\n");
return;
}
j = 0;
attron(COLOR_PAIR(COLOR_RED));
for (i = 0; i < NUM_TOP_PLAYERS; ++i)
{
if (read_score(fp, name, date, &score))
break;
if (j >= numlines - 4)
{
move(23,(COLS-strlen("<Hit Return>"))/2);
addstr("<Hit Return>");
refresh();
getch();
j = 0;
}
for (k = 0; k < num_players; ++k)
if (players[k].finished == i)
break;
fill_box(j+3,4,COLS-4,1);
move(j+3,4);
sprintf(stuff,"%3d : %-10s %s %d", i + 1, name, date, score);
addstr(stuff);
++j;
}
fclose(fp);
move(23,(COLS-strlen("<Hit Return>"))/2);
addstr("<Hit Return>");
refresh();
getch();
yend();
}
void
calc_random(void)
{
char nrollstr[10];
int nroll;
int table[NUM_FIELDS];
int i;
int j;
printf ("How many times to you wish to roll? ");
gets(nrollstr);
nroll = atoi(nrollstr);
printf("Generating...\n");
for (i = 0; i < NUM_FIELDS; ++i)
table[i] = 0;
for (i = 0; i < nroll; ++i)
{
for (j = 0; j < 5; ++j)
dice_values[j] = raw_roll_dice();
for (j = 1; j <= 6; ++j)
if (count(j) > 0)
++table[j-1];
if (find_n_of_a_kind(3, 0))
++table[6];
if (find_n_of_a_kind(4, 0))
++table[7];
j = find_n_of_a_kind(3, 0);
if (j != 0 && find_n_of_a_kind(2, j))
++table[8];
if (find_straight(4, 0, 0))
++table[9];
if (find_straight(5, 0, 0))
++table[10];
if (find_yahtzee())
++table[11];
}
printf("%-35s %10s %20s\n", "Results:", "Num Rolls", "Total");
for (i = 0; i < NUM_FIELDS; ++i)
{
if (i < NUM_UPPER)
printf("%-35s", upper_headers[i]);
else
printf("%-35s", lower_headers[i-NUM_UPPER]);
printf(" %10d %20d\n", table[i],
(long) (table[i] * 100) / nroll);
}
}
void
signal_trap()
{
yend();
exit(0);
}
set_signal_traps()
{
signal(SIGHUP, signal_trap);
signal(SIGINT, signal_trap);
signal(SIGQUIT, signal_trap);
}
main(int argc, char **argv)
{
char num[10];
int i;
int num_computers;
short onlyshowscores = 0;
while (--argc > 0)
{
if ((*++argv)[0] == '-')
{
switch ((*argv)[1])
{
case 's':
onlyshowscores = 1;
break;
case 'n':
printf("obsolete function - delay turned off by default.\n");
break;
case 'd':
dodelay = 1;
break;
case 'r':
calc_random();
exit(0);
default:
printf("usage: yahtzee [-s] [-d] [-r]\n");
printf("\t-s\tonly show scores\n");
printf("\t-d\tcomputer move delay\n");
printf("\t-r\tcalculate random die throws (debug)\n");
exit(0);
}
}
}
if (!onlyshowscores)
{
printf("\n\nWelcome to the game of Yahtzee...\n\n");
init();
do
{
printf("How many wish to play (max of %d)? ",
MAX_NUMBER_OF_PLAYERS);
fflush(stdout);
fgets(num, 10, stdin);
if (strchr(num, '\n'))
*strchr(num, '\n') = '\0';
num_players = atoi(num);
if (num_players == 0)
break;
}
while (num_players < 1 || num_players > MAX_NUMBER_OF_PLAYERS);
for (i = 0; i < num_players; ++i)
{
printf("What is the name of player #%d ? ", i + 1);
fflush(stdout);
fgets(players[i].name, MAX_NAME_LENGTH, stdin);
if (strchr(players[i].name, '\n'))
*strchr(players[i].name, '\n') = '\0';
}
if (num_players == MAX_NUMBER_OF_PLAYERS)
{
printf("Boo hoo... I can't play...\n");
}
else
{
do
{
printf("How many computers to play (max of %d) ? ",
MAX_NUMBER_OF_PLAYERS - num_players);
fflush(stdout);
fgets(num, sizeof(num), stdin);
num_computers = atoi(num);
}
while (num_computers < 0 ||
num_players + num_computers > MAX_NUMBER_OF_PLAYERS);
for (i = 0; i < num_computers; ++i)
{
players[num_players].comp = 1;
sprintf(players[num_players].name, "Mr. %c",
i + 'A');
++num_players;
}
}
if (num_players == 0)
{
printf("Well, why did you run this anyways???\n\n");
exit(8);
}
}
setup_screen();
set_signal_traps();
if (!onlyshowscores)
{
setup_board();
play();
update_scorefile();
}
getch();
show_top_scores();
exit(0);
}
colour-yahtzee/yahtzee.h 100644 0 0 730 6044605116 13713 0 ustar root root #ifndef _yahtzee_H_
#define _yahtzee_H_
#include "config.h"
#define MAX_NUMBER_OF_PLAYERS 6
#define MAX_NAME_LENGTH 8
#define NUM_UPPER 6
#define NUM_LOWER 7
#define NUM_FIELDS (NUM_UPPER + NUM_LOWER)
#define H_3 6
#define H_4 7
#define H_FH 8
#define H_SS 9
#define H_LS 10
#define H_YA 11
#define H_CH 12
typedef struct
{
char name[MAX_NAME_LENGTH + 1];
short used[NUM_FIELDS];
int score[NUM_FIELDS];
int finished;
int comp;
} Player;
#endif /* _yahtzee_H_ */
colour-yahtzee/yahtzee 100755 0 0 216777 6044605121 13570 0 ustar root root d 臯 - ̀\ `D$4 ` P萰 Ȱ 5 P `[ ̀ 1 2 3 4 5 %d %d U(WVS E } E MˉЉB
f8 t"E 0 &E 0 M< <hT E 4 R `EUE E }lE MˉЉB
f8 t)E@Pz PE@UE띐E } E MˉЉB
f8 t E 0 D E }WEUB9 t;E@Ph^ EPP `EPE 4 R{ `E몐E@Pz UӉэ 0
}W >~K= ~7E 0 MΉˍ 0 <
<m}W; ËE@P UB>~7E 0 MΉˍ 0 <#<E@P E@Pn )E@9U}\E@PL UӉэ 0 ]]؋}؉ލ 0 )ljE؋}؉<3)lj<
nE@P ~VE@P UӉэ 0 ]]؋}؉ލ 0 E؋}؉<3lj<
E6= E f| r E } a j }W E} u3 E $ E } }W E9EEE9E},}W E!}W x}} tE }bE 9UtAE@Ph^ EP `EPh$ `M} uE룐EME f| E } n j }W E} u@ E)щȅ}= E } }W? E9EEE9E})}W E!}W x}} tE }bE 9UtAE@Ph^ EP9 `EPh x `M} uE룐E
ME f| E } E } ~1}W 9EMԐ} u
x }}= E }?E 9Ut'E@Ph^ EP `EPh H `E뿐M0E f| E } E } ~1}W 9EMԐ} u
x}}= E }?E 9Ut'E@Ph^ EP `EPh H `E뿐M0E f| E } E } ~1}W 9EMԐ} u
x}}=8 <