Files
CS3841/05-JurrasicPark/park.c
p-w-rs 0924ea2496 stuff
2022-09-30 15:35:16 -05:00

631 lines
23 KiB
C

// os45park.c - Jurassic Park 10/24/2013
// ***********************************************************************
// ** DISCLAMER ** DISCLAMER ** DISCLAMER ** DISCLAMER ** DISCLAMER **
// ** **
// ** The code given here is the basis for the CS345 projects. **
// ** It comes "as is" and "unwarranted." As such, when you use part **
// ** or all of the code, it becomes "yours" and you are responsible to **
// ** understand any algorithm or method presented. Likewise, any **
// ** errors or problems become your responsibility to fix. **
// ** **
// ** NOTES: **
// ** -Comments beginning with "// ??" may require some implementation. **
// ** -Tab stops are set at every 3 spaces. **
// ** -The function API's in "OS345.h" should not be altered. **
// ** **
// ** DISCLAMER ** DISCLAMER ** DISCLAMER ** DISCLAMER ** DISCLAMER **
// ***********************************************************************
#include <assert.h>
#include <ctype.h>
#include <pthread.h>
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include "park.h"
JPARK myPark;
pthread_mutex_t parkMutex; // mutex park variable access
pthread_mutex_t moveCars;
pthread_mutex_t fillSeat[NUM_CARS]; // (signal) seat ready to fill
pthread_mutex_t seatFilled[NUM_CARS]; // (wait) passenger seated
pthread_mutex_t rideOver[NUM_CARS]; // (signal) ride over
void *jurassicTask(void *args)
{
int i, j, k;
char buf[32];
int c[NUM_CARS];
// initial car locations
for (i = 0; i < NUM_CARS; i++)
{
myPark.cars[i].location = 33 - i;
myPark.cars[i].passengers = 0;
}
// drivers are all asleep
for (i = 0; i < NUM_DRIVERS; i++)
{
myPark.drivers[i] = 0;
}
// initialize other park variables
myPark.numOutsidePark = 0;
// # trying to enter park
myPark.numTicketsAvailable = MAX_TICKETS;
// T=#
myPark.numInPark = 0;
// P=#
myPark.numRidesTaken = 0;
// S=#
myPark.numInTicketLine = 0;
// Ticket line
myPark.numInMuseumLine = 0;
// Museum line
myPark.numInMuseum = 0;
// # in museum
myPark.numInCarLine = 0;
// Ride line
myPark.numInCars = 0;
// # in cars
myPark.numInGiftLine = 0;
// Gift shop line
myPark.numInGiftShop = 0;
// # in gift shop
myPark.numExitedPark = 0;
// # exited park
// create move car signal semaphore
pthread_mutex_init(&moveCars, NULL);
pthread_mutex_lock(&moveCars);
// initialize communication semaphores
for (i = 0; i < NUM_CARS; i++)
{
pthread_mutex_init(&fillSeat[i], NULL);
pthread_mutex_lock(&fillSeat[i]);
pthread_mutex_init(&seatFilled[i], NULL);
pthread_mutex_lock(&seatFilled[i]);
pthread_mutex_init(&rideOver[i], NULL);
pthread_mutex_lock(&rideOver[i]);
}
// start display park task
pthread_t displayTask;
pthread_create(&displayTask, NULL, jurassicDisplayTask, NULL);
// OK, let's get the park going...
pthread_mutex_init(&parkMutex, NULL);
begin = 1;
// start lost visitor task
pthread_t lostTask;
pthread_create(&lostTask, NULL, lostVisitorTask, NULL);
// wait to move cars
do
{
// wait for signal to move cars
ParkDebug("WAIT(moveCars)");
pthread_mutex_lock(&moveCars);
// order car locations
for (i = 0; i < NUM_CARS; i++)
{
c[i] = i;
}
// sort car positions
for (i = 0; i < (NUM_CARS - 1); i++)
{
for (j = i + 1; j < NUM_CARS; j++)
{
if (myPark.cars[c[i]].location < myPark.cars[c[j]].location)
{
k = c[i];
c[i] = c[j];
c[j] = k;
}
}
}
// move each car if possible (or load or unload)
for (i = 0; i < NUM_CARS; i++)
{
// move car (-1=location occupied, 0=moved, 1=no move)
if (makeMove(c[i]))
{
// check if car is loading
if ((myPark.cars[c[i]].location == 33) && (myPark.cars[c[i]].passengers < NUM_SEATS) &&
(myPark.numInCarLine))
{
// need a passenger
sprintf(buf, "SIGNAL(fillSeat[%d])", c[i]);
ParkDebug(buf);
pthread_mutex_unlock(&fillSeat[c[i]]);
// seat open
sprintf(buf, "WAIT(seatFilled[%d])", c[i]);
ParkDebug(buf);
pthread_mutex_unlock(&seatFilled[c[i]]);
// passenger in seat
myPark.cars[c[i]].passengers++;
}
// check if car is unloading
if ((myPark.cars[c[i]].location == 30) && (myPark.cars[c[i]].passengers > 0))
{
// empty each seat until car is empty
myPark.numRidesTaken++;
// if car empty, signal ride over
if (--myPark.cars[c[i]].passengers == 0)
{
sprintf(buf, "SIGNAL(rideOver[%d])", c[i]);
ParkDebug(buf);
pthread_mutex_unlock(&rideOver[c[i]]);
}
}
// sanity check
if ((myPark.cars[0].location == myPark.cars[1].location) ||
(myPark.cars[0].location == myPark.cars[2].location) ||
(myPark.cars[0].location == myPark.cars[3].location) ||
(myPark.cars[1].location == myPark.cars[2].location) ||
(myPark.cars[1].location == myPark.cars[3].location) ||
(myPark.cars[2].location == myPark.cars[3].location))
{
printf("\nProblem:");
for (k = 0; k < NUM_CARS; k++)
printf(" %d", myPark.cars[k].location);
k = getchar();
}
}
}
} while (myPark.numExitedPark < NUM_VISITORS);
// park done
printf("\nJurassic Park is shutting down for the evening!!");
return NULL;
} // end
//***********************************************************************
// Move car in Jurassic Park (if possible)
//
// return -1 if location occupied
// 0 if move ok
// 1 if no move
//
int makeMove(int car)
{
int i, j;
int moved;
switch (j = myPark.cars[car].location)
{
// at cross roads 1
case 7: {
j = (rand() % 2) ? 24 : 8;
break;
}
// at cross roads 2
case 20: {
// take shorter route if no one in line
if (myPark.numInCarLine == 0)
{
j = 28;
}
else
{
j = (rand() % 3) ? 28 : 21;
}
break;
}
// bridge loop
case 23: {
j = 1;
break;
}
// bridge short route
case 27: {
j = 20;
break;
}
// exit car
case 30: {
if (myPark.cars[car].passengers == 0)
{
j++;
}
break;
}
// loading car
case 33: {
// if there is someone in car and noone is in line, proceed
// if ((myPark.cars[car].passengers == NUM_SEATS) ||
// ((myPark.numInCarLine == 0) && myPark.cars[car].passengers))
// if car is full, proceed into park
if (myPark.cars[car].passengers == NUM_SEATS)
{
j = 0;
}
break;
}
// all other moves
default: {
j++;
break;
}
}
// check to see if position is taken
for (i = 0; i < NUM_CARS; i++)
{
if (i != car)
{
if (myPark.cars[i].location == j)
{
return -1;
}
}
}
// return 0 if car moved
moved = (myPark.cars[car].location == j);
// make move
myPark.cars[car].location = j;
return moved;
}
// ***********************************************************************
// ***********************************************************************
// jurassic task
// ***********************************************************************
void *jurassicDisplayTask(void *args)
{
// wait for park to get initialized...
while (!begin)
{
}
printf("Starting jurassicDisplayTask\n");
// display park every second
do
{
JPARK currentPark;
// update every second
sleep(1);
// take snapshot of park
pthread_mutex_lock(&parkMutex);
currentPark = myPark;
pthread_mutex_unlock(&parkMutex);
// draw current park
drawPark(&currentPark);
// signal for cars to move
pthread_mutex_unlock(&moveCars);
} while (myPark.numExitedPark < NUM_VISITORS);
// park done
printf("\nThank you for visiting Jurassic Park!!");
return NULL;
} // end
//***********************************************************************
// Draw Jurassic Park
// 1 2 3 4 5 6 7
// 01234567890123456789012345678901234567890123456789012345678901234567890
// _______________________________________________________ 0
// Entrance / ++++++++++++++++++++++++++++++++++++++++++| 1
// - +o0o-o1o-o2o-o3o-o4o-o5o-o6o +| 2
// ## - /+ / \ +| 3
// / o + o ************ o +| 4
// |******** ##>>33 + 23 *Cntrl Room* 7 +| 5
// |*Ticket* o + o * A=# D1=# * o +| 6
// |*Booth * 32 + | * B=# D2=# * / \ +| 7
// |* T=# * ## o + o * C=# D3=# * o o8o-o9o +| 8
// |* P=## * 31 + 22 * D=# D4=# * 24 \ +| 9
// |* S=# * o + o ************ o o +| 10
// |******** ##<<30 + \ / 10 +| 11
// | o + o21-o20-o27-o26-o25 o +| 12
// | \+ / \ | +| 13
// | +o29-o28 o o +| 14
// | +++++++++++ 19 11 +| 15
// | + o o +| 16
// | ## ## + \ / +| 17
// | ******\ /****\ /******** + o O\ o +| 18
// | * * * + 18 \/|||\___ 12 +| 19
// \ * Gifts * Museum * + o x x o +| 20
// - * # * ## * + \ / +| 21
// ## - * * * + o17-o16-o15-o14-o13 +| 22
// \ ************************ ++++++++++++++++++++++++++++++++| 23
//
char *myTime(char *svtime)
{
time_t cTime; // current time
time(&cTime); // read current time
strcpy(svtime, asctime(localtime(&cTime)));
svtime[strlen(svtime) - 1] = 0; // eliminate nl at end
return svtime;
} // end myTime
#define D1Upper 13
#define D1Left 45
#define D1Lower 18
#define D1Right 53
#define D2Upper 4
#define D2Left 53
#define D2Lower 13
#define D2Right 57
void drawPark(JPARK *park)
{
static int direction1 = D1Left;
static int dy1 = D1Lower;
static int direction2 = D2Left;
static int dy2 = D1Lower - 9;
int i, j;
char svtime[64]; // ascii current time
char driver[] = {'T', 'z', 'A', 'B', 'C', 'D'};
char buf[32];
char pk[25][80];
static int cp[34][3] = {
{2, 29, 0}, {2, 33, 0}, {2, 37, 0}, {2, 41, 0}, // 0-6
{2, 45, 0}, {2, 49, 0}, {2, 53, 0}, {4, 57, 1}, // 7
{8, 59, 0}, {8, 63, 0}, // 8-9
{10, 67, 1}, {14, 67, 1}, {18, 65, 1}, // 10-12
{22, 61, 0}, {22, 57, 0}, {22, 53, 0}, // 13-17
{22, 49, 0}, {22, 45, 0}, {18, 43, 1}, {14, 41, 1}, // 18-19
{12, 37, 0}, {12, 33, 0}, {8, 31, 1}, {4, 31, 1}, // 20-23
{8, 55, 3}, // 24
{12, 49, 0}, {12, 45, 0}, {12, 41, 0}, // 25-27
{14, 33, 0}, {14, 29, 0}, // 28-29
{10, 26, 1}, {8, 26, 1}, {6, 26, 1}, {4, 26, 1}, // 30-33
};
strcpy(&pk[0][0], " ___Jurassic Park_______________________________________");
strcpy(&pk[1][0], " Entrance / ++++++++++++++++++++++++++++++++++++++++++|");
strcpy(&pk[2][0], " - +--------------------------- +|");
strcpy(&pk[3][0], " # - /+ / \\ +|");
strcpy(&pk[4][0], " / | + | ************ | +|");
strcpy(&pk[5][0], " |******** # >>| + | *Cntrl Room* | +|");
strcpy(&pk[6][0], " |*Ticket* | + | * A=# D1=# * | +|");
strcpy(&pk[7][0], " |*Booth * | + | * B=# D2=# * / \\ +|");
strcpy(&pk[8][0], " |* T=# * # | + | * C=# D3=# * / ------- +|");
strcpy(&pk[9][0], " |* P=# * | + | * D=# D4=# * / \\ +|");
strcpy(&pk[10][0], " |* S=# * | + | ************ / | +|");
strcpy(&pk[11][0], " |******** <<| + \\ / | +|");
strcpy(&pk[12][0], " | | + ------------------- | +|");
strcpy(&pk[13][0], " | \\+ / \\ | +|");
strcpy(&pk[14][0], " | +------- | | +|");
strcpy(&pk[15][0], " | +++++++++++ | | +|");
strcpy(&pk[16][0], " | + | | +|");
strcpy(&pk[17][0], " | # # + \\ / +|");
strcpy(&pk[18][0], " | ******\\ /****\\ /******** + | | +|");
strcpy(&pk[19][0], " | * * * + | | +|");
strcpy(&pk[20][0], " \\ * Gifts * Museum * + | | +|");
strcpy(&pk[21][0], " - * * * + \\ / +|");
strcpy(&pk[22][0], " # - * * * + ------------------- +|");
strcpy(&pk[23][0], " \\ ************************ ++++++++++++++++++++++++++++++++|");
strcpy(&pk[24][0], " Exit \\_____________________________________________________________|");
// output time
sprintf(buf, "%s", myTime(svtime));
memcpy(&pk[0][strlen(pk[0]) - strlen(buf)], buf, strlen(buf));
// out number waiting to get into park
sprintf(buf, "%d", park->numOutsidePark);
memcpy(&pk[3][12 - strlen(buf)], buf, strlen(buf));
// T=#, out number of tickets available
sprintf(buf, "%d ", park->numTicketsAvailable);
memcpy(&pk[8][8], buf, strlen(buf));
// P=#, out number in park (not to exceed OSHA requirements)
sprintf(buf, "%d ", park->numInPark);
memcpy(&pk[9][8], buf, strlen(buf));
// S=#, output guests completing ride
sprintf(buf, "%d", park->numRidesTaken);
memcpy(&pk[10][8], buf, strlen(buf));
// out number in ticket line
sprintf(buf, "%d ", park->numInTicketLine);
memcpy(&pk[8][13], buf, strlen(buf));
// out number in gift shop line
sprintf(buf, "%d", park->numInGiftLine);
memcpy(&pk[17][21 - strlen(buf)], buf, strlen(buf));
// out number in museum line
sprintf(buf, "%d", park->numInMuseumLine);
memcpy(&pk[17][28 - strlen(buf)], buf, strlen(buf));
// out number in car line
sprintf(buf, "%d", park->numInCarLine);
memcpy(&pk[5][23 - strlen(buf)], buf, strlen(buf));
// out number in gift shop
sprintf(buf, "%d ", park->numInGiftShop);
memcpy(&pk[21][17], buf, strlen(buf));
// out number in museum
sprintf(buf, "%d ", park->numInMuseum);
memcpy(&pk[21][29], buf, strlen(buf));
// out number exited park
sprintf(buf, "%d", park->numExitedPark);
memcpy(&pk[22][5 - strlen(buf)], buf, strlen(buf));
// cars
for (i = 0; i < NUM_CARS; i++)
{
sprintf(buf, "%d", park->cars[i].passengers);
memcpy(&pk[6 + i][42 - strlen(buf)], buf, strlen(buf));
}
// drivers
for (i = 0; i < NUM_DRIVERS; i++)
{
pk[6 + i][46] = driver[park->drivers[i] + 1];
}
// output cars
for (i = 0; i < NUM_CARS; i++)
{
// draw car
j = park->cars[i].location;
switch (cp[j][2])
{
// horizontal
case 0: {
pk[cp[j][0]][cp[j][1] + 0] = 'o';
pk[cp[j][0]][cp[j][1] + 1] = 'A' + i;
pk[cp[j][0]][cp[j][1] + 2] = 'o';
break;
}
// vertical
case 1: {
pk[cp[j][0] + 0][cp[j][1]] = 'o';
// pk[cp[j][0]+1][cp[j][1]] = 'A'+i;
// if ((park->cars[i].passengers > 0) && (park->cars[i].passengers < NUM_SEATS))
if ((park->cars[i].passengers > 0) && ((j == 30) || (j == 33)))
{
pk[cp[j][0] + 1][cp[j][1]] = '0' + park->cars[i].passengers;
}
else
pk[cp[j][0] + 1][cp[j][1]] = 'A' + i;
pk[cp[j][0] + 2][cp[j][1]] = 'o';
break;
}
case 2: {
pk[cp[j][0] + 0][cp[j][1] + 0] = 'o';
pk[cp[j][0] + 1][cp[j][1] + 1] = 'A' + i;
pk[cp[j][0] + 2][cp[j][1] + 2] = 'o';
break;
}
case 3: {
pk[cp[j][0] + 0][cp[j][1] - 0] = 'o';
pk[cp[j][0] + 1][cp[j][1] - 1] = 'A' + i;
pk[cp[j][0] + 2][cp[j][1] - 2] = 'o';
break;
}
}
}
// move dinosaur #1
dy1 = dy1 + (rand() % 3) - 1;
if (dy1 < D1Upper)
dy1 = D1Upper;
if (dy1 > D1Lower)
dy1 = D1Lower;
if (direction1 > 0)
{
memcpy(&pk[dy1 + 0][direction1 + 4], "... /O", 7);
memcpy(&pk[dy1 + 1][direction1 + 0], "___/|||\\/", 9);
memcpy(&pk[dy1 + 2][direction1 + 3], "x x", 5);
if (++direction1 > D1Right)
direction1 = -direction1;
}
else
{
if ((rand() % 3) == 1)
{
memcpy(&pk[dy1 + 0][-direction1 + 4], "...", 3);
memcpy(&pk[dy1 + 1][-direction1 + 1], "__/|||\\___", 10);
memcpy(&pk[dy1 + 2][-direction1 + 0], "O x x", 8);
}
else
{
memcpy(&pk[dy1 + 0][-direction1 + 0], "O\\ ...", 7);
memcpy(&pk[dy1 + 1][-direction1 + 2], "\\/|||\\___", 9);
memcpy(&pk[dy1 + 2][-direction1 + 3], "x x", 5);
}
if (++direction1 > -D1Left)
direction1 = -direction1;
}
// move dinosaur #2
dy2 = dy2 + (rand() % 3) - 1;
if (dy2 < D2Upper)
dy2 = D2Upper;
if (dy2 > D2Lower)
dy2 = D2Lower;
dy2 = (dy2 + 9) >= dy1 ? dy1 - 9 : dy2;
if (direction2 > 0)
{
memcpy(&pk[dy2 + 0][direction2 + 7], "_", 1);
memcpy(&pk[dy2 + 1][direction2 + 6], "/o\\", 3);
memcpy(&pk[dy2 + 2][direction2 + 4], "</ _<", 5);
memcpy(&pk[dy2 + 3][direction2 + 3], "</ /", 4);
memcpy(&pk[dy2 + 4][direction2 + 2], "</ ==x", 6);
memcpy(&pk[dy2 + 5][direction2 + 3], "/ \\", 4);
memcpy(&pk[dy2 + 6][direction2 + 2], "//)__)", 6);
memcpy(&pk[dy2 + 7][direction2 + 0], "<<< \\_ \\_", 9);
if (++direction2 > D2Right)
direction2 = -direction2;
}
else
{
memcpy(&pk[dy2 + 0][-direction2 + 1], "_", 1);
memcpy(&pk[dy2 + 1][-direction2 + 0], "/o\\", 3);
memcpy(&pk[dy2 + 2][-direction2 + 0], ">_ \\>", 5);
memcpy(&pk[dy2 + 3][-direction2 + 2], "\\ \\>", 4);
memcpy(&pk[dy2 + 4][-direction2 + 1], "x== \\>", 6);
memcpy(&pk[dy2 + 5][-direction2 + 2], "/ \\", 4);
memcpy(&pk[dy2 + 6][-direction2 + 1], "(__(\\\\", 6);
memcpy(&pk[dy2 + 7][-direction2 + 0], "_/ _/ >>>", 9);
if (++direction2 > -D2Left)
direction2 = -direction2;
}
// draw park
system("clear");
printf("\n");
for (i = 0; i < 25; i++)
printf("\n%s", &pk[i][0]);
printf("\n");
// driver in only one place at a time
for (i = 0; i < (NUM_DRIVERS - 1); i++)
{
if (park->drivers[i] != 0)
{
for (j = i + 1; j < NUM_DRIVERS; j++)
{
assert("Driver Error" && (park->drivers[i] != park->drivers[j]));
}
}
}
return;
} // end drawPark
// ***********************************************************************
// ***********************************************************************
// lostVisitor task
// ***********************************************************************
void *lostVisitorTask(void *args)
{
int inPark;
while (myPark.numExitedPark < NUM_VISITORS)
{
// number in park
pthread_mutex_lock(&parkMutex);
inPark = myPark.numInTicketLine + myPark.numInMuseumLine + myPark.numInMuseum + myPark.numInCarLine +
myPark.numInCars + myPark.numInGiftLine + myPark.numInGiftShop;
if (inPark != myPark.numInPark)
{
printf("\nSomeone is lost!!!");
printf("\nThere are %d visitors in the park,", myPark.numInPark);
printf("\nbut I can only find %d of them!\n", inPark);
printf("\n numInPark=%d", myPark.numInPark);
printf("\n inPark=%d", inPark);
printf("\nnumInTicketLine=%d", myPark.numInTicketLine);
printf("\nnumInMuseumLine=%d", myPark.numInMuseumLine);
printf("\n numInMuseum=%d", myPark.numInMuseum);
printf("\n numInCarLine=%d", myPark.numInCarLine);
printf("\n numInCars=%d", myPark.numInCars);
printf("\n numInGiftLine=%d", myPark.numInGiftLine);
printf("\n numInGiftShop=%d", myPark.numInGiftShop);
printf("\n");
assert("Too few in Park!" && (inPark == myPark.numInPark));
}
pthread_mutex_unlock(&parkMutex);
}
return NULL;
} // end lostVisitorTask