1*c34afa68Sdholland /* $NetBSD: monop.c,v 1.27 2012/06/19 05:35:32 dholland Exp $ */
242fb1b9dScgd
361f28255Scgd /*
442fb1b9dScgd * Copyright (c) 1980, 1993
542fb1b9dScgd * The Regents of the University of California. All rights reserved.
661f28255Scgd *
761f28255Scgd * Redistribution and use in source and binary forms, with or without
861f28255Scgd * modification, are permitted provided that the following conditions
961f28255Scgd * are met:
1061f28255Scgd * 1. Redistributions of source code must retain the above copyright
1161f28255Scgd * notice, this list of conditions and the following disclaimer.
1261f28255Scgd * 2. Redistributions in binary form must reproduce the above copyright
1361f28255Scgd * notice, this list of conditions and the following disclaimer in the
1461f28255Scgd * documentation and/or other materials provided with the distribution.
15e5aeb4eaSagc * 3. Neither the name of the University nor the names of its contributors
1661f28255Scgd * may be used to endorse or promote products derived from this software
1761f28255Scgd * without specific prior written permission.
1861f28255Scgd *
1961f28255Scgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2061f28255Scgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2161f28255Scgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2261f28255Scgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2361f28255Scgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2461f28255Scgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2561f28255Scgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2661f28255Scgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2761f28255Scgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2861f28255Scgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2961f28255Scgd * SUCH DAMAGE.
3061f28255Scgd */
3161f28255Scgd
32b118ad22Schristos #include <sys/cdefs.h>
3361f28255Scgd #ifndef lint
342fe2731dSlukem __COPYRIGHT("@(#) Copyright (c) 1980, 1993\
352fe2731dSlukem The Regents of the University of California. All rights reserved.");
3661f28255Scgd #endif /* not lint */
3761f28255Scgd
3861f28255Scgd #ifndef lint
3942fb1b9dScgd #if 0
4042fb1b9dScgd static char sccsid[] = "@(#)monop.c 8.1 (Berkeley) 5/31/93";
4142fb1b9dScgd #else
42*c34afa68Sdholland __RCSID("$NetBSD: monop.c,v 1.27 2012/06/19 05:35:32 dholland Exp $");
4342fb1b9dScgd #endif
4461f28255Scgd #endif /* not lint */
4561f28255Scgd
46b118ad22Schristos #include <stdio.h>
47b118ad22Schristos #include <signal.h>
48b118ad22Schristos #include <stdlib.h>
49a03fcca3Sdholland #include <time.h>
50b118ad22Schristos #include <unistd.h>
51b51259daSdholland #include "deck.h"
52b51259daSdholland #include "monop.h"
5361f28255Scgd
54cb5fd834Sjsm int main(int, char *[]);
55cb5fd834Sjsm static void getplayers(void);
56cb5fd834Sjsm static void init_players(void);
57cb5fd834Sjsm static void init_monops(void);
58cb5fd834Sjsm static void do_quit(int);
59b118ad22Schristos
60b51259daSdholland
61b51259daSdholland bool fixing, /* set if fixing up debt */
62b51259daSdholland trading, /* set if in process of trading */
63b51259daSdholland told_em, /* set if told user he's out of debt */
64b51259daSdholland spec; /* set if moving by card to RR or UTIL */
65b51259daSdholland
66f2a20f5fSdholland const char *name_list[MAX_PL+2]; /* list of players' names */
67f2a20f5fSdholland static const char *const comlist[] = { /* list of normal commands */
68b51259daSdholland "quit", /* 0 */ "print", /* 1 */
69b51259daSdholland "where", /* 2 */ "own holdings", /* 3 */
70b51259daSdholland "holdings", /* 4 */ "mortgage", /* 5 */
71b51259daSdholland "unmortgage", /* 6 */ "buy houses", /* 7 */
72b51259daSdholland "sell houses", /* 8 */ "card", /* 9 */
73b51259daSdholland "pay", /* 10 */ "trade", /* 11 */
74b51259daSdholland "resign", /* 12 */ "save", /* 13 */
75b51259daSdholland "restore", /* 14 */ "roll", /* 15 */
76b51259daSdholland "", /* 16 */
77b51259daSdholland 0
78f2a20f5fSdholland };
79f2a20f5fSdholland const char *const yncoms[] = { /* list of commands for yes/no answers */
80b51259daSdholland "yes", /* 0 */ "no", /* 1 */
81b51259daSdholland "quit", /* 2 */ "print", /* 3 */
82b51259daSdholland "where", /* 4 */ "own holdings", /* 5 */
83b51259daSdholland "holdings", /* 6 */
84b51259daSdholland 0
85f2a20f5fSdholland };
86f2a20f5fSdholland const char *const lucky_mes[] = { /* "got lucky" messages */
87b51259daSdholland "You lucky stiff", "You got lucky",
88b51259daSdholland "What a lucky person!", "You must have a 4-leaf clover",
89b51259daSdholland "My, my! Aren't we lucky!", "Luck smiles upon you",
90b51259daSdholland "You got lucky this time", "Lucky person!",
91b51259daSdholland "Your karma must certainly be together",
92b51259daSdholland "How beautifully Cosmic", "Wow, you must be really with it"
93b51259daSdholland /* "I want your autograph", -- Save for later */
94b51259daSdholland };
95b51259daSdholland
96b51259daSdholland int player, /* current player number */
97b51259daSdholland num_play, /* current number of players */
98b51259daSdholland num_doub, /* # of doubles current player rolled */
99b51259daSdholland /* # of "got lucky" messages */
100b51259daSdholland num_luck = sizeof lucky_mes / sizeof (char *);
101b51259daSdholland
102b51259daSdholland /* list of command functions */
103b51259daSdholland void (*const func[])(void) = { /* array of function calls for commands */
104b51259daSdholland quit, /* quit game |* 0 *| */
105b51259daSdholland printboard, /* print board |* 1 *| */
106b51259daSdholland where, /* where players are |* 2 *| */
107b51259daSdholland list, /* own holdings |* 3 *| */
108b51259daSdholland list_all, /* holdings list |* 4 *| */
109b51259daSdholland mortgage, /* mortgage property |* 5 *| */
110b51259daSdholland unmortgage, /* unmortgage property |* 6 *| */
111b51259daSdholland buy_houses, /* buy houses |* 7 *| */
112b51259daSdholland sell_houses, /* sell houses |* 8 *| */
113b51259daSdholland card, /* card for jail |* 9 *| */
114b51259daSdholland pay, /* pay for jail |* 10 *| */
115b51259daSdholland trade, /* trade |* 11 *| */
116b51259daSdholland resign, /* resign |* 12 *| */
117b51259daSdholland save, /* save game |* 13 *| */
118b51259daSdholland restore, /* restore game |* 14 *| */
119b51259daSdholland do_move, /* roll |* 15 *| */
120b51259daSdholland do_move /* "" |* 16 *| */
121b51259daSdholland };
122b51259daSdholland
123b51259daSdholland DECK deck[2]; /* Chance and Community Chest */
124b51259daSdholland
125b51259daSdholland PLAY *play, /* player structure array ("calloc"ed) */
126b51259daSdholland *cur_p; /* pointer to current player's struct */
127b51259daSdholland
128f2a20f5fSdholland static RR_S rr[N_RR]; /* railroad descriptions */
129b51259daSdholland
130f2a20f5fSdholland static UTIL_S util[2]; /* utility descriptions */
131b51259daSdholland
132b51259daSdholland #define MONINIT(num_in, h_cost, not_m, mon_n, sq1,sq2,sq3) \
133b51259daSdholland {0, -1, num_in, 0, h_cost, not_m, mon_n, {sq1,sq2,sq3}, {0,0,0}}
134b51259daSdholland /* name owner num_own sq */
135b51259daSdholland
136f2a20f5fSdholland static MON mon[N_MON] = { /* monopoly descriptions */
137b51259daSdholland /* num_in h_cost not_m mon_n sqnums */
138b51259daSdholland MONINIT(2, 1, "Purple", "PURPLE", 1,3, 0),
139b51259daSdholland MONINIT(3, 1, "Lt. Blue", "LT. BLUE", 6,8,9),
140b51259daSdholland MONINIT(3, 2, "Violet", "VIOLET", 11,13,14),
141b51259daSdholland MONINIT(3, 2, "Orange", "ORANGE", 16,18,19),
142b51259daSdholland MONINIT(3, 3, "Red", "RED", 21,23,24),
143b51259daSdholland MONINIT(3, 3, "Yellow", "YELLOW", 26,27,29),
144b51259daSdholland MONINIT(3, 4, "Green", "GREEN", 31,32,34),
145b51259daSdholland MONINIT(2, 4, "Dk. Blue", "DK. BLUE", 37,39, 0),
146b51259daSdholland };
147b51259daSdholland #undef MONINIT
148b51259daSdholland
149b51259daSdholland PROP prop[N_PROP] = { /* typical properties */
150b51259daSdholland /* morg monop square houses mon_desc rent */
151b51259daSdholland {0, 0, 1, 0, &mon[0], { 2, 10, 30, 90, 160, 250} },
152b51259daSdholland {0, 0, 3, 0, &mon[0], { 4, 20, 60, 180, 320, 450} },
153b51259daSdholland {0, 0, 6, 0, &mon[1], { 6, 30, 90, 270, 400, 550} },
154b51259daSdholland {0, 0, 7, 0, &mon[1], { 6, 30, 90, 270, 400, 550} },
155b51259daSdholland {0, 0, 9, 0, &mon[1], { 8, 40,100, 300, 450, 600} },
156b51259daSdholland {0, 0, 11, 0, &mon[2], {10, 50,150, 450, 625, 750} },
157b51259daSdholland {0, 0, 13, 0, &mon[2], {10, 50,150, 450, 625, 750} },
158b51259daSdholland {0, 0, 14, 0, &mon[2], {12, 60,180, 500, 700, 900} },
159b51259daSdholland {0, 0, 16, 0, &mon[3], {14, 70,200, 550, 750, 950} },
160b51259daSdholland {0, 0, 17, 0, &mon[3], {14, 70,200, 550, 750, 950} },
161b51259daSdholland {0, 0, 19, 0, &mon[3], {16, 80,220, 600, 800,1000} },
162b51259daSdholland {0, 0, 21, 0, &mon[4], {18, 90,250, 700, 875,1050} },
163b51259daSdholland {0, 0, 23, 0, &mon[4], {18, 90,250, 700, 875,1050} },
164b51259daSdholland {0, 0, 24, 0, &mon[4], {20,100,300, 750, 925,1100} },
165b51259daSdholland {0, 0, 26, 0, &mon[5], {22,110,330, 800, 975,1150} },
166b51259daSdholland {0, 0, 27, 0, &mon[5], {22,110,330, 800, 975,1150} },
167b51259daSdholland {0, 0, 29, 0, &mon[5], {24,120,360, 850,1025,1200} },
168b51259daSdholland {0, 0, 31, 0, &mon[6], {26,130,390, 900,1100,1275} },
169b51259daSdholland {0, 0, 32, 0, &mon[6], {26,130,390, 900,1100,1275} },
170b51259daSdholland {0, 0, 34, 0, &mon[6], {28,150,450,1000,1200,1400} },
171b51259daSdholland {0, 0, 37, 0, &mon[7], {35,175,500,1100,1300,1500} },
172b51259daSdholland {0, 0, 39, 0, &mon[7], {50,200,600,1400,1700,2000} }
173b51259daSdholland };
174b51259daSdholland
175b51259daSdholland SQUARE board[N_SQRS+1] = { /* board itself (+1 for Jail) */
176b51259daSdholland /* name (COLOR) owner type desc cost */
177b51259daSdholland
178b51259daSdholland {"=== GO ===", -1, SAFE, NULL, 0 },
179b51259daSdholland {"Mediterranean Ave. (P)", -1, PRPTY, &prop[0], 60 },
180b51259daSdholland {"Community Chest i", -1, CC, NULL, 0 },
181b51259daSdholland {"Baltic Ave. (P)", -1, PRPTY, &prop[1], 60 },
182b51259daSdholland {"Income Tax", -1, INC_TAX, NULL, 0 },
183b51259daSdholland {"Reading RR", -1, RR, &rr[0], 200 },
184b51259daSdholland {"Oriental Ave. (L)", -1, PRPTY, &prop[2], 100 },
185b51259daSdholland {"Chance i", -1, CHANCE, NULL, 0 },
186b51259daSdholland {"Vermont Ave. (L)", -1, PRPTY, &prop[3], 100 },
187b51259daSdholland {"Connecticut Ave. (L)", -1, PRPTY, &prop[4], 120 },
188b51259daSdholland {"Just Visiting", -1, SAFE, NULL, 0 },
189b51259daSdholland {"St. Charles Pl. (V)", -1, PRPTY, &prop[5], 140 },
190b51259daSdholland {"Electric Co.", -1, UTIL, &util[0], 150 },
191b51259daSdholland {"States Ave. (V)", -1, PRPTY, &prop[6], 140 },
192b51259daSdholland {"Virginia Ave. (V)", -1, PRPTY, &prop[7], 160 },
193b51259daSdholland {"Pennsylvania RR", -1, RR, &rr[1], 200 },
194b51259daSdholland {"St. James Pl. (O)", -1, PRPTY, &prop[8], 180 },
195b51259daSdholland {"Community Chest ii", -1, CC, NULL, 0 },
196b51259daSdholland {"Tennessee Ave. (O)", -1, PRPTY, &prop[9], 180 },
197b51259daSdholland {"New York Ave. (O)", -1, PRPTY, &prop[10], 200 },
198b51259daSdholland {"Free Parking", -1, SAFE, NULL, 0 },
199b51259daSdholland {"Kentucky Ave. (R)", -1, PRPTY, &prop[11], 220 },
200b51259daSdholland {"Chance ii", -1, CHANCE, NULL, 0 },
201b51259daSdholland {"Indiana Ave. (R)", -1, PRPTY, &prop[12], 220 },
202b51259daSdholland {"Illinois Ave. (R)", -1, PRPTY, &prop[13], 240 },
203b51259daSdholland {"B&O RR", -1, RR, &rr[2], 200 },
204b51259daSdholland {"Atlantic Ave. (Y)", -1, PRPTY, &prop[14], 260 },
205b51259daSdholland {"Ventnor Ave. (Y)", -1, PRPTY, &prop[15], 260 },
206b51259daSdholland {"Water Works", -1, UTIL, &util[1], 150 },
207b51259daSdholland {"Marvin Gardens (Y)", -1, PRPTY, &prop[16], 280 },
208b51259daSdholland {"GO TO JAIL", -1, GOTO_J, NULL, 0 },
209b51259daSdholland {"Pacific Ave. (G)", -1, PRPTY, &prop[17], 300 },
210b51259daSdholland {"N. Carolina Ave. (G)", -1, PRPTY, &prop[18], 300 },
211b51259daSdholland {"Community Chest iii", -1, CC, NULL, 0 },
212b51259daSdholland {"Pennsylvania Ave. (G)", -1, PRPTY, &prop[19], 320 },
213b51259daSdholland {"Short Line RR", -1, RR, &rr[3], 200 },
214b51259daSdholland {"Chance iii", -1, CHANCE, NULL, 0 },
215b51259daSdholland {"Park Place (D)", -1, PRPTY, &prop[20], 350 },
216b51259daSdholland {"Luxury Tax", -1, LUX_TAX, NULL, 0 },
217b51259daSdholland {"Boardwalk (D)", -1, PRPTY, &prop[21], 400 },
218b51259daSdholland {"JAIL", -1, IN_JAIL, NULL, 0 }
219b51259daSdholland };
220b51259daSdholland
221b51259daSdholland
22261f28255Scgd /*
22361f28255Scgd * This program implements a monopoly game
22461f28255Scgd */
225b118ad22Schristos int
main(int ac,char * av[])226*c34afa68Sdholland main(int ac, char *av[])
227e42b2048Ssimonb {
2285367f340Sjsm /* Revoke setgid privileges */
229f9eca697Smycroft setgid(getgid());
2305367f340Sjsm
231dc11f84dSchristos srandom((unsigned long)time(NULL));
232d49f907eSdholland num_luck = sizeof lucky_mes / sizeof (char *);
233d49f907eSdholland init_decks();
234d49f907eSdholland init_monops();
23561f28255Scgd if (ac > 1) {
236c0cbd1abSdholland if (rest_f(av[1]) < 0)
23761f28255Scgd restore();
23861f28255Scgd }
23961f28255Scgd else {
24061f28255Scgd getplayers();
24161f28255Scgd init_players();
24261f28255Scgd }
243e1627357Shubertf signal(SIGINT, do_quit);
24461f28255Scgd for (;;) {
24561f28255Scgd printf("\n%s (%d) (cash $%d) on %s\n", cur_p->name, player + 1,
24661f28255Scgd cur_p->money, board[cur_p->loc].name);
24761f28255Scgd printturn();
24861f28255Scgd force_morg();
24961f28255Scgd execute(getinp("-- Command: ", comlist));
25061f28255Scgd }
25161f28255Scgd }
252b118ad22Schristos
253b118ad22Schristos /*ARGSUSED*/
254b118ad22Schristos static void
do_quit(int n __unused)255*c34afa68Sdholland do_quit(int n __unused)
256b118ad22Schristos {
257b118ad22Schristos quit();
258b118ad22Schristos }
259e42b2048Ssimonb
26061f28255Scgd /*
26161f28255Scgd * This routine gets the names of the players
26261f28255Scgd */
263b118ad22Schristos static void
getplayers(void)264*c34afa68Sdholland getplayers(void)
265b118ad22Schristos {
266b118ad22Schristos int i, j;
26761f28255Scgd char buf[257];
26861f28255Scgd
26961f28255Scgd blew_it:
27061f28255Scgd for (;;) {
271d49f907eSdholland if ((num_play = get_int("How many players? ")) <= 1 ||
27261f28255Scgd num_play > MAX_PL)
273d49f907eSdholland printf("Sorry. Number must range from 2 to %d\n",
274d49f907eSdholland MAX_PL);
27561f28255Scgd else
27661f28255Scgd break;
27761f28255Scgd }
278dc11f84dSchristos cur_p = play = calloc((size_t)num_play, sizeof (PLAY));
279a9c7f9b0Sjsm if (play == NULL)
280a5da40c5Sjsm err(1, NULL);
28161f28255Scgd for (i = 0; i < num_play; i++) {
282d49f907eSdholland do {
28361f28255Scgd printf("Player %d's name: ", i + 1);
284d49f907eSdholland fgets(buf, sizeof(buf), stdin);
285d49f907eSdholland if (feof(stdin)) {
286c509c631Sahoka quit();
287d49f907eSdholland }
288d49f907eSdholland buf[strcspn(buf, "\n")] = '\0';
289d49f907eSdholland } while (strlen(buf) == 0);
290d49f907eSdholland name_list[i] = play[i].name = strdup(buf);
291a9c7f9b0Sjsm if (name_list[i] == NULL)
292a5da40c5Sjsm err(1, NULL);
29361f28255Scgd play[i].money = 1500;
29461f28255Scgd }
29561f28255Scgd name_list[i++] = "done";
29661f28255Scgd name_list[i] = 0;
29761f28255Scgd for (i = 0; i < num_play; i++)
298d49f907eSdholland for (j = i + 1; j <= num_play; j++)
29961f28255Scgd if (strcasecmp(name_list[i], name_list[j]) == 0) {
300d49f907eSdholland if (j != num_play)
301e42b2048Ssimonb printf("Hey!!! Some of those are "
302e42b2048Ssimonb "IDENTICAL!! Let's try that "
303d49f907eSdholland "again...\n");
30461f28255Scgd else
305e42b2048Ssimonb printf("\"done\" is a reserved word. "
306e42b2048Ssimonb "Please try again\n");
30761f28255Scgd for (i = 0; i < num_play; i++)
308b118ad22Schristos free(play[i].name);
309b118ad22Schristos free(play);
31061f28255Scgd goto blew_it;
31161f28255Scgd }
31261f28255Scgd }
313e42b2048Ssimonb
31461f28255Scgd /*
31561f28255Scgd * This routine figures out who goes first
31661f28255Scgd */
317b118ad22Schristos static void
init_players(void)318*c34afa68Sdholland init_players(void)
319b118ad22Schristos {
320b118ad22Schristos int i, rl, cur_max;
321b118ad22Schristos bool over = 0;
322b118ad22Schristos int max_pl = 0;
32361f28255Scgd
32461f28255Scgd again:
32561f28255Scgd putchar('\n');
32661f28255Scgd for (cur_max = i = 0; i < num_play; i++) {
32761f28255Scgd printf("%s (%d) rolls %d\n", play[i].name, i+1, rl=roll(2, 6));
32861f28255Scgd if (rl > cur_max) {
32961f28255Scgd over = FALSE;
33061f28255Scgd cur_max = rl;
33161f28255Scgd max_pl = i;
33261f28255Scgd }
33361f28255Scgd else if (rl == cur_max)
33461f28255Scgd over++;
33561f28255Scgd }
33661f28255Scgd if (over) {
33761f28255Scgd printf("%d people rolled the same thing, so we'll try again\n",
33861f28255Scgd over + 1);
33961f28255Scgd goto again;
34061f28255Scgd }
34161f28255Scgd player = max_pl;
34261f28255Scgd cur_p = &play[max_pl];
34361f28255Scgd printf("%s (%d) goes first\n", cur_p->name, max_pl + 1);
34461f28255Scgd }
345e42b2048Ssimonb
34661f28255Scgd /*
3479fa0b176Swiz * This routine initializes the monopoly structures.
34861f28255Scgd */
349b118ad22Schristos static void
init_monops(void)350*c34afa68Sdholland init_monops(void)
351b118ad22Schristos {
352b118ad22Schristos MON *mp;
353b118ad22Schristos int i;
35461f28255Scgd
35561f28255Scgd for (mp = mon; mp < &mon[N_MON]; mp++) {
35661f28255Scgd mp->name = mp->not_m;
35761f28255Scgd for (i = 0; i < mp->num_in; i++)
35861f28255Scgd mp->sq[i] = &board[mp->sqnums[i]];
35961f28255Scgd }
36061f28255Scgd }
361