Home | History | Annotate | Line # | Download | only in monop
monop.c revision 1.24
      1 /*	$NetBSD: monop.c,v 1.24 2008/07/20 01:03:21 lukem 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.24 2008/07/20 01:03:21 lukem 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 	*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 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 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 RR_S	rr[N_RR];		/* railroad descriptions		*/
    129 
    130 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 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(ac, av)
    227 	int ac;
    228 	char *av[];
    229 {
    230 	/* Revoke setgid privileges */
    231 	setgid(getgid());
    232 
    233 	srandom((unsigned long)time(NULL));
    234 	num_luck = sizeof lucky_mes / sizeof (char *);
    235 	init_decks();
    236 	init_monops();
    237 	if (ac > 1) {
    238 		if (rest_f(av[1]) < 0)
    239 			restore();
    240 	}
    241 	else {
    242 		getplayers();
    243 		init_players();
    244 	}
    245 	signal(SIGINT, do_quit);
    246 	for (;;) {
    247 		printf("\n%s (%d) (cash $%d) on %s\n", cur_p->name, player + 1,
    248 			cur_p->money, board[cur_p->loc].name);
    249 		printturn();
    250 		force_morg();
    251 		execute(getinp("-- Command: ", comlist));
    252 	}
    253 }
    254 
    255 /*ARGSUSED*/
    256 static void
    257 do_quit(n)
    258 	int n __unused;
    259 {
    260 	quit();
    261 }
    262 
    263 /*
    264  *	This routine gets the names of the players
    265  */
    266 static void
    267 getplayers()
    268 {
    269 	int i, j;
    270 	char buf[257];
    271 
    272 blew_it:
    273 	for (;;) {
    274 		if ((num_play = get_int("How many players? ")) <= 1 ||
    275 		    num_play > MAX_PL)
    276 			printf("Sorry. Number must range from 2 to %d\n",
    277 			    MAX_PL);
    278 		else
    279 			break;
    280 	}
    281 	cur_p = play = calloc((size_t)num_play, sizeof (PLAY));
    282 	if (play == NULL)
    283 		err(1, NULL);
    284 	for (i = 0; i < num_play; i++) {
    285 		do {
    286 			printf("Player %d's name: ", i + 1);
    287 			fgets(buf, sizeof(buf), stdin);
    288 			if (feof(stdin)) {
    289 				printf("End of file on stdin\n");
    290 				exit(0);
    291 			}
    292 			buf[strcspn(buf, "\n")] = '\0';
    293 		} while (strlen(buf) == 0);
    294 		name_list[i] = play[i].name = strdup(buf);
    295 		if (name_list[i] == NULL)
    296 			err(1, NULL);
    297 		play[i].money = 1500;
    298 	}
    299 	name_list[i++] = "done";
    300 	name_list[i] = 0;
    301 	for (i = 0; i < num_play; i++)
    302 		for (j = i + 1; j <= num_play; j++)
    303 			if (strcasecmp(name_list[i], name_list[j]) == 0) {
    304 				if (j != num_play)
    305 					printf("Hey!!! Some of those are "
    306 					    "IDENTICAL!!  Let's try that "
    307 					    "again...\n");
    308 				else
    309 					printf("\"done\" is a reserved word.  "
    310 					    "Please try again\n");
    311 				for (i = 0; i < num_play; i++)
    312 					free(play[i].name);
    313 				free(play);
    314 				goto blew_it;
    315 			}
    316 }
    317 
    318 /*
    319  *	This routine figures out who goes first
    320  */
    321 static void
    322 init_players()
    323 {
    324 	int i, rl, cur_max;
    325 	bool over = 0;
    326 	int max_pl = 0;
    327 
    328 again:
    329 	putchar('\n');
    330 	for (cur_max = i = 0; i < num_play; i++) {
    331 		printf("%s (%d) rolls %d\n", play[i].name, i+1, rl=roll(2, 6));
    332 		if (rl > cur_max) {
    333 			over = FALSE;
    334 			cur_max = rl;
    335 			max_pl = i;
    336 		}
    337 		else if (rl == cur_max)
    338 			over++;
    339 	}
    340 	if (over) {
    341 		printf("%d people rolled the same thing, so we'll try again\n",
    342 		    over + 1);
    343 		goto again;
    344 	}
    345 	player = max_pl;
    346 	cur_p = &play[max_pl];
    347 	printf("%s (%d) goes first\n", cur_p->name, max_pl + 1);
    348 }
    349 
    350 /*
    351  *	This routine initializes the monopoly structures.
    352  */
    353 static void
    354 init_monops()
    355 {
    356 	MON *mp;
    357 	int i;
    358 
    359 	for (mp = mon; mp < &mon[N_MON]; mp++) {
    360 		mp->name = mp->not_m;
    361 		for (i = 0; i < mp->num_in; i++)
    362 			mp->sq[i] = &board[mp->sqnums[i]];
    363 	}
    364 }
    365