#include "gp142.h"
#include <stdlib.h>
#include <time.h>
#define NUMROWS 50
#define NUMCOLS 50
#define MAX_FISH (NUMROWS*NUMCOLS)
#define FISH_BREED_TIME 15
#define NUM_INITIAL_FISH 10
#define LEFTBORDER 10
#define RIGHTBORDER 10
#define TOPBORDER 10
#define BOTTOMBORDER 10
#define GRIDULX (-GP142_XMAX+LEFTBORDER)
#define GRIDULY (GP142_YMAX-TOPBORDER)
#define GRIDLRX (GP142_XMAX-RIGHTBORDER)
#define GRIDLRY (-GP142_YMAX+BOTTOMBORDER)
#define GRIDWIDTH (GRIDLRX-GRIDULX)
#define GRIDHEIGHT (GRIDULY-GRIDLRY)
#define BOXWIDTH (GRIDWIDTH/NUMCOLS)
#define BOXHEIGHT (GRIDHEIGHT/NUMROWS)
#define TRUE 1
#define FALSE 0
typedef struct {
int occupied;
int occupantID;
} GridSquare;
typedef struct {
int processed;
int alive;
int breedTime;
} Fish;
GP142_point convertGridToGP142(int row, int col);
void initializeGrid(GridSquare theGrid[][NUMCOLS]);
void initializeFish(GridSquare theGrid[][NUMCOLS], Fish theFish[]);
void drawScreen(GridSquare grid[][NUMCOLS]);
void updateSimulation(GridSquare grid[][NUMCOLS], Fish theFish[]);
void processFish(int row, int col, GridSquare theGrid[][NUMCOLS], Fish theFish[]);
int findFreeAdjacentSquare(int row, int col, int *newRow, int *newCol, GridSquare theGrid[][NUMCOLS]);
int fishCrowded(int row, int col, GridSquare theGrid[][NUMCOLS]);
void createFish(int row, int col, GridSquare theGrid[][NUMCOLS], Fish theFish[]);
int main(void) {
int quit, event;
char key_pressed;
int mouse_x, mouse_y;
GridSquare theGrid[NUMROWS][NUMCOLS];
Fish theFish[MAX_FISH];
GP142_open();
GP142_logging(LOG_OFF);
GP142_animate(ANI_RUN);
GP142_clear();
srand(time(NULL));
initializeGrid(theGrid);
initializeFish(theGrid, theFish);
quit = FALSE;
do {
drawScreen(theGrid);
event = GP142_await_event(&mouse_x, &mouse_y, &key_pressed);
switch (event) {
case GP142_QUIT:
quit = TRUE;
break;
case GP142_KBD:
break;
case GP142_MOUSE:
break;
case GP142_PERIODIC:
updateSimulation(theGrid, theFish);
break;
default:
printf("Received unknown event\n");
break;
}
} while (!quit);
GP142_close();
return 0;
}
GP142_point convertGridToGP142(int row, int col) {
GP142_point gpPoint;
gpPoint.x = (col * BOXWIDTH) + GRIDULX;
gpPoint.y = -((row * BOXHEIGHT) - GRIDULY);
return gpPoint;
}
void initializeGrid(GridSquare grid[][NUMCOLS]) {
int row, col;
for (row = 0; row < NUMROWS; row++) {
for (col = 0; col < NUMCOLS; col++) {
grid[row][col].occupied = FALSE;
}
}
}
void initializeFish(GridSquare theGrid[][NUMCOLS], Fish theFish[]) {
int i, success, row, col;
for (i = 0; i < MAX_FISH; i++) {
theFish[i].alive = FALSE;
}
for (i = 0; i < NUM_INITIAL_FISH; i++) {
success = FALSE;
do {
row = rand() % NUMROWS;
col = rand() % NUMCOLS;
if (!theGrid[row][col].occupied) {
createFish(row, col, theGrid, theFish);
success = TRUE;
}
} while (!success);
}
}
void createFish(int row, int col, GridSquare theGrid[][NUMCOLS], Fish theFish[]) {
int i;
for (i = 0; i < MAX_FISH; i++) {
if (theFish[i].alive == FALSE) {
theFish[i].alive = TRUE;
theFish[i].breedTime = 0;
theGrid[row][col].occupied = TRUE;
theGrid[row][col].occupantID = i;
break;
}
}
}
void drawScreen(GridSquare theGrid[][NUMCOLS]) {
int row, col;
GP142_point ulPoint;
GP142_clear();
for (row = 0; row < NUMROWS; row++) {
for (col = 0; col < NUMCOLS; col++) {
ulPoint = convertGridToGP142(row, col);
if (theGrid[row][col].occupied) {
GP142_rectangleXY(GREEN,
ulPoint.x, ulPoint.y,
ulPoint.x + BOXWIDTH, ulPoint.y - BOXHEIGHT,
0);
}
GP142_rectangleXY(BLACK,
ulPoint.x, ulPoint.y,
ulPoint.x + BOXWIDTH, ulPoint.y - BOXHEIGHT,
1);
}
}
}
void updateSimulation(GridSquare theGrid[][NUMCOLS], Fish theFish[]) {
int i, row, col;
for (i = 0; i < MAX_FISH; i++) {
theFish[i].processed = FALSE;
}
for (row = 0; row < NUMROWS; row++) {
for (col = 0; col < NUMCOLS; col++) {
if (theGrid[row][col].occupied) {
processFish(row, col, theGrid, theFish);
}
}
}
}
void processFish(int row, int col, GridSquare theGrid[][NUMCOLS], Fish theFish[]) {
int ID = theGrid[row][col].occupantID;
int newRow, newCol;
if (findFreeAdjacentSquare(row, col, &newRow, &newCol, theGrid)) {
theGrid[newRow][newCol].occupied = TRUE;
theGrid[newRow][newCol].occupantID = theGrid[row][col].occupantID;
theGrid[row][col].occupied = FALSE;
row = newRow;
col = newCol;
}
theFish[ID].breedTime++;
if (theFish[ID].breedTime >= FISH_BREED_TIME) {
if (findFreeAdjacentSquare(row, col, &newRow, &newCol, theGrid)) {
createFish(newRow, newCol, theGrid, theFish);
}
theFish[ID].breedTime = 0;
}
if (fishCrowded(row, col, theGrid)) {
theFish[ID].alive = FALSE;
theGrid[row][col].occupied = FALSE;
}
theFish[ID].processed = TRUE;
}
int fishCrowded(int row, int col, GridSquare theGrid[][NUMCOLS]) {
int upperRow, lowerRow, leftCol, rightCol;
int numSurrounding;
if (row == 0) {
upperRow = NUMROWS - 1;
} else {
upperRow = row - 1;
}
lowerRow = (row + 1) % NUMROWS;
if (col == 0) {
leftCol = NUMCOLS - 1;
} else {
leftCol = col - 1;
}
rightCol = (col + 1) % NUMCOLS;
numSurrounding = 0;
if (theGrid[upperRow][col].occupied) {
numSurrounding++;
}
if (theGrid[lowerRow][col].occupied) {
numSurrounding++;
}
if (theGrid[row][leftCol].occupied) {
numSurrounding++;
}
if (theGrid[row][rightCol].occupied) {
numSurrounding++;
}
if (numSurrounding == 4) {
return TRUE;
} else {
return FALSE;
}
}
int findFreeAdjacentSquare(int row, int col, int *newRow, int *newCol, GridSquare theGrid[][NUMCOLS]) {
int upperRow, lowerRow, leftCol, rightCol;
int freeArray[4][3];
int i, j, dir;
for (i = 0; i < 4; i++) {
freeArray[i][0] = FALSE;
}
if (row == 0) {
upperRow = NUMROWS - 1;
} else {
upperRow = row - 1;
}
lowerRow = (row + 1) % NUMROWS;
if (col == 0) {
leftCol = NUMCOLS - 1;
} else {
leftCol = col - 1;
}
rightCol = (col + 1) % NUMCOLS;
if (!theGrid[upperRow][col].occupied) {
freeArray[0][0] = TRUE;
freeArray[0][1] = upperRow;
freeArray[0][2] = col;
}
if (!theGrid[lowerRow][col].occupied) {
freeArray[1][0] = TRUE;
freeArray[1][1] = lowerRow;
freeArray[1][2] = col;
}
if (!theGrid[row][leftCol].occupied) {
freeArray[2][0] = TRUE;
freeArray[2][1] = row;
freeArray[2][2] = leftCol;
}
if (!theGrid[row][rightCol].occupied) {
freeArray[3][0] = TRUE;
freeArray[3][1] = row;
freeArray[3][2] = rightCol;
}
dir = rand() % 4;
for (i = dir, j = 0; j < 4; i = (i + 1) % 4, j++) {
if (freeArray[i][0] == TRUE) {
*newRow = freeArray[i][1];
*newCol = freeArray[i][2];
return TRUE;
}
}
return FALSE;
}