home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
games
/
volume7
/
hotel
/
part01
/
hotel.c
< prev
next >
Wrap
C/C++ Source or Header
|
1989-07-13
|
18KB
|
814 lines
/*
* This program (called "Hotel") is copyright 1989 to Scott R. Turner,
* in both source code and executable form. Permission is given to
* copy both the source code and the executable under the following
* conditions:
*
* COPYING POLICIES
*
* 1. You may copy and distribute verbatim copies of Hotel code as you
* receive it, in any medium, provided that you conspicuously and
* appropriately publish on each file a valid copyright notice such as
* "Copyright (C) 1989 Scott R. Turner", and keep intact the copyright
* and license notices on all files. You may charge a distribution fee for the
* physical act of transferring a copy, but that fee may not exceed
* your actual costs in creating and delivering the copy.
*
* 2. You may modify your copy or copies of Hotel or any portion of it,
* and copy and distribute such modifications under the terms of
* Paragraph 1 above, provided that you also do the following:
*
* a) cause the modified files to carry prominent notices stating
* who last changed such files and the date of any change; and
*
* b) cause the whole of any work that you distribute or publish,
* that in whole or in part contains or is a derivative of Hotel
* or any part thereof, to be licensed at no charge to all third
* parties on terms identical to those contained in this License
* Agreement (except that you may choose to grant more extensive
* warranty protection to third parties, at your option).
*
* 3. You may not copy, sublicense, distribute or transfer Hotel
* except as expressly provided under this License Agreement. Any attempt
* otherwise to copy, sublicense, distribute or transfer Hotel is void and
* your rights to use Hotel under this License agreement shall be
* automatically terminated. However, parties who have received computer
* software programs from you with this License Agreement will not have
* their licenses terminated so long as such parties remain in full compliance.
*
* 4. Under no circumstances may you charge for copies of Hotel, for copies
* of any program containing code from Hotel in whole or in part, or for
* any software package or collection of programs or code that contains Hotel
* in whole or part.
*
*/
/*
* hotel.c
* Scott R. Turner
* 9/7/88
*
* The main program and declarations for Hotel.
*
*/
#include "defs.h"
#include <signal.h>
#ifdef TURBO
#include <stdlib.h>
#include <time.h>
#endif
/* Hotels Array */
hotel hotels[MAXHOTELS+1];
/* Players Array */
player players[MAXPLAYERS+1];
/* Board */
int board[MAXBOARD+1][MAXBOARD+1];
/* Run-time variables */
int numplayers, numhotels, boardsize, numshares, numtiles, startcash;
int turn, maxbuy, debug, pnum;
/* Externals */
extern int share_cost();
extern void majority_bonus();
extern void print_board();
extern int new_hotel();
extern void anykey_help();
void endgame()
{
nocrmode();
echo();
endwin();
printf("\n");
exit(1);
};
/*
* Quit - a little subroutine to handle the quit key.
*
*/
void quit()
{
char ans;
printw("\nAre you sure you want to quit? (Y/N) ");
refresh();
ans = getch();
if (ans == 'Y' || ans == 'y') {
echo();
nocrmode();
endwin();
exit(1);
};
};
main ()
{
int i,j,k,x,y,hotelchoice,played;
int purchases[MAXHOTELS];
extern long time();
#ifdef UNIX
extern void srandom();
#endif
extern void human_play();
extern int human_new();
extern int human_save();
extern void human_buy();
extern void human_liquidate();
extern void comp_play();
extern int comp_new();
extern int comp_save();
extern void get_maj_strategy();
extern void comp_liquidate();
/* Debug flag. */
debug = 0;
/* Initialize random number generator. */
#ifdef UNIX
srandom((int) time(0));
#else
randomize();
#endif
/*
Curses Initialization.
*/
initscr();
#ifdef UNIX
nonl();
#endif UNIX
crmode();
/* Initialize game. */
init();
noecho();
signal(SIGINT,endgame);
#ifdef UNIX
signal(SIGQUIT,endgame);
#endif
/* Game Cycle:
For each player in the game, execute their "play" and "buy"
behaviors.
*/
turn = 1;
while(!game_over()) {
for (i=1;i<=numplayers;i++) {
/*
* If a player has a tile that is permanently unplayable because
* it would cause the merger of two safe hotel chains, then he
* is allowed to discard that tile and draw a new one. We do this
* automatically for each player at the beginning of each round.
*
*/
for(k=1;k<=boardsize;k++)
for(j=1;j<=boardsize;j++)
if (unplayable(k,j)) {
if (board[k][j] < 0 && board[k][j] != UNPLAYABLE)
newtile(-board[k][j]);
board[k][j] = UNPLAYABLE;
};
pnum = i;
move((boardsize+5),0);
clrtobot();
played = 0;
/*
* The "play" behavior returns (in &x and &y) the location of
* the tile the player would like to play this round.
*
*/
if (players[i].strategy) {
/* A computer player. */
comp_play(i,&x,&y);
printw("%s played (%d,%d).\n",players[i].name,x,y);
} else {
/* Human player. */
human_play(i,&x,&y);
};
/*
* If the move is legal and on the board and owned by the player,
* then make the move.
*
*/
if (x > 0 && y > 0 && x <= boardsize && y <= boardsize && legal_play(x,y) &&
board[x][y] == -i) {
/* Place the tile on the board. */
board[x][y] = UNUSED;
/* Check to see if the play merged two hotel chains, or added to a hotel. */
hotel_merge(x,y,i);
/* Check to see if the play created a new hotel chain. */
if (new_hotel(x,y)) {
/* It did, so let him choose the hotel chain. */
if (players[i].strategy) {
hotelchoice = comp_new(i,x,y);
} else {
hotelchoice = human_new(i,x,y);
};
make_new_hotel(hotelchoice,x,y,i);
};
played = 1;
};
/*
* The player is done placing his tile. Now execute his buy
* behavior, which returns (in purchases) the stocks he chooses
* to buy.
*
*/
if (players[i].strategy) {
get_maj_strategy(i,purchases);
print_board(human_player);
refresh();
any_key();
} else {
human_buy(i,purchases);
};
/*
* Actually make the purchases, checking to see that the
* the shares are available, the hotel exists, and he has the money.
*
*/
for (j=1;j<=numhotels;j++)
if (purchases[j] != 0 && hotels[j].size > 0 &&
purchases[j] <= hotels[j].shares &&
purchases[j]*share_cost(j) <= players[i].cash) {
hotels[j].shares -= purchases[j];
players[i].shares[j] += purchases[j];
players[i].cash -= purchases[j]*share_cost(j);
};
/* Give the player a new tile to replace the one just played. */
if (played==1) newtile(i);
};
turn++;
};
standings();
endwin();
exit(1);
};
/*
* game_over checks to see whether or not the end conditions
* have become satisfied.
*
*/
game_over()
{
int i,x,y;
int done = 1, any = 0, available = 0;
/* Game is over if all the hotels on the board are safe,
* or any chain is > 42% of the board, or if no one has
* a legal play.
*/
/*
* No legal plays...?
*
*/
for(x=1;x<=boardsize;x++)
for(y=1;y<=boardsize;y++)
if (board[x][y] <= 0 && board[x][y] != UNPLAYABLE &&
!unplayable(x,y)) available++;
if (!available) return(1);
/*
* Big hotel?
*
*/
for(i=1;i<=numhotels;i++)
if(hotels[i].size > (.42 * boardsize * boardsize)) return(1);
/*
* Just started?
*
*/
for(i=1;i<=numhotels;i++)
if(hotels[i].size > 0) {
any = 1;
break;
};
if (!any) return(0);
for(i=1;i<=numhotels;i++)
if(hotels[i].size > 0 && !safe(i)) {
done = 0;
break;
};
return(done);
};
/*
* make_new_hotel makes a new hotel (hotel #n) around x,y.
*
*/
make_new_hotel(n,x,y,pl)
int n,x,y,pl;
{
int change,i,j;
board[x][y] = n;
hotels[n].size++;
spread_hotel(n,x,y);
/* Give the player one free share, if available. */
if (hotels[n].shares > 0) {
hotels[n].shares -= 1;
players[pl].shares[n] += 1;
};
};
/*
* hotel_merge checks to see if the newly placed tile at (x,y) merges two
* hotel chains.
*
*/
hotel_merge(x,y,p)
int x,y,p;
{
int adj[MAXHOTELS+1],shares[MAXHOTELS+1];
int i, j, k, count, max, dup, winner, hot, maxhot;
int hold, sell, trade, numtraded, cp;
int max1, max2, num1, num2, first, second;
/*
* Start by making a list of all the hotels that this
* new play is adjacent to.
*
*/
for(i=1;i<=numhotels;i++) {
adj[i] = 0;
shares[i] = 0;
};
count = 0;
max = 0;
dup = 0;
for(i= -1;i<2;i++)
for(j= -1;j<2;j++) {
hot = board[x+i][y+j];
if ((i*j == 0) && (i != 0 || j != 0) &&
((x+i) > 0) && ((y+j) > 0) &&
((x+i) <= boardsize) && ((y+j) <= boardsize) &&
(hot > 0) && (hot != UNUSED)) {
if (!adj[hot]) count++;
adj[hot] = hotels[hot].size;
shares[hot] = share_cost(hot);
};
};
for(i=1;i<=numhotels;i++)
if (adj[i] == max) {
dup++;
} else if (adj[i] > max) {
dup = 0;
max = adj[i];
maxhot = i;
};
/* If count = 0, we weren't adjacent to anything. */
if (count == 0) return(0);
/* If count = 1, we were adjacent to a single hotel, so spread that hotel. */
if (count == 1) {
spread_hotel(maxhot,x,y);
return(1);
};
/* If count > 1, then we are merging two or more chains. */
/* If dup > 0, then we have two chains of the same size,
* so the player gets to choose which to dump. If dup = 0,
* then there is a clear winner, and we find it.
*/
if (dup > 0)
if (players[p].strategy) {
maxhot = comp_save(p,max,adj);
} else {
maxhot = human_save(p,max,adj);
};
/*
* Hand out the majority bonuses for all the sunken hotels.
*
*/
for(i=1;i<=numhotels;i++)
if(i != maxhot && adj[i] != 0) do_maj_bonuses(i);
/*
* After the other chains have been sunk, we need to give people
* a chance to liquidate, starting with the current player and
* continuing in play order.
*
*/
for(j=1;j<=numhotels;j++)
if(adj[j] && j != maxhot)
for(i=0;i<numplayers;i++){
cp = ((p+i)%numplayers) + 1;
if (players[cp].shares[j] > 0) {
if (players[cp].strategy) {
comp_liquidate(cp,maxhot,j,&sell,&trade);
} else {
human_liquidate(cp,maxhot,j,&sell,&trade);
};
/* Sell as many as he asked. */
if (sell <= players[cp].shares[j] && sell > 0) {
players[cp].cash += sell*share_cost(j);
players[cp].shares[j] -= sell;
hotels[j].shares += sell;
};
/* Trade as many as possible. */
if (trade <= players[cp].shares[j] && trade > 0) {
numtraded = (hotels[maxhot].shares <= (int) (trade / 2)) ? (hotels[maxhot].shares * 2) :
trade;
players[cp].shares[j] -= numtraded;
hotels[j].shares += numtraded;
players[cp].shares[maxhot] += round(numtraded / 2);
hotels[maxhot].shares -= round(numtraded / 2);
};
/* Everything left gets held. */
};
};
/*
* Merge all the chains other than the winner into the winner.
*
*/
for(i=1;i<=numhotels;i++)
if(i != maxhot && adj[i] != 0)
for(x=1;x<=boardsize;x++)
for(y=1;y<=boardsize;y++)
if (board[x][y] == i) {
board[x][y] = maxhot;
hotels[i].size--;
hotels[maxhot].size++;
};
/*
* Finally, spread the winning hotel, in case the new tile also
* touched some unused tiles.
*
*/
spread_hotel(maxhot,x,y);
};
/*
* Spread_hotel iteratively changes unused tiles into the hotel
* they are next to.
*
*/
spread_hotel(n,x,y)
int n,x,y;
{
int i,j,change;
change = 1;
while(change){
change = 0;
for(x=1;x<=boardsize;x++)
for(y=1;y<=boardsize;y++)
if(board[x][y] == n)
for(i= -1;i<2;i++)
for(j= -1;j<2;j++)
if((i*j == 0) && (i != 0 || j != 0) && (x+i) > 0 && (x+i) <= boardsize &&
(y+j) > 0 && (y+j) <= boardsize &&
board[x+i][y+j] == UNUSED) {
board[x+i][y+j] = n;
hotels[n].size++;
change = 1;
};
};
};
/*
* safe returns true if a hotel is safe, i.e., > 10
*
*/
safe(hot)
int hot;
{
if (hotels[hot].size > 10) return(1);
else return(0);
};
/*
* legal_play returns false if the play would create a (numhotels + 1) hotel
*
*/
legal_play(x,y)
int x,y;
{
int i,j,new;
/* Is the new tile adjacent to an existing hotel? */
new = 1;
for(i= -1;i<2;i++)
for(j= -1;j<2;j++)
if ( i*j == 0 && (i != 0 || j != 0) &&
((x+i) > 0) && ((y+j) > 0) &&
((x+i) <= boardsize) && ((y+j) <= boardsize) &&
(board[x+i][y+j] > 0) && (board[x+i][y+j] < UNUSED)) {
new = 0;
break;
};
if (new == 0) return(1);
/* Is there an UNUSED adjacent? */
new = 0;
for(i= -1;i<2;i++)
for(j= -1;j<2;j++)
if ( i*j == 0 && (i != 0 || j != 0) &&
((x+i) > 0) && ((y+j) > 0) &&
((x+i) <= boardsize) && ((y+j) <= boardsize) &&
(board[x+i][y+j] == UNUSED)) {
new = 1;
goto done;
};
done:
if (new == 0) return(1);
/* Is there an available hotel? */
new = 0;
for(i=1;i<=numhotels;i++)
if(hotels[i].size == 0) {
new = 1;
break;
};
return(new);
};
/*
* unplayable returns true if the play would merge two "safe" hotels.
*
*/
unplayable(x,y)
int x,y;
{
int i,j,count,adj[MAXHOTELS+1];
for(i=1;i<=numhotels;i++)
adj[i] = 0;
for(i= -1;i<2;i++)
for(j= -1;j<2;j++)
if (i*j == 0 && (i != 0 || j != 0) &&
((x+i) > 0) && ((y+j) > 0) &&
((x+i) <= boardsize) && ((y+j) <= boardsize) &&
(board[x+i][y+j] != UNUSED) &&
(board[x+i][y+j] > 0) &&
safe(board[x+i][y+j]))
adj[board[x+i][y+j]] = 1;
count = 0;
for(i=1;i<=numhotels;i++)
if(adj[i]) count++;
if (count > 1 && debug) {
printw("(%d, %d): ",x,y);
for(i=1;i<=numhotels;i++)
if(adj[i]) printw("%c ",'A'+i-1);
printw("%d\n",count);
refresh();
any_key();
};
if (count > 1) return(1);
else return(0);
};
/*
* standings calculates and prints the value of everyone at the endgame.
*
*/
standings()
{
int i,j,order[MAXPLAYERS+1],tmp;
clear();
printw("The game is over!.\n\n");
for(i=1;i<=numhotels;i++)
if(hotels[i].size > 0) do_maj_bonuses(i);
for(i=1;i<=numplayers;i++)
for(j=1;j<=numhotels;j++)
if (hotels[j].size > 0) players[i].cash += players[i].shares[j] * share_cost(j);
/* Sort */
for(i=1;i<=numplayers;i++) order[i] = i;
for(j=1;j<=numplayers;j++)
for(i=1;i<=(numplayers-1);i++)
if (players[order[i]].cash < players[order[i+1]].cash) {
tmp = order[i];
order[i] = order[i+1];
order[i+1] = tmp;
};
clear();
printw("Here are the final standings:\n");
for(i=1;i<=numplayers;i++)
printw(" (%d) %s: $%ld\n",i,players[order[i]].name,
players[order[i]].cash);
refresh();
any_key();
};
any_key()
{
char ans;
int y,x;
clrtoeol();
printw("--- Hit any Key to Continue ---");
getyx(stdscr,y,x);
refresh();
topofanykey:
ans = getch();
if (islower(ans)) ans = toupper(ans);
/*
* Removed in production version...
*
if (ans == 'D') {
if (!debug) debug = 1;
else debug = 0;
goto topofanykey;
};
*
*/
if (ans == REFRESHKEY) {
wrefresh(curscr);
goto topofanykey;
};
if (ans == HELPKEY) {
anykey_help();
goto topofanykey;
};
if (ans == QUITKEY) {
quit();
};
move(y,0);
clrtoeol();
};
do_maj_bonuses(i)
int i;
{
int j,k,max1,num1,max2,num2,first,second;
max1 = 0;
num1 = 0;
max2 = 0;
num2 = 0;
for(j=1;j<=numplayers;j++) {
if (players[j].shares[i] > max1) {
max2 = max1;
num2 = num1;
max1 = players[j].shares[i];
num1 = 1;
} else if (players[j].shares[i] == max1) {
num1++;
} else if (players[j].shares[i] > max2) {
max2 = players[j].shares[i];
num2 = 1;
} else if (players[j].shares[i] == max2) {
num2++;
};
};
majority_bonus(i,&first,&second);
if (max2 == 0 || num1 > 1) {
/*
* The top dogs split both.
*
*/
for(k=1;k<=numplayers;k++)
if (players[k].shares[i] == max1) {
if (players[k].strategy == 0) {
printw("%s get $%d Majority Bonus for %s\n",
players[k].name, round((first + second) / num1), hotels[i].name);
} else {
printw("%s gets $%d Majority Bonus for %s\n",
players[k].name, round((first + second) / num1), hotels[i].name);
};
players[k].cash += round((first + second) / num1);
};
} else
for (k=1;k<=numplayers;k++)
if (players[k].shares[i] == max1) {
if (players[k].strategy == 0) {
printw("%s get %d Majority Bonus (First) for %s\n",
players[k].name, first, hotels[i].name);
} else {
printw("%s gets %d Majority Bonus (First) for %s\n",
players[k].name, first, hotels[i].name);
};
players[k].cash += round(first);
} else if (players[k].shares[i] == max2) {
if (players[k].strategy == 0) {
printw("%s get %d Majority Bonus (Second) for %s\n",
players[k].name, round(second/num2), hotels[i].name);
} else {
printw("%s gets %d Majority Bonus (Second) for %s\n",
players[k].name, round(second/num2), hotels[i].name);
};
players[k].cash += round(second/num2);
};
refresh();
any_key();
};