130198Sbostic /*
2*60812Sbostic * Copyright (c) 1982, 1993
3*60812Sbostic * The Regents of the University of California. All rights reserved.
433170Sbostic *
542578Sbostic * %sccs.include.redist.c%
630198Sbostic */
730198Sbostic
830198Sbostic #ifndef lint
9*60812Sbostic static char sccsid[] = "@(#)comp.c 8.1 (Berkeley) 05/31/93";
1033170Sbostic #endif /* not lint */
1130198Sbostic
1230198Sbostic # include "mille.h"
1330198Sbostic
1430198Sbostic /*
1530198Sbostic * @(#)comp.c 1.1 (Berkeley) 4/1/82
1630198Sbostic */
1730198Sbostic
1830198Sbostic # define V_VALUABLE 40
1930198Sbostic
calcmove()2030198Sbostic calcmove()
2130198Sbostic {
2230198Sbostic register CARD card;
2330198Sbostic register int *value;
2430198Sbostic register PLAY *pp, *op;
2530198Sbostic register bool foundend, cango, canstop, foundlow;
2630198Sbostic register unsgn int i, count200, badcount, nummin, nummax, diff;
2730198Sbostic register int curmin, curmax;
2830198Sbostic register CARD safe, oppos;
2930198Sbostic int valbuf[HAND_SZ], count[NUM_CARDS];
3030198Sbostic bool playit[HAND_SZ];
3130198Sbostic
3230198Sbostic wmove(Score, ERR_Y, ERR_X); /* get rid of error messages */
3330198Sbostic wclrtoeol(Score);
3430198Sbostic pp = &Player[COMP];
3530198Sbostic op = &Player[PLAYER];
3630198Sbostic safe = 0;
3730198Sbostic cango = 0;
3830198Sbostic canstop = FALSE;
3930198Sbostic foundend = FALSE;
4052876Storek
4152876Storek /* Try for a Coup Forre, and see what we have. */
4230198Sbostic for (i = 0; i < NUM_CARDS; i++)
4330198Sbostic count[i] = 0;
4430198Sbostic for (i = 0; i < HAND_SZ; i++) {
4530198Sbostic card = pp->hand[i];
4630198Sbostic switch (card) {
4730198Sbostic case C_STOP: case C_CRASH:
4830198Sbostic case C_FLAT: case C_EMPTY:
4930198Sbostic if (playit[i] = canplay(pp, op, card))
5030198Sbostic canstop = TRUE;
5130198Sbostic goto norm;
5230198Sbostic case C_LIMIT:
5330198Sbostic if ((playit[i] = canplay(pp, op, card))
5430198Sbostic && Numseen[C_25] == Numcards[C_25]
5530198Sbostic && Numseen[C_50] == Numcards[C_50])
5630198Sbostic canstop = TRUE;
5730198Sbostic goto norm;
5830198Sbostic case C_25: case C_50: case C_75:
5930198Sbostic case C_100: case C_200:
6030198Sbostic if ((playit[i] = canplay(pp, op, card))
6130198Sbostic && pp->mileage + Value[card] == End)
6230198Sbostic foundend = TRUE;
6330198Sbostic goto norm;
6430198Sbostic default:
6530198Sbostic playit[i] = canplay(pp, op, card);
6630198Sbostic norm:
6730198Sbostic if (playit[i])
6830198Sbostic ++cango;
6930198Sbostic break;
7030198Sbostic case C_GAS_SAFE: case C_DRIVE_SAFE:
7130198Sbostic case C_SPARE_SAFE: case C_RIGHT_WAY:
7230198Sbostic if (pp->battle == opposite(card) ||
7330198Sbostic (pp->speed == C_LIMIT && card == C_RIGHT_WAY)) {
7430198Sbostic Movetype = M_PLAY;
7530198Sbostic Card_no = i;
7630198Sbostic return;
7730198Sbostic }
7830198Sbostic ++safe;
7930198Sbostic playit[i] = TRUE;
8030198Sbostic break;
8130198Sbostic }
8252876Storek if (card >= 0)
8352876Storek ++count[card];
8430198Sbostic }
8552876Storek
8652876Storek /* No Coup Forre. Draw to fill hand, then restart, as needed. */
8730198Sbostic if (pp->hand[0] == C_INIT && Topcard > Deck) {
8830198Sbostic Movetype = M_DRAW;
8930198Sbostic return;
9030198Sbostic }
9152876Storek
9233170Sbostic #ifdef DEBUG
9330198Sbostic if (Debug)
9430198Sbostic fprintf(outf, "CALCMOVE: cango = %d, canstop = %d, safe = %d\n",
9530198Sbostic cango, canstop, safe);
9633170Sbostic #endif
9730198Sbostic if (foundend)
9830198Sbostic foundend = !check_ext(TRUE);
9930198Sbostic for (i = 0; safe && i < HAND_SZ; i++) {
10030198Sbostic if (issafety(pp->hand[i])) {
10130198Sbostic if (onecard(op) || (foundend && cango && !canstop)) {
10233170Sbostic #ifdef DEBUG
10330198Sbostic if (Debug)
10430198Sbostic fprintf(outf,
10530198Sbostic "CALCMOVE: onecard(op) = %d, foundend = %d\n",
10630198Sbostic onecard(op), foundend);
10733170Sbostic #endif
10830198Sbostic playsafe:
10930198Sbostic Movetype = M_PLAY;
11030198Sbostic Card_no = i;
11130198Sbostic return;
11230198Sbostic }
11330198Sbostic oppos = opposite(pp->hand[i]);
11430198Sbostic if (Numseen[oppos] == Numcards[oppos] &&
11530198Sbostic !(pp->hand[i] == C_RIGHT_WAY &&
11630198Sbostic Numseen[C_LIMIT] != Numcards[C_LIMIT]))
11730198Sbostic goto playsafe;
11830198Sbostic else if (!cango
11930198Sbostic && (op->can_go || !pp->can_go || Topcard < Deck)) {
12030198Sbostic card = (Topcard - Deck) - roll(1, 10);
12130198Sbostic if ((!pp->mileage) != (!op->mileage))
12230198Sbostic card -= 7;
12333170Sbostic #ifdef DEBUG
12430198Sbostic if (Debug)
12530198Sbostic fprintf(outf,
12630198Sbostic "CALCMOVE: card = %d, DECK_SZ / 4 = %d\n",
12730198Sbostic card, DECK_SZ / 4);
12833170Sbostic #endif
12930198Sbostic if (card < DECK_SZ / 4)
13030198Sbostic goto playsafe;
13130198Sbostic }
13230198Sbostic safe--;
13330198Sbostic playit[i] = cango;
13430198Sbostic }
13530198Sbostic }
13630198Sbostic if (!pp->can_go && !isrepair(pp->battle))
13730198Sbostic Numneed[opposite(pp->battle)]++;
13830198Sbostic redoit:
13930198Sbostic foundlow = (cango || count[C_END_LIMIT] != 0
14030198Sbostic || Numseen[C_LIMIT] == Numcards[C_LIMIT]
14130198Sbostic || pp->safety[S_RIGHT_WAY] != S_UNKNOWN);
14230198Sbostic foundend = FALSE;
14330198Sbostic count200 = pp->nummiles[C_200];
14430198Sbostic badcount = 0;
14530198Sbostic curmax = -1;
14630198Sbostic curmin = 101;
14730198Sbostic nummin = -1;
14830198Sbostic nummax = -1;
14930198Sbostic value = valbuf;
15030198Sbostic for (i = 0; i < HAND_SZ; i++) {
15130198Sbostic card = pp->hand[i];
15230198Sbostic if (issafety(card) || playit[i] == (cango != 0)) {
15333170Sbostic #ifdef DEBUG
15430198Sbostic if (Debug)
15530198Sbostic fprintf(outf, "CALCMOVE: switch(\"%s\")\n",
15630198Sbostic C_name[card]);
15733170Sbostic #endif
15830198Sbostic switch (card) {
15930198Sbostic case C_25: case C_50:
16030198Sbostic diff = End - pp->mileage;
16130198Sbostic /* avoid getting too close */
16230198Sbostic if (Topcard > Deck && cango && diff <= 100
16330198Sbostic && diff / Value[card] > count[card]
16430198Sbostic && (card == C_25 || diff % 50 == 0)) {
16530198Sbostic if (card == C_50 && diff - 50 == 25
16630198Sbostic && count[C_25] > 0)
16730198Sbostic goto okay;
16830198Sbostic *value = 0;
16930198Sbostic if (--cango <= 0)
17030198Sbostic goto redoit;
17130198Sbostic break;
17230198Sbostic }
17330198Sbostic okay:
17430198Sbostic *value = (Value[card] >> 3);
17530198Sbostic if (pp->speed == C_LIMIT)
17630198Sbostic ++*value;
17730198Sbostic else
17830198Sbostic --*value;
17930198Sbostic if (!foundlow
18030198Sbostic && (card == C_50 || count[C_50] == 0)) {
18130198Sbostic *value = (pp->mileage ? 10 : 20);
18230198Sbostic foundlow = TRUE;
18330198Sbostic }
18430198Sbostic goto miles;
18530198Sbostic case C_200:
18630198Sbostic if (++count200 > 2) {
18730198Sbostic *value = 0;
18830198Sbostic break;
18930198Sbostic }
19030198Sbostic case C_75: case C_100:
19130198Sbostic *value = (Value[card] >> 3);
19230198Sbostic if (pp->speed == C_LIMIT)
19330198Sbostic --*value;
19430198Sbostic else
19530198Sbostic ++*value;
19630198Sbostic miles:
19730198Sbostic if (pp->mileage + Value[card] > End)
19830198Sbostic *value = (End == 700 ? card : 0);
19930198Sbostic else if (pp->mileage + Value[card] == End) {
20030198Sbostic *value = (foundend ? card : V_VALUABLE);
20130198Sbostic foundend = TRUE;
20230198Sbostic }
20330198Sbostic break;
20430198Sbostic case C_END_LIMIT:
20530198Sbostic if (pp->safety[S_RIGHT_WAY] != S_UNKNOWN)
20630198Sbostic *value = (pp->safety[S_RIGHT_WAY] ==
20730198Sbostic S_PLAYED ? -1 : 1);
20830198Sbostic else if (pp->speed == C_LIMIT &&
20930198Sbostic End - pp->mileage <= 50)
21030198Sbostic *value = 1;
21130198Sbostic else if (pp->speed == C_LIMIT
21230198Sbostic || Numseen[C_LIMIT] != Numcards[C_LIMIT]) {
21330198Sbostic safe = S_RIGHT_WAY;
21430198Sbostic oppos = C_LIMIT;
21530198Sbostic goto repair;
21630198Sbostic }
21730198Sbostic else {
21830198Sbostic *value = 0;
21930198Sbostic --count[C_END_LIMIT];
22030198Sbostic }
22130198Sbostic break;
22230198Sbostic case C_REPAIRS: case C_SPARE: case C_GAS:
22330198Sbostic safe = safety(card) - S_CONV;
22430198Sbostic oppos = opposite(card);
22530198Sbostic if (pp->safety[safe] != S_UNKNOWN)
22630198Sbostic *value = (pp->safety[safe] ==
22730198Sbostic S_PLAYED ? -1 : 1);
22830198Sbostic else if (pp->battle != oppos
22930198Sbostic && (Numseen[oppos] == Numcards[oppos] ||
23030198Sbostic Numseen[oppos] + count[card] >
23130198Sbostic Numcards[oppos])) {
23230198Sbostic *value = 0;
23330198Sbostic --count[card];
23430198Sbostic }
23530198Sbostic else {
23630198Sbostic repair:
23730198Sbostic *value = Numcards[oppos] * 6;
23830198Sbostic *value += Numseen[card] -
23930198Sbostic Numseen[oppos];
24030198Sbostic if (!cango)
24130198Sbostic *value /= (count[card]*count[card]);
24230198Sbostic count[card]--;
24330198Sbostic }
24430198Sbostic break;
24530198Sbostic case C_GO:
24630198Sbostic if (pp->safety[S_RIGHT_WAY] != S_UNKNOWN)
24730198Sbostic *value = (pp->safety[S_RIGHT_WAY] ==
24830198Sbostic S_PLAYED ? -1 : 2);
24930198Sbostic else if (pp->can_go
25030198Sbostic && Numgos + count[C_GO] == Numneed[C_GO]) {
25130198Sbostic *value = 0;
25230198Sbostic --count[C_GO];
25330198Sbostic }
25430198Sbostic else {
25530198Sbostic *value = Numneed[C_GO] * 3;
25630198Sbostic *value += (Numseen[C_GO] - Numgos);
25730198Sbostic *value /= (count[C_GO] * count[C_GO]);
25830198Sbostic count[C_GO]--;
25930198Sbostic }
26030198Sbostic break;
26130198Sbostic case C_LIMIT:
26230198Sbostic if (op->mileage + 50 >= End) {
26330198Sbostic *value = (End == 700 && !cango);
26430198Sbostic break;
26530198Sbostic }
26630198Sbostic if (canstop || (cango && !op->can_go))
26730198Sbostic *value = 1;
26830198Sbostic else {
26930198Sbostic *value = (pp->safety[S_RIGHT_WAY] !=
27030198Sbostic S_UNKNOWN ? 2 : 3);
27130198Sbostic safe = S_RIGHT_WAY;
27230198Sbostic oppos = C_END_LIMIT;
27330198Sbostic goto normbad;
27430198Sbostic }
27530198Sbostic break;
27630198Sbostic case C_CRASH: case C_EMPTY: case C_FLAT:
27730198Sbostic safe = safety(card) - S_CONV;
27830198Sbostic oppos = opposite(card);
27930198Sbostic *value = (pp->safety[safe]!=S_UNKNOWN ? 3 : 4);
28030198Sbostic normbad:
28130198Sbostic if (op->safety[safe] == S_PLAYED)
28230198Sbostic *value = -1;
28330198Sbostic else {
28430198Sbostic *value *= Numneed[oppos] +
28530198Sbostic Numseen[oppos] + 2;
28630198Sbostic if (!pp->mileage || foundend ||
28730198Sbostic onecard(op))
28830198Sbostic *value += 5;
28930198Sbostic if (op->mileage == 0 || onecard(op))
29030198Sbostic *value += 5;
29130198Sbostic if (op->speed == C_LIMIT)
29230198Sbostic *value -= 3;
29330198Sbostic if (cango &&
29430198Sbostic pp->safety[safe] != S_UNKNOWN)
29530198Sbostic *value += 3;
29630198Sbostic if (!cango)
29730198Sbostic *value /= ++badcount;
29830198Sbostic }
29930198Sbostic break;
30030198Sbostic case C_STOP:
30130198Sbostic if (op->safety[S_RIGHT_WAY] == S_PLAYED)
30230198Sbostic *value = -1;
30330198Sbostic else {
30430198Sbostic *value = (pp->safety[S_RIGHT_WAY] !=
30530198Sbostic S_UNKNOWN ? 3 : 4);
30630198Sbostic *value *= Numcards[C_STOP] +
30730198Sbostic Numseen[C_GO];
30830198Sbostic if (!pp->mileage || foundend ||
30930198Sbostic onecard(op))
31030198Sbostic *value += 5;
31130198Sbostic if (!cango)
31230198Sbostic *value /= ++badcount;
31330198Sbostic if (op->mileage == 0)
31430198Sbostic *value += 5;
31530198Sbostic if ((card == C_LIMIT &&
31630198Sbostic op->speed == C_LIMIT) ||
31730198Sbostic !op->can_go)
31830198Sbostic *value -= 5;
31930198Sbostic if (cango && pp->safety[S_RIGHT_WAY] !=
32030198Sbostic S_UNKNOWN)
32130198Sbostic *value += 5;
32230198Sbostic }
32330198Sbostic break;
32430198Sbostic case C_GAS_SAFE: case C_DRIVE_SAFE:
32530198Sbostic case C_SPARE_SAFE: case C_RIGHT_WAY:
32630198Sbostic *value = cango ? 0 : 101;
32730198Sbostic break;
32830198Sbostic case C_INIT:
32930198Sbostic *value = 0;
33030198Sbostic break;
33130198Sbostic }
33230198Sbostic }
33330198Sbostic else
33430198Sbostic *value = cango ? 0 : 101;
33530198Sbostic if (card != C_INIT) {
33630198Sbostic if (*value >= curmax) {
33730198Sbostic nummax = i;
33830198Sbostic curmax = *value;
33930198Sbostic }
34030198Sbostic if (*value <= curmin) {
34130198Sbostic nummin = i;
34230198Sbostic curmin = *value;
34330198Sbostic }
34430198Sbostic }
34533170Sbostic #ifdef DEBUG
34630198Sbostic if (Debug)
34730198Sbostic mvprintw(i + 6, 2, "%3d %-14s", *value,
34830198Sbostic C_name[pp->hand[i]]);
34933170Sbostic #endif
35030198Sbostic value++;
35130198Sbostic }
35230198Sbostic if (!pp->can_go && !isrepair(pp->battle))
35330198Sbostic Numneed[opposite(pp->battle)]++;
35430198Sbostic if (cango) {
35530198Sbostic play_it:
35630198Sbostic mvaddstr(MOVE_Y + 1, MOVE_X, "PLAY\n");
35752876Storek Movetype = M_PLAY;
35852876Storek Card_no = nummax;
35930198Sbostic }
36030198Sbostic else {
36130198Sbostic if (issafety(pp->hand[nummin])) { /* NEVER discard a safety */
36230198Sbostic nummax = nummin;
36330198Sbostic goto play_it;
36430198Sbostic }
36530198Sbostic mvaddstr(MOVE_Y + 1, MOVE_X, "DISCARD\n");
36652876Storek Movetype = M_DISCARD;
36752876Storek Card_no = nummin;
36830198Sbostic }
36930198Sbostic mvprintw(MOVE_Y + 2, MOVE_X, "%16s", C_name[pp->hand[Card_no]]);
37030198Sbostic }
37130198Sbostic
37252876Storek /*
37352876Storek * Return true if the given player could conceivably win with his next card.
37452876Storek */
onecard(pp)37530198Sbostic onecard(pp)
37630198Sbostic register PLAY *pp;
37730198Sbostic {
37830198Sbostic register CARD bat, spd, card;
37930198Sbostic
38030198Sbostic bat = pp->battle;
38130198Sbostic spd = pp->speed;
38230198Sbostic card = -1;
38330198Sbostic if (pp->can_go || ((isrepair(bat) || bat == C_STOP || spd == C_LIMIT) &&
38430198Sbostic Numseen[S_RIGHT_WAY] != 0) ||
38552872Storek bat >= 0 && Numseen[safety(bat)] != 0)
38630198Sbostic switch (End - pp->mileage) {
38730198Sbostic case 200:
38830198Sbostic if (pp->nummiles[C_200] == 2)
38930198Sbostic return FALSE;
39030198Sbostic card = C_200;
39130198Sbostic /* FALLTHROUGH */
39230198Sbostic case 100:
39330198Sbostic case 75:
39430198Sbostic if (card == -1)
39530198Sbostic card = (End - pp->mileage == 75 ? C_75 : C_100);
39630198Sbostic if (spd == C_LIMIT)
39730198Sbostic return Numseen[S_RIGHT_WAY] == 0;
39830198Sbostic case 50:
39930198Sbostic case 25:
40030198Sbostic if (card == -1)
40130198Sbostic card = (End - pp->mileage == 25 ? C_25 : C_50);
40230198Sbostic return Numseen[card] != Numcards[card];
40330198Sbostic }
40430198Sbostic return FALSE;
40530198Sbostic }
40630198Sbostic
canplay(pp,op,card)40730198Sbostic canplay(pp, op, card)
40830198Sbostic register PLAY *pp, *op;
40930198Sbostic register CARD card;
41030198Sbostic {
41130198Sbostic switch (card) {
41230198Sbostic case C_200:
41330198Sbostic if (pp->nummiles[C_200] == 2)
41430198Sbostic break;
41530198Sbostic /* FALLTHROUGH */
41630198Sbostic case C_75: case C_100:
41730198Sbostic if (pp->speed == C_LIMIT)
41830198Sbostic break;
41930198Sbostic /* FALLTHROUGH */
42030198Sbostic case C_50:
42130198Sbostic if (pp->mileage + Value[card] > End)
42230198Sbostic break;
42330198Sbostic /* FALLTHROUGH */
42430198Sbostic case C_25:
42530198Sbostic if (pp->can_go)
42630198Sbostic return TRUE;
42730198Sbostic break;
42830198Sbostic case C_EMPTY: case C_FLAT: case C_CRASH:
42930198Sbostic case C_STOP:
43030198Sbostic if (op->can_go && op->safety[safety(card) - S_CONV] != S_PLAYED)
43130198Sbostic return TRUE;
43230198Sbostic break;
43330198Sbostic case C_LIMIT:
43430198Sbostic if (op->speed != C_LIMIT &&
43530198Sbostic op->safety[S_RIGHT_WAY] != S_PLAYED &&
43630198Sbostic op->mileage + 50 < End)
43730198Sbostic return TRUE;
43830198Sbostic break;
43930198Sbostic case C_GAS: case C_SPARE: case C_REPAIRS:
44030198Sbostic if (pp->battle == opposite(card))
44130198Sbostic return TRUE;
44230198Sbostic break;
44330198Sbostic case C_GO:
44430198Sbostic if (!pp->can_go &&
44530198Sbostic (isrepair(pp->battle) || pp->battle == C_STOP))
44630198Sbostic return TRUE;
44730198Sbostic break;
44830198Sbostic case C_END_LIMIT:
44930198Sbostic if (pp->speed == C_LIMIT)
45030198Sbostic return TRUE;
45130198Sbostic }
45230198Sbostic return FALSE;
45330198Sbostic }
454