xref: /minix/games/monop/monop.c (revision e39e890e)
1 /*	$NetBSD: monop.c,v 1.27 2012/06/19 05:35:32 dholland Exp $	*/
2 
3 /*
4  * Copyright (c) 1980, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 #ifndef lint
34 __COPYRIGHT("@(#) Copyright (c) 1980, 1993\
35  The Regents of the University of California.  All rights reserved.");
36 #endif /* not lint */
37 
38 #ifndef lint
39 #if 0
40 static char sccsid[] = "@(#)monop.c	8.1 (Berkeley) 5/31/93";
41 #else
42 __RCSID("$NetBSD: monop.c,v 1.27 2012/06/19 05:35:32 dholland Exp $");
43 #endif
44 #endif /* not lint */
45 
46 #include <stdio.h>
47 #include <signal.h>
48 #include <stdlib.h>
49 #include <time.h>
50 #include <unistd.h>
51 #include "deck.h"
52 #include "monop.h"
53 
54 int main(int, char *[]);
55 static void getplayers(void);
56 static void init_players(void);
57 static void init_monops(void);
58 static void do_quit(int);
59 
60 
61 bool	fixing,			/* set if fixing up debt		*/
62 	trading,		/* set if in process of trading		*/
63 	told_em,		/* set if told user he's out of debt	*/
64 	spec;			/* set if moving by card to RR or UTIL	*/
65 
66 const char *name_list[MAX_PL+2];	/* list of players' names	*/
67 static const char *const comlist[] = {	/* list of normal commands 	*/
68 	"quit",		/*  0 */	"print",	/*  1 */
69 	"where",	/*  2 */	"own holdings",	/*  3 */
70 	"holdings",	/*  4 */	"mortgage",	/*  5 */
71 	"unmortgage",	/*  6 */	"buy houses",	/*  7 */
72 	"sell houses",	/*  8 */	"card",		/*  9 */
73 	"pay",		/* 10 */	"trade",	/* 11 */
74 	"resign",	/* 12 */	"save",		/* 13 */
75 	"restore",	/* 14 */	"roll",		/* 15 */
76 	"",		/* 16 */
77 	0
78 };
79 const char *const yncoms[] = {	/* list of commands for yes/no answers	*/
80 	"yes",		/*  0 */	"no",		/*  1 */
81 	"quit",		/*  2 */	"print",	/*  3 */
82 	"where",	/*  4 */	"own holdings",	/*  5 */
83 	"holdings",	/*  6 */
84 	0
85 };
86 const char *const lucky_mes[]	= {	/* "got lucky" messages		*/
87 	"You lucky stiff",		"You got lucky",
88 	"What a lucky person!",		"You must have a 4-leaf clover",
89 	"My, my!  Aren't we lucky!",	"Luck smiles upon you",
90 	"You got lucky this time",	"Lucky person!",
91 	"Your karma must certainly be together",
92 	"How beautifully Cosmic",	"Wow, you must be really with it"
93 	/* "I want your autograph",	-- Save for later */
94 };
95 
96 int	player,			/* current player number		*/
97 	num_play,		/* current number of players		*/
98 	num_doub,		/* # of doubles current player rolled	*/
99 				/* # of "got lucky" messages		*/
100 	num_luck	= sizeof lucky_mes / sizeof (char *);
101 
102 /* list of command functions		*/
103 void (*const func[])(void) = { /* array of function calls for commands */
104 	quit,			/* quit game		|*  0 *|	*/
105 	printboard,		/* print board		|*  1 *|	*/
106 	where,			/* where players are	|*  2 *|	*/
107 	list,			/* own holdings		|*  3 *|	*/
108 	list_all,		/* holdings list	|*  4 *|	*/
109 	mortgage,		/* mortgage property	|*  5 *|	*/
110 	unmortgage,		/* unmortgage property	|*  6 *|	*/
111 	buy_houses,		/* buy houses		|*  7 *|	*/
112 	sell_houses,		/* sell houses		|*  8 *|	*/
113 	card,			/* card for jail	|*  9 *|	*/
114 	pay,			/* pay for jail		|* 10 *|	*/
115 	trade,			/* trade		|* 11 *|	*/
116 	resign,			/* resign		|* 12 *|	*/
117 	save,			/* save game		|* 13 *|	*/
118 	restore,		/* restore game		|* 14 *|	*/
119 	do_move,		/* roll			|* 15 *|	*/
120 	do_move			/* ""			|* 16 *|	*/
121 	};
122 
123 DECK	deck[2];		/* Chance and Community Chest		*/
124 
125 PLAY	*play,			/* player structure array ("calloc"ed)	*/
126 	*cur_p;			/* pointer to current player's struct	*/
127 
128 static RR_S rr[N_RR];		/* railroad descriptions		*/
129 
130 static UTIL_S util[2];		/* utility descriptions			*/
131 
132 #define MONINIT(num_in, h_cost, not_m, mon_n, sq1,sq2,sq3) \
133      {0,    -1, num_in, 0,      h_cost, not_m, mon_n, {sq1,sq2,sq3}, {0,0,0}}
134 /* name  owner          num_own                                      sq */
135 
136 static MON mon[N_MON] = {	/* monopoly descriptions		*/
137 /*   num_in h_cost  not_m	mon_n	    sqnums */
138 MONINIT(2,  1,	"Purple",	"PURPLE",   1,3, 0),
139 MONINIT(3,  1,	"Lt. Blue",	"LT. BLUE", 6,8,9),
140 MONINIT(3,  2,	"Violet",	"VIOLET",   11,13,14),
141 MONINIT(3,  2,	"Orange",	"ORANGE",   16,18,19),
142 MONINIT(3,  3,	"Red",		"RED",	    21,23,24),
143 MONINIT(3,  3,	"Yellow",	"YELLOW",   26,27,29),
144 MONINIT(3,  4,	"Green",	"GREEN",    31,32,34),
145 MONINIT(2,  4,	"Dk. Blue",	"DK. BLUE", 37,39, 0),
146 };
147 #undef MONINIT
148 
149 PROP	prop[N_PROP]	= {	/* typical properties			*/
150 /* morg	monop	square	houses	mon_desc	rent	*/
151 {0,	0,	1,	0,	&mon[0],	{ 2, 10, 30,  90, 160, 250} },
152 {0,	0,	3,	0,	&mon[0],	{ 4, 20, 60, 180, 320, 450} },
153 {0,	0,	6,	0,	&mon[1],	{ 6, 30, 90, 270, 400, 550} },
154 {0,	0,	7,	0,	&mon[1],	{ 6, 30, 90, 270, 400, 550} },
155 {0,	0,	9,	0,	&mon[1],	{ 8, 40,100, 300, 450, 600} },
156 {0,	0,	11,	0,	&mon[2],	{10, 50,150, 450, 625, 750} },
157 {0,	0,	13,	0,	&mon[2],	{10, 50,150, 450, 625, 750} },
158 {0,	0,	14,	0,	&mon[2],	{12, 60,180, 500, 700, 900} },
159 {0,	0,	16,	0,	&mon[3],	{14, 70,200, 550, 750, 950} },
160 {0,	0,	17,	0,	&mon[3],	{14, 70,200, 550, 750, 950} },
161 {0,	0,	19,	0,	&mon[3],	{16, 80,220, 600, 800,1000} },
162 {0,	0,	21,	0,	&mon[4],	{18, 90,250, 700, 875,1050} },
163 {0,	0,	23,	0,	&mon[4],	{18, 90,250, 700, 875,1050} },
164 {0,	0,	24,	0,	&mon[4],	{20,100,300, 750, 925,1100} },
165 {0,	0,	26,	0,	&mon[5],	{22,110,330, 800, 975,1150} },
166 {0,	0,	27,	0,	&mon[5],	{22,110,330, 800, 975,1150} },
167 {0,	0,	29,	0,	&mon[5],	{24,120,360, 850,1025,1200} },
168 {0,	0,	31,	0,	&mon[6],	{26,130,390, 900,1100,1275} },
169 {0,	0,	32,	0,	&mon[6],	{26,130,390, 900,1100,1275} },
170 {0,	0,	34,	0,	&mon[6],	{28,150,450,1000,1200,1400} },
171 {0,	0,	37,	0,	&mon[7],	{35,175,500,1100,1300,1500} },
172 {0,	0,	39,	0,	&mon[7],	{50,200,600,1400,1700,2000} }
173 };
174 
175 SQUARE	board[N_SQRS+1]	= {	/* board itself (+1 for Jail)		*/
176 /* name (COLOR)			owner	type	desc		cost	*/
177 
178 {"=== GO ===",			-1,	SAFE,	NULL,		0	},
179 {"Mediterranean Ave. (P)",	-1,	PRPTY,	&prop[0],	60	},
180 {"Community Chest i",		-1,	CC,	NULL,		0	},
181 {"Baltic Ave. (P)",		-1,	PRPTY,	&prop[1],	60	},
182 {"Income Tax",			-1,	INC_TAX, NULL,		0	},
183 {"Reading RR",			-1,	RR,	&rr[0],		200	},
184 {"Oriental Ave. (L)",		-1,	PRPTY,	&prop[2],	100	},
185 {"Chance i",			-1,	CHANCE,	NULL,		0	},
186 {"Vermont Ave. (L)",		-1,	PRPTY,	&prop[3],	100	},
187 {"Connecticut Ave. (L)",	-1,	PRPTY,	&prop[4],	120	},
188 {"Just Visiting",		-1,	SAFE,	NULL,		0	},
189 {"St. Charles Pl. (V)",		-1,	PRPTY,	&prop[5],	140	},
190 {"Electric Co.",		-1,	UTIL,	&util[0],	150	},
191 {"States Ave. (V)",		-1,	PRPTY,	&prop[6],	140	},
192 {"Virginia Ave. (V)",		-1,	PRPTY,	&prop[7],	160	},
193 {"Pennsylvania RR",		-1,	RR,	&rr[1],		200	},
194 {"St. James Pl. (O)",		-1,	PRPTY,	&prop[8],	180	},
195 {"Community Chest ii",		-1,	CC,	NULL,		0	},
196 {"Tennessee Ave. (O)",		-1,	PRPTY,	&prop[9],	180	},
197 {"New York Ave. (O)",		-1,	PRPTY,	&prop[10],	200	},
198 {"Free Parking",		-1,	SAFE,	NULL,		0	},
199 {"Kentucky Ave. (R)",		-1,	PRPTY,	&prop[11],	220	},
200 {"Chance ii",			-1,	CHANCE,	NULL,		0	},
201 {"Indiana Ave. (R)",		-1,	PRPTY,	&prop[12],	220	},
202 {"Illinois Ave. (R)",		-1,	PRPTY,	&prop[13],	240	},
203 {"B&O RR",			-1,	RR,	&rr[2],		200	},
204 {"Atlantic Ave. (Y)",		-1,	PRPTY,	&prop[14],	260	},
205 {"Ventnor Ave. (Y)",		-1,	PRPTY,	&prop[15],	260	},
206 {"Water Works",			-1,	UTIL,	&util[1],	150	},
207 {"Marvin Gardens (Y)",		-1,	PRPTY,	&prop[16],	280	},
208 {"GO TO JAIL",			-1,	GOTO_J,	NULL,		0	},
209 {"Pacific Ave. (G)",		-1,	PRPTY,	&prop[17],	300	},
210 {"N. Carolina Ave. (G)",	-1,	PRPTY,	&prop[18],	300	},
211 {"Community Chest iii",		-1,	CC,	NULL,		0	},
212 {"Pennsylvania Ave. (G)",	-1,	PRPTY,	&prop[19],	320	},
213 {"Short Line RR",		-1,	RR,	&rr[3],		200	},
214 {"Chance iii",			-1,	CHANCE,	NULL,		0	},
215 {"Park Place (D)",		-1,	PRPTY,	&prop[20],	350	},
216 {"Luxury Tax",			-1,	LUX_TAX, NULL,		0	},
217 {"Boardwalk (D)",		-1,	PRPTY,	&prop[21],	400	},
218 {"JAIL",			-1,	IN_JAIL, NULL,		0	}
219 };
220 
221 
222 /*
223  *	This program implements a monopoly game
224  */
225 int
226 main(int ac, char *av[])
227 {
228 	/* Revoke setgid privileges */
229 	setgid(getgid());
230 
231 	srandom((unsigned long)time(NULL));
232 	num_luck = sizeof lucky_mes / sizeof (char *);
233 	init_decks();
234 	init_monops();
235 	if (ac > 1) {
236 		if (rest_f(av[1]) < 0)
237 			restore();
238 	}
239 	else {
240 		getplayers();
241 		init_players();
242 	}
243 	signal(SIGINT, do_quit);
244 	for (;;) {
245 		printf("\n%s (%d) (cash $%d) on %s\n", cur_p->name, player + 1,
246 			cur_p->money, board[cur_p->loc].name);
247 		printturn();
248 		force_morg();
249 		execute(getinp("-- Command: ", comlist));
250 	}
251 }
252 
253 /*ARGSUSED*/
254 static void
255 do_quit(int n __unused)
256 {
257 	quit();
258 }
259 
260 /*
261  *	This routine gets the names of the players
262  */
263 static void
264 getplayers(void)
265 {
266 	int i, j;
267 	char buf[257];
268 
269 blew_it:
270 	for (;;) {
271 		if ((num_play = get_int("How many players? ")) <= 1 ||
272 		    num_play > MAX_PL)
273 			printf("Sorry. Number must range from 2 to %d\n",
274 			    MAX_PL);
275 		else
276 			break;
277 	}
278 	cur_p = play = calloc((size_t)num_play, sizeof (PLAY));
279 	if (play == NULL)
280 		err(1, NULL);
281 	for (i = 0; i < num_play; i++) {
282 		do {
283 			printf("Player %d's name: ", i + 1);
284 			fgets(buf, sizeof(buf), stdin);
285 			if (feof(stdin)) {
286 				quit();
287 			}
288 			buf[strcspn(buf, "\n")] = '\0';
289 		} while (strlen(buf) == 0);
290 		name_list[i] = play[i].name = strdup(buf);
291 		if (name_list[i] == NULL)
292 			err(1, NULL);
293 		play[i].money = 1500;
294 	}
295 	name_list[i++] = "done";
296 	name_list[i] = 0;
297 	for (i = 0; i < num_play; i++)
298 		for (j = i + 1; j <= num_play; j++)
299 			if (strcasecmp(name_list[i], name_list[j]) == 0) {
300 				if (j != num_play)
301 					printf("Hey!!! Some of those are "
302 					    "IDENTICAL!!  Let's try that "
303 					    "again...\n");
304 				else
305 					printf("\"done\" is a reserved word.  "
306 					    "Please try again\n");
307 				for (i = 0; i < num_play; i++)
308 					free(play[i].name);
309 				free(play);
310 				goto blew_it;
311 			}
312 }
313 
314 /*
315  *	This routine figures out who goes first
316  */
317 static void
318 init_players(void)
319 {
320 	int i, rl, cur_max;
321 	bool over = 0;
322 	int max_pl = 0;
323 
324 again:
325 	putchar('\n');
326 	for (cur_max = i = 0; i < num_play; i++) {
327 		printf("%s (%d) rolls %d\n", play[i].name, i+1, rl=roll(2, 6));
328 		if (rl > cur_max) {
329 			over = FALSE;
330 			cur_max = rl;
331 			max_pl = i;
332 		}
333 		else if (rl == cur_max)
334 			over++;
335 	}
336 	if (over) {
337 		printf("%d people rolled the same thing, so we'll try again\n",
338 		    over + 1);
339 		goto again;
340 	}
341 	player = max_pl;
342 	cur_p = &play[max_pl];
343 	printf("%s (%d) goes first\n", cur_p->name, max_pl + 1);
344 }
345 
346 /*
347  *	This routine initializes the monopoly structures.
348  */
349 static void
350 init_monops(void)
351 {
352 	MON *mp;
353 	int i;
354 
355 	for (mp = mon; mp < &mon[N_MON]; mp++) {
356 		mp->name = mp->not_m;
357 		for (i = 0; i < mp->num_in; i++)
358 			mp->sq[i] = &board[mp->sqnums[i]];
359 	}
360 }
361