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