|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T s
Length: 14014 (0x36be)
Types: TextFile
Names: »strategies.c«
└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987
└─⟦this⟧ »EUUGD18/General/Cubes/strategies.c«
/* vi:set sw=4 ts=4: */
#ifndef lint
static char sccsid[] = "@(#)strategies.c 5.1 (G.M. Paris) 89/01/22";
#endif lint
/*
**
** cubes 5.1 Copyright 1989 Gregory M. Paris
** Permission granted to redistribute on a no charge basis.
** All other rights are reserved.
**
*/
#include <stdio.h>
#include <syslog.h>
#include "cubes.h"
extern boolean jokermode;
extern boolean sameface();
extern char *malloc();
#define P_HAND (NDICE * P_ACE) /* a threshold */
/*
** basic: (formerly) the most basic strategy
*/
static
basic(pd, need)
diceset *pd;
int need;
{
/*
** The basic strategy doesn't use need.
*/
#ifdef lint
need = need;
#endif lint
/*
** Respect a complete dice set.
*/
if(pd->d_rolling == 0)
return;
/*
** If we're one away from All_of_a_kind, we're done.
*/
if(pd->d_rolling == 1) {
if(sameface(pd, Ace, True) == True)
return;
if(sameface(pd, Five, True) == True)
return;
if(jokermode == True && sameface(pd, Joker, True) == True)
return;
}
/*
** Discard Jokers and Fives.
*/
if(jokermode == True)
nojokers(pd);
nofives(pd);
}
/*
** merrier: the more dice to throw, the merrier
*/
static
merrier(pd, need)
diceset *pd;
int need;
{
diceset temp;
/*
** The merrier strategy doesn't use need.
*/
#ifdef lint
need = need;
#endif lint
/*
** Respect a complete dice set.
*/
if(pd->d_rolling == 0)
return;
/*
** Discard Jokers, Fives, and Aces if the result is three or more dice.
*/
temp = *pd;
if(jokermode == True)
nojokers(&temp);
nofives(&temp);
noaces(&temp);
if(temp.d_rolling >= THREE)
*pd = temp;
}
/*
** respect: Respect the power of the Ace.
*/
static
respect(pd, need)
diceset *pd;
int need;
{
diceset temp;
/*
** We've completed all dice. Try discarding Jokers and Fives.
** If the result is one die to roll and all Aces showing,
** then do it -- going for All_of_a_kind in Aces.
*/
if(pd->d_rolling == 0) {
if(need > 0 && need < P_ACEMULT * P_AOKMULT)
return;
if(pd->d_pts_turn >= P_HAND)
return;
temp = *pd;
if(jokermode == True)
nojokers(&temp);
nofives(&temp);
if(temp.d_rolling == 1 && sameface(&temp, Ace, True) == True)
*pd = temp;
return;
}
/*
** Don't discard Aces if we're one away from All_of_a_kind.
*/
if(pd->d_rolling == 1)
if(sameface(pd, Ace, True) == True)
return;
/*
** If we've got some points accumulated, we must be a bit desperate
** to want to roll again. Improve our chances of getting something
** by scrapping junky Small_straights, freeing an Ace.
*/
if(pd->d_best == Small_straight)
if(need > P_SMSTR || (need == 0 && pd->d_pts_turn > P_SMSTR))
noacesmall(pd);
/*
** Get rid of 3o'kind in deuces. Scrap Jokers and Fives.
*/
if(pd->d_best == Three_of_a_kind)
no3deuce(pd);
if(jokermode == True)
nojokers(pd);
nofives(pd);
/*
** Discard Aces if we end up with three or more dice.
*/
temp = *pd;
noaces(&temp);
if(temp.d_rolling >= THREE)
*pd = temp;
}
/*
** twohater: doesn't like 3o'kind in twos
*/
static
twohater(pd, need)
diceset *pd;
int need;
{
/*
** The twohater strategy doesn't use need.
*/
#ifdef lint
need = need;
#endif lint
/*
** Respect completed dice set.
*/
if(pd->d_rolling == 0)
return;
/*
** Hates Jokers even more than 3o'kind in twos.
*/
if(jokermode == True)
nojokers(pd);
/*
** Prefers Fives and Aces over 3o'kind in twos.
*/
if(pd->d_best == Three_of_a_kind)
no3deuce(pd);
/*
** Discard Fives, but only discard Aces if
** we're already rolling more than one die.
*/
nofives(pd);
if(pd->d_rolling > 1)
noaces(pd);
}
/*
** greedy: Tries for All_of_a_kind in Aces, Fives, and Jokers.
*/
static
greedy(pd, need)
diceset *pd;
int need;
{
diceset temp;
int d, held, jokers;
/*
** We've completed all dice. If a single discard can get us
** closer to All_of_a_kind in Aces, Fives or Jokers, do it.
*/
if(pd->d_rolling == 0) {
if(pd->d_pts_turn >= P_HAND)
return;
/*
** Discard Fives and Aces. Check for all Jokers.
*/
if(jokermode == True) {
if(need > 0 && need < P_JOKERMULT * P_AOKMULT)
return;
temp = *pd;
nofives(&temp);
noaces(&temp);
if(temp.d_rolling == 1 && sameface(&temp, Joker, True) == True) {
*pd = temp;
return;
}
}
/*
** Discard Jokers and Fives. Check for all Aces.
*/
if(need > 0 && need < P_ACEMULT * P_AOKMULT)
return;
temp = *pd;
if(jokermode == True)
nojokers(&temp);
nofives(&temp);
if(temp.d_rolling == 1 && sameface(&temp, Ace, True) == True) {
*pd = temp;
return;
}
/*
** Discard Jokers and Aces. Check for all Fives.
*/
if(need > 0 && need < FIVE * P_AOKMULT)
return;
temp = *pd;
if(jokermode == True)
nojokers(&temp);
noaces(&temp);
if(temp.d_rolling == 1 && sameface(&temp, Five, True) == True) {
*pd = temp;
return;
}
return;
}
/*
** On the first roll, if we have the choice between holding Jokers
** and Fives, choose the Jokers -- going for AOK in Jokers.
*/
if(jokermode == True) {
if(need == 0 || need >= P_JOKERMULT * P_AOKMULT) {
if(pd->d_pts_turn == 0 && pd->d_best == Five) {
held = jokers = 0;
for(d = 0;d < NDICE;++d) {
switch(pd->d_comb[d]) {
case Previous: ++held; break;
case Joker: ++jokers; break;
}
}
if(held == 0 && jokers > 0)
nofives(pd);
return;
}
}
}
/*
** Small_straights make getting 5o'kind difficult, but if
** ASMSTR is defined, they can be converted to Straights,
** giving us another chance with all dice. The Small_straight
** containing an Ace is the most difficult to convert.
** If no ASMSTR, discard all Small_straights, otherwise
** discard only the tough kind.
*/
if(pd->d_best == Small_straight) {
#ifdef ASMSTR
noacesmall(pd); /* this kind too hard to convert */
#else ASMSTR
nosmall(pd); /* don't like any Small_straights */
#endif ASMSTR
return;
}
/*
** Try to get all Aces showing. If we can, we're done.
*/
temp = *pd;
if(temp.d_best == Three_of_a_kind) {
no3three(&temp);
if(temp.d_best == Three_of_a_kind)
no3deuce(&temp);
}
nofives(&temp);
if(jokermode == True)
nojokers(&temp);
if(sameface(&temp, Ace, True) == True) {
*pd = temp;
return;
}
/*
** Try to get all Fives showing. If we can, we're done.
*/
if(need == 0 || need >= FIVE * P_AOKMULT) {
temp = *pd;
if(temp.d_best == Three_of_a_kind) {
no3three(&temp);
if(temp.d_best == Three_of_a_kind)
no3deuce(&temp);
}
noaces(&temp);
if(jokermode == True)
nojokers(&temp);
if(sameface(&temp, Five, True) == True) {
*pd = temp;
return;
}
}
/*
** Try to get all Jokers showing. If we can, we're done.
*/
if(jokermode == True) {
if(need == 0 || need >= P_JOKERMULT * P_AOKMULT) {
temp = *pd;
if(temp.d_best == Three_of_a_kind) {
no3three(&temp);
if(temp.d_best == Three_of_a_kind)
no3deuce(&temp);
}
noaces(&temp);
nofives(&temp);
if(sameface(&temp, Joker, True) == True) {
*pd = temp;
return;
}
}
}
/*
** Discard Jokers and Fives.
** Discard Aces if the result is three or more dice.
*/
if(jokermode == True)
nojokers(pd);
nofives(pd);
temp = *pd;
noaces(&temp);
if(temp.d_rolling >= THREE)
*pd = temp;
}
/*
** picky: be picky about what we'll keep
*/
static
picky(pd, need)
diceset *pd;
int need;
{
diceset temp;
/*
** Respect a completed dice set.
*/
if(pd->d_rolling == 0)
return;
/*
** Don't like 3o'kind in twos or threes.
*/
if(pd->d_best == Three_of_a_kind) {
if(need == 0 || need > THREE * P_3OKMULT) {
no3three(pd);
if(pd->d_best == Three_of_a_kind)
if(need == 0 || need > DEUCE * P_3OKMULT)
no3deuce(pd);
}
}
/*
** We've got held Aces, discard Jokers and Fives.
** If not all Aces showing, discard Aces too.
*/
if(need == 0 || need >= P_ACEMULT * P_AOKMULT) {
if(sameface(pd, Ace, False) == True) {
if(jokermode == True)
nojokers(pd);
nofives(pd);
if(sameface(pd, Ace, True) == False)
noaces(pd);
return;
}
}
/*
** We've got held Fives, discard Jokers and Aces.
** If not all Fives showing, discard Fives too.
*/
if(need == 0 || need >= FIVE * P_AOKMULT) {
if(sameface(pd, Five, False) == True) {
if(jokermode == True)
nojokers(pd);
noaces(pd);
if(sameface(pd, Five, True) == False)
nofives(pd);
return;
}
}
/*
** We've got held Jokers, discard Fives and Aces.
** If not all Jokers showing, discard Jokers too.
*/
if(jokermode == True) {
if(need == 0 || need >= P_JOKERMULT * P_AOKMULT) {
if(sameface(pd, Joker, False) == True) {
nofives(pd);
noaces(pd);
if(sameface(pd, Joker, True) == False)
nojokers(pd);
return;
}
}
}
/*
** We're holding a mix or nothing. Discard Jokers.
** Discard Fives and Aces if the result is three or more dice.
*/
if(jokermode == True)
nojokers(pd);
temp = *pd;
nofives(&temp);
noaces(&temp);
if(temp.d_rolling >= THREE)
*pd = temp;
}
/*
** finicky: a pickier picky
*/
static
finicky(pd, need)
diceset *pd;
int need;
{
diceset temp;
/*
** Respect a completed set of dice.
*/
if(pd->d_rolling == 0)
return;
/*
** Discard three twos and Small_straights containing an Ace.
*/
if(pd->d_best == Three_of_a_kind)
if(need == 0 || need > DEUCE * P_3OKMULT)
no3deuce(pd);
if(pd->d_best == Small_straight)
if(need == 0 || need > P_SMSTR)
noacesmall(pd);
/*
** We've held all Aces. Discard Jokers and Fives.
** If rolling more than one die, discard Aces too.
*/
if(sameface(pd, Ace, False) == True) {
if(jokermode == True)
nojokers(pd);
nofives(pd);
if(pd->d_rolling > 1)
noaces(pd);
return;
}
/*
** We've held all Fives. Discard Jokers and Aces.
** If rolling more than one die, discard Fives too.
*/
if(need == 0 || need >= FIVE * P_AOKMULT) {
if(sameface(pd, Five, False) == True) {
if(jokermode == True)
nojokers(pd);
noaces(pd);
if(pd->d_rolling > 1)
nofives(pd);
return;
}
}
/*
** We've held all Jokers. Discard Fives and Aces.
** If we're rolling more than one die, discard Jokers too.
** Else, if it will give us three dice, discard Jokers.
*/
if(jokermode == True) {
if(need == 0 || need >= P_JOKERMULT * P_AOKMULT) {
if(sameface(pd, Joker, False) == True) {
nofives(pd);
noaces(pd);
if(pd->d_rolling > 1)
nojokers(pd);
else {
temp = *pd;
nojokers(&temp);
if(temp.d_rolling >= THREE)
*pd = temp;
}
return;
}
}
}
/*
** Holding a mix or nothing. Discard Jokers and Fives.
** If we're rolling more than one, discard Aces too.
** Else, if we can get three dice, discard Aces.
** Else, discard 3o'kind in threes.
*/
if(jokermode == True)
nojokers(pd);
nofives(pd);
if(pd->d_rolling > 1)
noaces(pd);
else {
temp = *pd;
noaces(&temp);
if(temp.d_rolling >= THREE)
*pd = temp;
else if(pd->d_best == Three_of_a_kind)
no3three(pd);
}
}
/*
** holdall: hold all scoring dice
XXX: Intended for choosy selection only -- not a valid strategy.
*/
static
holdall(pd, need)
diceset *pd;
int need;
{
#ifdef lint
pd = pd;
need = need;
#endif lint
}
/*
** tossall: always throw maximum number of dice
XXX: Intended for choosy selection only -- not a valid strategy.
*/
static
tossall(pd, need)
diceset *pd;
int need;
{
#ifdef lint
need = need;
#endif lint
/*
** Discard Small_straights, all Three_of_a_kinds, Jokers, Fives, and Aces.
** We never honor a complete dice set!
*/
if(pd->d_best == Small_straight)
nosmall(pd);
if(pd->d_best == Three_of_a_kind)
no3any(pd);
if(jokermode == True)
nojokers(pd);
nofives(pd);
noaces(pd);
}
/*
** choosy: try all known strategies then pick the one
** with the best expectation for this diceset
*/
static
choosy(pd, need)
diceset *pd;
int need;
{
register int n, best, maxx;
diceset temp;
static int *xtbl = 0;
extern int strategies;
extern strategy *strattbl[];
if(xtbl == 0) {
xtbl = (int *)malloc((unsigned)(strategies * sizeof *xtbl));
if(xtbl == 0) {
syslog(LOG_WARNING, "choosy: no memory for xtbl");
fickle(pd, need); /* emergency backup! */
return;
}
}
for(n = 0;n < strategies - 1;++n) { /* fickle is last */
if(strattbl[n]->s_func == choosy) {
*(xtbl+n) = -WINSCORE;
continue;
}
temp = *pd;
(*strattbl[n]->s_func)(&temp, need);
*(xtbl+n) = expect(&temp);
}
maxx = *(xtbl+(best=0));
for(n = 1;n < strategies - 1;++n) /* fickle is last */
if(*(xtbl+n) > maxx)
maxx = *(xtbl+(best=n));
(*strattbl[best]->s_func)(pd, need);
}
/*
** kamelion: should never be called
*/
static
kamelion(pd, need)
diceset *pd;
int need;
{
syslog(LOG_WARNING, "kamelion strategy called!");
choosy(pd, need);
}
/*
** fickle: pick another strategy randomly!
** intended for proxy players only
*/
static
fickle(pd, need)
diceset *pd;
int need;
{
int n;
extern int strategies;
extern strategy *strattbl[];
hesitate(100L, 1000L);
n = randint(strategies - 1) - 1; /* this one is last -- don't pick it */
(*strattbl[n]->s_func)(pd, need);
}
/*
** strattbl: table listing available strategies
*/
strategy st_basic = { basic, "basic" };
strategy st_merrier = { merrier, "merrier" };
strategy st_respect = { respect, "respect" };
strategy st_twohater = { twohater, "twohater" };
strategy st_greedy = { greedy, "greedy" };
strategy st_picky = { picky, "picky" };
strategy st_finicky = { finicky, "finicky" };
static strategy st_holdall = { holdall, "holdall" }; /* table only */
static strategy st_tossall = { tossall, "tossall" }; /* table only */
strategy st_choosy = { choosy, "choosy" };
strategy st_fickle = { fickle, "fickle" };
strategy st_kamelion = { kamelion, "kamelion" }; /* semi-dummy */
strategy *strattbl[] = {
&st_basic, &st_merrier, &st_respect, &st_twohater,
&st_greedy, &st_picky, &st_finicky,
&st_holdall, &st_tossall, &st_choosy,
&st_fickle /* st_fickle must be last */
};
int strategies = sizeof strattbl / sizeof strattbl[0];