/* Manufacturing Simulation Program version 1.09, last updated April 11, 1999. */ /* C compilable. */ /* Copyright 1999 by Rick Wagner, all rights reserved. */ #include #include #include /* For tolower() */ void about() { puts("Manufacturing Simulation Program version 1.09, last updated April 11, 1999"); puts("C compilable."); puts("Copyright 1999 by Rick Wagner, all rights reserved."); puts(""); } /* Part type struct */ typedef struct { char sName[30]; /* Most entities here have names. */ char sDrawing[10]; /* Parts usually have drawings that control their config. */ int iType; } PartType; /* Part struct */ typedef struct { PartType* t; /* Physical part: an instantiation of a part design. */ int iSerialNumber; float sfWorkTime; float sfWaitTime; } Part; /* Process struct */ typedef struct { char sName[30]; float sfDuration; int iNumInParts; PartType ptIn[10]; /* Process uses part types. Machine uses part. */ int iGotInPart[10]; int iNumOutParts; PartType ptOut[10]; int iGotOutPart[10]; } Process; /* Worker struct */ typedef struct { char sSkillName[30]; /* Workers are nameless in this version. */ float sfTimeWorked; } Worker; /* Workstation struct */ typedef struct { char sName[30]; int iType; /* Workstation type is 2 */ int iNumWorkers; Worker w[10]; int iNumProcesses; Process pr[10]; Part* pOut; /* Output part pointer */ int iNumPrev; /* Workstations have arrays of previous and */ int iPrevType[10]; /* next machines: networks can be created. */ void* prev[10]; int iNumNext; int iNextType[10]; void* next[10]; } Workstation; /* Buffer struct */ typedef struct { char sName[30]; int iType; /* Buffer type is 1 */ int iNumInBuffer; Part* p[100]; int iNumPrev; int iPrevType[10]; void* prev[10]; int iNumNext; int iNextType[10]; void* next[10]; } Buffer; /* Source struct */ typedef struct { char sName[30]; int iType; /* Source type is 0 */ Part* pSupplied[100]; int iNumPartsSupplied; int iNumNext; int iNextType[10]; void* next[10]; } Source; /* Sink struct */ typedef struct { char sName[30]; int iType; /* Sink type is 3 */ Part* pConsumed[100]; int iNumPartsRequested; int iNumPartsConsumed; int iNumPrev; int iPrevType[10]; void* prev[10]; } Sink; /* Factory struct */ typedef struct { char sName[30]; int iNumPartTypes; PartType pt[10]; int PartCount[10]; Part* p[10]; int iNumProcesses; Process* pr[10]; int iNumSources; Source* src[10]; int iNumBuffers; Buffer* b[10]; int iNumWorkstations; Workstation* ws[10]; int iNumSinks; Sink* snk[10]; } Factory; /* Function prototypes */ void about(); void buildFactory(Factory* fWidgetFactory); void menu(Factory* fWidgetFactory); void requestProduct(Factory* fWidgetFactory, int iNumProdReq, PartType pt); void requestPart(Factory* fWidgetFactory, void* t, int iThingType, PartType pt); void sendPart(Factory* f, Part* p, void* t, int iThingType, PartType pt); void doProcesses(Factory* f, Workstation* ws); void main() { int i = 0; /* Loop index */ PartType ptA; /* Three types of parts in this simulation. */ PartType ptB; PartType ptC; Part pA[100]; /* Arrays for the physical parts. */ Part pB[100]; Part pC[100]; Process prFW; /* Four processes in this simulation. */ Process prFG; Process prAW; Process prPW; Source src1; /* The parts source */ Buffer b1; Workstation wsAssembler; /* Widget assembly workstation */ Buffer b2; Workstation wsPolisher; /* Widget polishing workstation */ Buffer b3; Sink snk1; /* Great attractor for widgets */ Factory fWidgetFactory; /* No executable statements above this point for C compiler */ about(); /* Tell about the program */ /* Define the part types */ strcpy(ptA.sName, "Wicket"); strcpy(ptB.sName, "Gadget"); strcpy(ptC.sName, "Widget"); ptA.iType = 0; ptB.iType = 1; ptC.iType = 2; /* Define some parts */ for (i = 0; i < 100; i++) { pA[i].t = &ptA; pB[i].t = &ptB; pC[i].t = &ptC; } fWidgetFactory.iNumPartTypes = 3; for (i = 0; i < fWidgetFactory.iNumPartTypes; i++) { fWidgetFactory.PartCount[i] = 100; } /* Define the widget factory */ strcpy(fWidgetFactory.sName, "Widget Factory"); fWidgetFactory.pt[0] = ptA; fWidgetFactory.pt[1] = ptB; fWidgetFactory.pt[2] = ptC; fWidgetFactory.p[0] = pA; /* Array of 100 A parts */ fWidgetFactory.p[1] = pB; /* Array of 100 B parts */ fWidgetFactory.p[2] = pC; /* Array of 100 C parts */ fWidgetFactory.iNumProcesses = 4; fWidgetFactory.pr[0] = &prFW; fWidgetFactory.pr[1] = &prFG; fWidgetFactory.pr[2] = &prAW; fWidgetFactory.pr[3] = &prPW; fWidgetFactory.iNumSources = 1; fWidgetFactory.src[0] = &src1; fWidgetFactory.iNumBuffers = 3; fWidgetFactory.b[0] = &b1; fWidgetFactory.b[1] = &b2; fWidgetFactory.b[2] = &b3; fWidgetFactory.iNumWorkstations = 2; fWidgetFactory.ws[0] = &wsAssembler; fWidgetFactory.ws[1] = &wsPolisher; fWidgetFactory.iNumSinks = 1; fWidgetFactory.snk[0] = &snk1; /* Build the factory */ buildFactory(&fWidgetFactory); /* Text-based user interface: */ menu(&fWidgetFactory); } /* End of main() */ void buildFactory(Factory* fWidgetFactory) { int i = 0; /* Construct the processes */ strcpy(fWidgetFactory->pr[0]->sName, "Fetch Wicket"); fWidgetFactory->pr[0]->sfDuration = 10; fWidgetFactory->pr[0]->iNumInParts = 1; for (i = 0; i < fWidgetFactory->pr[0]->iNumInParts; i++) { fWidgetFactory->pr[0]->iGotInPart[i] = 0; } fWidgetFactory->pr[0]->ptIn[0] = fWidgetFactory->pt[0]; fWidgetFactory->pr[0]->iNumOutParts = 1; for (i = 0; i < fWidgetFactory->pr[0]->iNumOutParts; i++) { fWidgetFactory->pr[0]->iGotOutPart[i] = 0; } fWidgetFactory->pr[0]->ptOut[0] = fWidgetFactory->pt[0]; strcpy(fWidgetFactory->pr[1]->sName, "Fetch Gadget"); fWidgetFactory->pr[1]->sfDuration = 15; fWidgetFactory->pr[1]->iNumInParts = 1; for (i = 0; i < fWidgetFactory->pr[1]->iNumInParts; i++) { fWidgetFactory->pr[1]->iGotInPart[i] = 0; } fWidgetFactory->pr[1]->ptIn[0] = fWidgetFactory->pt[1]; fWidgetFactory->pr[1]->iNumOutParts = 1; for (i = 0; i < fWidgetFactory->pr[1]->iNumOutParts; i++) { fWidgetFactory->pr[1]->iGotOutPart[i] = 0; } fWidgetFactory->pr[1]->ptOut[0] = fWidgetFactory->pt[1]; strcpy(fWidgetFactory->pr[2]->sName, "Assemble Widget"); fWidgetFactory->pr[2]->sfDuration = 30; fWidgetFactory->pr[2]->iNumInParts = 0; /* diag. (2) */ for (i = 0; i < fWidgetFactory->pr[2]->iNumInParts; i++) { fWidgetFactory->pr[2]->iGotInPart[i] = 0; } fWidgetFactory->pr[2]->ptIn[0] = fWidgetFactory->pt[0]; fWidgetFactory->pr[2]->ptIn[1] = fWidgetFactory->pt[1]; fWidgetFactory->pr[2]->iNumOutParts = 1; for (i = 0; i < fWidgetFactory->pr[2]->iNumOutParts; i++) { fWidgetFactory->pr[2]->iGotOutPart[i] = 0; } fWidgetFactory->pr[2]->ptOut[0] = fWidgetFactory->pt[2]; strcpy(fWidgetFactory->pr[3]->sName, "Polish Widget"); fWidgetFactory->pr[3]->sfDuration = 40; fWidgetFactory->pr[3]->iNumInParts = 1; for (i = 0; i < fWidgetFactory->pr[3]->iNumInParts; i++) { fWidgetFactory->pr[3]->iGotInPart[i] = 0; } fWidgetFactory->pr[3]->ptIn[0] = fWidgetFactory->pt[2]; fWidgetFactory->pr[3]->iNumOutParts = 1; for (i = 0; i < fWidgetFactory->pr[3]->iNumOutParts; i++) { fWidgetFactory->pr[3]->iGotOutPart[i] = 0; } fWidgetFactory->pr[3]->ptOut[0] = fWidgetFactory->pt[2]; /* Construct the source */ strcpy(fWidgetFactory->src[0]->sName, "Source"); fWidgetFactory->src[0]->iType = 0; fWidgetFactory->src[0]->iNumPartsSupplied = 0; fWidgetFactory->src[0]->iNumNext = 1; fWidgetFactory->src[0]->iNextType[0] = 1; /* src1's next is a buffer */ fWidgetFactory->src[0]->next[0] = fWidgetFactory->b[0]; /* Construct the source buffer */ strcpy(fWidgetFactory->b[0]->sName, "Source buffer"); fWidgetFactory->b[0]->iType = 1; fWidgetFactory->b[0]->iNumInBuffer = 0; fWidgetFactory->b[0]->iNumPrev = 1; fWidgetFactory->b[0]->iPrevType[0] = 0; /* b1's previous is a source */ fWidgetFactory->b[0]->prev[0] = fWidgetFactory->src[0]; fWidgetFactory->b[0]->iNumNext = 1; fWidgetFactory->b[0]->iNextType[0] = 2; /* b1's next is a workstation */ fWidgetFactory->b[0]->next[0] = fWidgetFactory->ws[0]; /* Construct the assembly machine */ strcpy(fWidgetFactory->ws[0]->sName, "Assembly Machine"); fWidgetFactory->ws[0]->iType = 2; fWidgetFactory->ws[0]->iNumWorkers = 0; fWidgetFactory->ws[0]->iNumProcesses = 3; fWidgetFactory->ws[0]->pr[0] = *fWidgetFactory->pr[0]; fWidgetFactory->ws[0]->pr[1] = *fWidgetFactory->pr[1]; fWidgetFactory->ws[0]->pr[2] = *fWidgetFactory->pr[2]; fWidgetFactory->ws[0]->pOut = 0; fWidgetFactory->ws[0]->iNumPrev = 1; fWidgetFactory->ws[0]->iPrevType[0] = 1; /* Buffer */ fWidgetFactory->ws[0]->prev[0] = fWidgetFactory->b[0]; fWidgetFactory->ws[0]->iNumNext = 1; fWidgetFactory->ws[0]->iNextType[0] = 1; /* Buffer */ fWidgetFactory->ws[0]->next[0] = fWidgetFactory->b[1]; /* Construct the assembly machine buffer */ strcpy(fWidgetFactory->b[1]->sName, "Assembler buffer"); fWidgetFactory->b[1]->iType = 1; fWidgetFactory->b[1]->iNumInBuffer = 0; fWidgetFactory->b[1]->iNumPrev = 1; fWidgetFactory->b[1]->iPrevType[0] = 2; /* b2's previous is a workstation */ fWidgetFactory->b[1]->prev[0] = fWidgetFactory->ws[0]; fWidgetFactory->b[1]->iNumNext = 1; fWidgetFactory->b[1]->iNextType[0] = 2; /* b2's next is a workstation */ fWidgetFactory->b[1]->next[0] = fWidgetFactory->ws[1]; /* Construct the polishing machine */ strcpy(fWidgetFactory->ws[1]->sName, "Polishing Machine"); fWidgetFactory->ws[1]->iType = 2; fWidgetFactory->ws[1]->iNumWorkers = 0; fWidgetFactory->ws[1]->iNumProcesses = 1; fWidgetFactory->ws[1]->pr[0] = *fWidgetFactory->pr[3]; fWidgetFactory->ws[1]->iNumPrev = 1; fWidgetFactory->ws[1]->iPrevType[0] = 1; /* Buffer */ fWidgetFactory->ws[1]->prev[0] = fWidgetFactory->b[1]; fWidgetFactory->ws[1]->iNumNext = 1; fWidgetFactory->ws[1]->iNextType[0] = 1; /* Buffer */ fWidgetFactory->ws[1]->next[0] = fWidgetFactory->b[2]; /* Construct the polishing machine buffer */ strcpy(fWidgetFactory->b[2]->sName, "Polisher buffer"); fWidgetFactory->b[2]->iType = 1; fWidgetFactory->b[2]->iNumInBuffer = 0; fWidgetFactory->b[2]->iNumPrev = 1; fWidgetFactory->b[2]->iPrevType[0] = 2; /* b3's previous is a workstation */ fWidgetFactory->b[2]->prev[0] = fWidgetFactory->ws[1]; fWidgetFactory->b[2]->iNumNext = 1; fWidgetFactory->b[2]->iNextType[0] = 3; /* b3's next is a sink */ fWidgetFactory->b[2]->next[0] = fWidgetFactory->snk[0]; /* Construct the sink */ strcpy(fWidgetFactory->snk[0]->sName, "Sink"); fWidgetFactory->snk[0]->iType = 3; fWidgetFactory->snk[0]->iNumPartsRequested = 0; fWidgetFactory->snk[0]->iNumPartsConsumed = 0; fWidgetFactory->snk[0]->iNumPrev = 1; fWidgetFactory->snk[0]->iPrevType[0] = 1; /* snk1's previous is a buffer */ fWidgetFactory->snk[0]->prev[0] = fWidgetFactory->b[2]; } /* End of buildFactory() */ /* Menu-driven user interface */ void menu(Factory* fWidgetFactory) { char cChoice = 0; int iNumProdReq = 0; int iLoopCondition = 1; while (iLoopCondition) { puts(""); puts("a. Request a set of products."); puts("q. Quit."); puts(""); printf("Enter your choice: "); scanf("%c", &cChoice); fflush(stdin); cChoice = (char) tolower((int) cChoice); switch (cChoice) { case 'a': { printf("\nHow many widgets do you want to produce? "); scanf("%d", &iNumProdReq); fflush(stdin); requestProduct(fWidgetFactory, iNumProdReq, fWidgetFactory->pt[2]); break; } default: { iLoopCondition = 0; } } } } /* End of menu() */ /* Initiate part requests from the product sinks */ void requestProduct(Factory* f, int iNumProdReq, PartType pt) { int i = 0; int j = 0; int k = 0; int iTotalProduced = 0; f->snk[0]->iNumPartsRequested += iNumProdReq; /* For all the sinks request parts from all the previous things for all the products required */ for (i = 0; i < f->iNumSinks; i++) { for (j = 0; j < f->snk[i]->iNumPrev; j++) { for (k = 0; k < iNumProdReq; k++) { printf("\nRequesting part %d\n", k + 1); requestPart(f, f->snk[i]->prev[j], f->snk[i]->iPrevType[j], pt); } } } /* Count up the number of requested products that got delivered */ for (i = 0; i < f->iNumSinks; i++) { iTotalProduced += f->snk[i]->iNumPartsConsumed; } printf("Total parts delivered = %d\n", iTotalProduced); } /* End of requestProduct() */ /* Propagate a part request backwards through the factory */ void requestPart(Factory* f, void* t, int iThingType, PartType pt) { int i = 0; int j = 0; int k = 0; /* "t" is some "thing" (entity) that passes parts in the factory. */ switch (iThingType) { case 0: /* Source */ { printf("Source received request for %s\n", pt.sName); ((Source*) t)->pSupplied[((Source*) t)->iNumPartsSupplied] = &(f->p[pt.iType][f->PartCount[pt.iType] - 1]); f->PartCount[pt.iType]--; ((Source*) t)->iNumPartsSupplied++; sendPart(f, ((Source*) t)->pSupplied[((Source*) t)->iNumPartsSupplied - 1], ((Source*) t)->next[0], ((Source*) t)->iNextType[0], pt); /* (fix for mult) */ break; } case 1: /* Buffer */ { /* Pass the request backward to the previous thing */ for (i = 0; i < ((Buffer*) t)->iNumPrev; i++) { /* printf("Request passed backward from buffer\n"); */ requestPart(f, ((Buffer*) t)->prev[i], ((Buffer*) t)->iPrevType[i], pt); } break; } case 2: /* Workstation */ { /* For each process in the workstation */ for (i = 0; i < ((Workstation*) t)->iNumProcesses; i++) { /* For each input part in the process */ for (j = 0; j < ((Workstation*) t)->pr[i].iNumInParts; j++) { /* Request the needed part for the processes from each of the previous things */ for (k = 0; k < ((Workstation*) t)->iNumPrev; k++) { /* printf("Request passed backward from workstation: i = %d, j = %d, k = %d\n", i, j, k); */ requestPart(f, ((Workstation*) t)->prev[k], /* The previous thing */ ((Workstation*) t)->iPrevType[k], /* The previous thing type */ ((Workstation*) t)->pr[i].ptIn[j]); /* The process input part type */ } } } break; } case 3: /* Sink */ { /* Sinks can't be sent parts requests, so do nothing. */ printf("Error in requestPart(): sink part request.\n"); break; } } } /* End of requestPart() */ /* Send a part from one entity to another */ void sendPart(Factory* f, Part* p, void* t, int iThingType, PartType pt) { /* "t" is some "thing" (entity) that receives parts in the factory. */ int i = 0; int j = 0; int k = 0; switch (iThingType) /* t has received p */ { case 0: /* Source */ { /* Sources can't be sent parts, so do nothing. */ printf("Error in sendPart(): part sent to source.\n"); break; } case 1: /* Buffer */ { printf("%s receives part %s\n", ((Buffer*) t)->sName, p->t->sName); /* Add the part to the buffer's array */ ((Buffer*) t)->p[((Buffer*) t)->iNumInBuffer] = p; ((Buffer*) t)->iNumInBuffer++; /* Pass the part on to the next thing */ ((Buffer*) t)->iNumInBuffer--; sendPart(f, ((Buffer*) t)->p[((Buffer*) t)->iNumInBuffer], ((Buffer*) t)->next[0], ((Buffer*) t)->iNextType[0], pt); /* (enhance for multiple nexts) */ break; } case 2: /* Workstation */ { printf("%s receives part %s\n", ((Workstation*) t)->sName, p->t->sName); /* Workstation receives the part. Set "got part" true for the relevant process. */ for (i = 0; i < ((Workstation*) t)->iNumProcesses; i++) { for (j = 0; j < ((Workstation*) t)->pr[i].iNumInParts; j++) { if(((Workstation*) t)->pr[i].ptIn[j].iType == p->t->iType) { printf("Process %s receives part %s\n", ((Workstation*) t)->pr[i].sName, p->t->sName); ((Workstation*) t)->pr[i].iGotInPart[j] = 1; } } } /* Trigger the processes */ doProcesses(f, (Workstation*) t); /* If the input parts were all present, an output part has resulted: */ if (((Workstation*) t)->pOut != 0) { printf("%s sending part %s to %s\n", ((Workstation*) t)->sName, ((Workstation*) t)->pOut->t->sName, ((Buffer*) ((Workstation*) t)->next[0])->sName); sendPart(f, ((Workstation*) t)->pOut, ((Workstation*) t)->next[0], ((Workstation*) t)->iNextType[0], pt); /* (enhance for multiple nexts) */ ((Workstation*) t)->pOut = 0; } break; } case 3: /* Sink */ { printf("%s receives part %s\n", ((Sink*) t)->sName, p->t->sName); /* The sink receives the requested part. Update the statistics. */ ((Sink*) t)->iNumPartsConsumed++; break; } } } /* End of sendPart() */ /* Activate all the processes of a workstation */ void doProcesses(Factory* f, Workstation* ws) { int i = 0; int j = 0; int iGotAllParts = 1; float sfOutpartDuration = 0; int iPartType = 0; /* See if all the parts are on hand to do the processes */ for (i = 0; i < ws->iNumProcesses; i++) { for (j = 0; j < ws->pr[i].iNumInParts; j++) { if (ws->pr[i].iGotInPart[j] == 0) { iGotAllParts = 0; break; } } } if (iGotAllParts) { /* Sum the process durations */ for (i = 0; i < ws->iNumProcesses; i++) { sfOutpartDuration += ws->pr[i].sfDuration; } iPartType = ws->pr[ws->iNumProcesses - 1].ptOut[0].iType; ws->pOut = &(f->p[iPartType][f->PartCount[iPartType] - 1]); ws->pOut->sfWorkTime = sfOutpartDuration; f->PartCount[iPartType]--; /* Remove the input part types from the processes */ for (i = 0; i < ws->iNumProcesses; i++) { for (j = 0; j < ws->pr[i].iNumInParts; j++) { ws->pr[i].iGotInPart[j] = 0; } } } else { ws->pOut = 0; } } /* End of doProcesses() */