Home | History | Annotate | Line # | Download | only in monop
monop.c revision 1.26
      1 /*	$NetBSD: monop.c,v 1.26 2011/12/01 07:05:52 ahoka 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.26 2011/12/01 07:05:52 ahoka 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(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 				quit();
    290 			}
    291 			buf[strcspn(buf, "\n")] = '\0';
    292 		} while (strlen(buf) == 0);
    293 		name_list[i] = play[i].name = strdup(buf);
    294 		if (name_list[i] == NULL)
    295 			err(1, NULL);
    296 		play[i].money = 1500;
    297 	}
    298 	name_list[i++] = "done";
    299 	name_list[i] = 0;
    300 	for (i = 0; i < num_play; i++)
    301 		for (j = i + 1; j <= num_play; j++)
    302 			if (strcasecmp(name_list[i], name_list[j]) == 0) {
    303 				if (j != num_play)
    304 					printf("Hey!!! Some of those are "
    305 					    "IDENTICAL!!  Let's try that "
    306 					    "again...\n");
    307 				else
    308 					printf("\"done\" is a reserved word.  "
    309 					    "Please try again\n");
    310 				for (i = 0; i < num_play; i++)
    311 					free(play[i].name);
    312 				free(play);
    313 				goto blew_it;
    314 			}
    315 }
    316 
    317 /*
    318  *	This routine figures out who goes first
    319  */
    320 static void
    321 init_players()
    322 {
    323 	int i, rl, cur_max;
    324 	bool over = 0;
    325 	int max_pl = 0;
    326 
    327 again:
    328 	putchar('\n');
    329 	for (cur_max = i = 0; i < num_play; i++) {
    330 		printf("%s (%d) rolls %d\n", play[i].name, i+1, rl=roll(2, 6));
    331 		if (rl > cur_max) {
    332 			over = FALSE;
    333 			cur_max = rl;
    334 			max_pl = i;
    335 		}
    336 		else if (rl == cur_max)
    337 			over++;
    338 	}
    339 	if (over) {
    340 		printf("%d people rolled the same thing, so we'll try again\n",
    341 		    over + 1);
    342 		goto again;
    343 	}
    344 	player = max_pl;
    345 	cur_p = &play[max_pl];
    346 	printf("%s (%d) goes first\n", cur_p->name, max_pl + 1);
    347 }
    348 
    349 /*
    350  *	This routine initializes the monopoly structures.
    351  */
    352 static void
    353 init_monops()
    354 {
    355 	MON *mp;
    356 	int i;
    357 
    358 	for (mp = mon; mp < &mon[N_MON]; mp++) {
    359 		mp->name = mp->not_m;
    360 		for (i = 0; i < mp->num_in; i++)
    361 			mp->sq[i] = &board[mp->sqnums[i]];
    362 	}
    363 }
    364