Solution#6

Gremlins

6.1 Clock.java

package gremlins;

 

/**

* Represents a simple game clock.

* This clock supports only minutes and hours.

* It also supports 3 parts of the day: day time, evening and night.

* Morning is 6am. Evening falls on 6pm. Night time falls on midnight.

* Day time is between morning and evening, night time is between midnight

* and morning, and evening is the rest of the day.

*

* @author Boaz Kantor

*

*/

public class Clock {

 

// public constants

/** Denotes the time of midnight, in hours */

public static final int MIDNIGHT = 0;

/** Denotes the time of morning, in hours */

public static final int MORNING = 6;

/** Denotes the time of evening, in hours */

public static final int EVENING = 18;

// private constants

private static final int MAX_HOURS = 23;

private static final int MIN_HOURS = 0;

private static final int MAX_MINUTES = 59;

private static final int MIN_MINUTES = 0;

// instance variables

private int hours;

private int minutes;

 

/**

* Constructs a new Clock object and sets its time accordingly.

* @param startingTimeInHours the initial clock time, in hours. Must be

* valid. If it's invalid, prompt a message and return nothing.

*/

public Clock(int startingTimeInHours) {

if (startingTimeInHours < MIN_HOURS

|| startingTimeInHours > MAX_HOURS) {

System.out.println("Invalid time " + startingTimeInHours + ".");

return;

}

// set the instance variables

this.hours = startingTimeInHours;

this.minutes = MIN_MINUTES;

}

/**

* Advances the clock one hour forward.

* Might cause the hours to reset.

*/

public void advanceHour() {

this.hours = (this.hours == MAX_HOURS? MIN_HOURS : hours + 1);

}

/**

* Advances the clock one minute forward.

* Might cause the hours to advance and the minutes to reset.

*/

public void advanceMinute() {

// check if the hour is ending

if (this.minutes == MAX_MINUTES) {

this.minutes = MIN_MINUTES;

advanceHour();

} else {

this.minutes++;

}

}

/**

* Returns the hour part of the clock.

* @return the hour part of the clock.

*/

public int getHours() {

return this.hours;

}

/**

* Returns the minute part of the clock.

* @return the minute part of the clock.

*/

public int getMinutes() {

return this.minutes;

}

 

/**

* Returns whether it's day time or not.

* Day time is defined as the time from morning and before evening falls.

* @return true if it's day time, otherwise false.

*/

public boolean isDaytime() {

return hours >= MORNING && hours < EVENING;

}

/**

* Returns whether it's night time or not.

* Night time is defined as the time since midnight and before morning.

* @return true if it's night time, otherwise false.

*/

public boolean isNightTime() {

return hours >= MIDNIGHT && hours < MORNING;

}

/**

* Returns a String representation of the clock.

* The String format is HH:MM, meaning, two digits for hours and two

* digits for minutes (e.g., "14:35", "03:01", etc).

*/

public String toString() {

return (hours < 10? "0":"") + hours + ":"

+ (minutes < 10? "0" : "") + minutes;

}

}

 


 

6.2 Gremlin.java

package gremlins;

 

import java.util.Random;

 

/**

* Represents a single Gremlin.

* A Gremlin can be either a Gizmo (a good Gremlin) or a white-stripe (a bad

* Gremlin). It is also aware of its location in the city. Therefore, the object

* state includes its status, Gizmo or White Stripe and the X and Y coordinates

* of its location.

*

* @author Boaz Kantor

*/

public class Gremlin {

// instance variables

private boolean isGizmo = true;

private int xLocation = 0;

private int yLocation = 0;

/**

* Represents enumerations of possible city directions the Gremlin can face.

*/

public enum Direction {

NORTH,

SOUTH,

EAST,

WEST

}

/**

* Constructor.

* Instantiates a new Gremlin, whether good (Gizmo) or bad (White-Stripe).

* @param isGizmo the Gremlin type, true for Gizmo (good Gremlin), false for

* white-stripe (bad)

*/

public Gremlin(boolean isGizmo) {

this.isGizmo = isGizmo;

}

/**

* Gets whether this Gremlin is a Gizmo or a white stripe.

* @return true if this Gremlin is a Gizmo, false if it's a white-stripe.

*/

public boolean isGizmo() {

return this.isGizmo;

}

 

/**

* Changes the direction this Gremlin is facing to a new random direction.

* Note: this does not relocates the Gremlin!

* @return the direction the Gremlin is now facing.

* @see Direction

*/

public Direction changeDirectionRandomly() {

Random randomizer = new Random();

return Direction.values()[randomizer.nextInt(

Direction.values().length)];

}

/**

* Moves the Gremlin to a new cell.

* Assumes valid coordinates.

* @param newX the X coordinate of the new cell.

* @param newY the Y coordinate of the new cell.

*/

public void walkToCell(int newX, int newY) {

this.xLocation = newX;

this.yLocation = newY;

}

/**

* Returns the X coordinate of the current Gremlin location.

* @return the X coordinate of the current Gremlin location.

*/

public int getXLocation() {

return this.xLocation;

}

/**

* Returns the Y coordinate of the current Gremlin location.

* @return the X coordinate of the current Gremlin location.

*/

public int getYLocation() {

return this.yLocation;

}

/**

* Transforms this Gremlin to a white-stripe (it doesn't matter what it

* was before).

*/

public void transformToWhiteStripe() {

this.isGizmo = false;

}

/**

* Clones this object and returns a reference to the clone.

* A clone is a different object but with the exact same state.

* This means you have to create a new object and copy the values of all

* the state variables to the new object, then return a reference to that

* new object.

*/

public Gremlin clone() {

// create the cloned object with the same type as this one

Gremlin newGremlin = new Gremlin(this.isGizmo);

// copy the coordinates (you can copy x/y directly if you want).

newGremlin.walkToCell(this.getXLocation(), this.getYLocation());

// return the reference to the new clone

return newGremlin;

}

}

 


 

6.3 City.java

package gremlins;

 

import java.util.ArrayList;

import java.util.Random;

 

/**

* A City object is the container of a Gremlins city, which holds the city

* structure (a square) with entrance and exit, obstacles (food, water, walls),

* and Gremlins.

*

* @author Boaz Kantor

*/

public class City {

 

/**

* Represents types of cells within the gremlins city.

*/

public enum CellType {

ENTRANCE,

EXIT,

GOLDEN_PASSAGE,

EMPTY,

WALL,

WATER,

FOOD

}

 

// constants

public static final int DEFAULT_CITY_SIZE = 9;

// instance variables

private int citySize = DEFAULT_CITY_SIZE;

private ArrayList gremlins = new ArrayList();

private CellType[][] city = null;

private int entranceX = 0;

private int entranceY = 0;

private int exitX = 0;

private int exitY = 0;

 

/**

* Constructor.

* Builds a new city with the given size (the city size is

* citySize X citySize), and places stuff in it randomly.

* The method makes sure that there is always a clear path (no walls)

* between the city entrance and exit. You can do that by writing an

* algorithm that walks from entrance to exit using X and Y differences,

* and setting each cell in this golden path as CellType.GOLDEN_PASSAGE.

* Then, when you place other stuff, make sure not to place walls (or

* anything else, if you want) on any of the cells in the golden pass.

* @param citySize the size of the city.

* @param entranceCellX the X coordinate of the city entrance.

* @param entranceCellY the Y coordinate of the city entrance.

* @param exitCellX the X coordinate of the city exit.

* @param exitCellY the Y coordinate of the city exit.

*/

public City(int citySize,

int entranceCellX,

int entranceCellY,

int exitCellX,

int exitCellY) {

// validate parameters

if (citySize <= 1) {

System.out.println("ERROR: Can't create a city of size "

+ citySize + ".");

return;

}

if (!coordinatesWithinRange(entranceCellX, entranceCellY)) {

System.out.println("ERROR: Invalid entrance point ("

+ entranceCellX + "," + entranceCellY + ").");

return;

}

if (!coordinatesWithinRange(exitCellX, exitCellY)) {

System.out.println("ERROR: Invalid exit point ("

+ exitCellX + "," + exitCellY + ").");

return;

}

if (entranceCellX == exitCellX && entranceCellY == exitCellY) {

System.out.println("ERROR: the exit point cannot be the same as"

+ " the entrance point.");

}

// build the city array

this.citySize = citySize; // save for later (required by methods)

city = new CellType[citySize][citySize];

this.entranceX = entranceCellX;

this.entranceY = entranceCellY;

this.exitX = exitCellX;

this.exitY = exitCellY;

// set the city entrance and exit

city[entranceX][entranceY] = CellType.ENTRANCE;

city[exitX][exitY] = CellType.EXIT;

// make sure there's always a clear path from entrance to exit

markGoldenPath();

// place stuff randomly in city cells

placeRandomObstacles();

}

 

/**

* Adds a Gremlin to the city.

* This method does not care where the Gremlin is.

* @param gremlin a non-null reference to the new Gremlin. If the reference

* is null, the method ignores it.

*/

public void addGremlin(Gremlin gremlin) {

// validate parameters

if (null == gremlin) {

System.out.println("ERROR: Cannot add a null gremlin to the city.");

return;

}

// add the new gremlin to the gremlins collection

gremlins.add(gremlin);

}

 

/**

* Returns the type of the cell denoted by the given coordinates.

* @param cellX the X coordinate of the cell. Must be within city range.

* @param cellY the Y coordinate of the cell. Must be within city range.

* @return the type of the given cell. If the given coordinate is outside

* the city range, returns null.

*/

public CellType getCellType(int cellX, int cellY) {

// validate parameters

if (!coordinatesWithinRange(cellX, cellY)) {

return null;

}

// return the cell type

return city[cellX][cellY];

}

/**

* Returns a collection of all the Gremlins located on the cell denoted by

* the given coordinates.

* @param cellX the X coordinate of the cell. Must be within city range.

* @param cellY the Y coordinate of the cell. Must be within city range.

* @return a reference to a new collection which includes references to all

* the Gremlins located in the given cell. If there are no such Gremlins,

* the collection will be empty (size=0). If the given coordinates are

* invalid, returns null.

*/

public ArrayList getGremlins(int cellX, int cellY) {

 

// validate parameters

if (!coordinatesWithinRange(cellX, cellY)) {

System.out.println("ERROR: No such cell ("

+ cellX + "," + cellY + ").");

return null;

}

// build the array of Gremlins

ArrayList gremlinsOnXY = new ArrayList();

for (Object object : gremlins) {

Gremlin gremlin = (Gremlin)object;

// check if the current Gremlin is on the wanted cell

if (gremlin.getXLocation() == cellX &&

gremlin.getYLocation() == cellY) {

// the Gremlin is on the cell and needs to be added to the

// array we're later returning

gremlinsOnXY.add(gremlin);

}

}

return gremlinsOnXY;

}

/**

* Returns a collection of all the Gremlins currently in the city.

* @return a direct reference to our internal collection.

*/

public ArrayList getGremlins() {

return gremlins;

}

/**

* Checks whether a Gremlin can stand in the cell denoted by the given

* coordinates.

* A cell is good if it's within the city range and there's no wall in it.

* @param cellX the X coordinate of the cell.

* @param cellY the Y coordinate of the cell.

* @return true if the cell is good for a gremlin, otherwise false.

*/

public boolean isLocationGoodForGremlin(int cellX, int cellY) {

return coordinatesWithinRange(cellX, cellY)

&& city[cellX][cellY] != CellType.WALL;

}

 

/**

* Let all the white stripes (bad Gremlins) in the city eat all the gizmos

* that share the same city cell with them.

* @see City#killAllGizmos(int, int)

*/

public void feedTheWhiteStripes() {

// iterate through the entire city

for (int currX = 0; currX < city.length; currX++) {

for (int currY = 0; currY < city[currX].length; ++currY) {

// iterate through all the gremlin to find out if there's a

// white-stripe there

for (Object object : getGremlins(currX, currY)) {

Gremlin gremlin = (Gremlin)object;

if (!gremlin.isGizmo()) {

// there's a white-stripe on that cell, let him feed

// on the poor gizmos :(

killAllGizmos(currX, currY);

break; // this break is very important! (why?)

}

}

}

}

}

/**

* When the sun is shining, all the White-Stripe Gremlins melt and die.

* To avoid concurrency issues, iterate only on a clone of your array.

*/

public void daylightMassacre() {

// clone the array to avoid concurrency issues

ArrayList stripes = (ArrayList)gremlins.clone();

// iterate on all the gremlins to find a white-stripe

for (Object object : stripes) {

Gremlin gremlin = (Gremlin)object;

if (!gremlin.isGizmo()) {

// it's a white-stripe. hasta la vista, baby.

gremlins.remove(gremlin);

}

}

}

/**

* Returns the internal city array.

* This is needed for the graphics part.

* @return a direct reference to our internal city array.

*/

public CellType[][] getCityArray() {

return this.city;

}

 

/**

* Returns the size of the city.

* @return the size of the city.

*/

public int getCitySize() {

return this.citySize;

}

/**

* Returns the X coordinates of the city entrance.

* @return the X coordinates of the city entrance.

*/

public int getEntranceX() {

return this.entranceX;

}

/**

* Returns the Y coordinates of the city entrance.

* @return the Y coordinates of the city entrance.

*/

public int getEntranceY() {

return this.entranceY;

}

/**

* Returns the X coordinates of the city exit.

* @return the X coordinates of the city exit.

*/

public int getExitX() {

return this.exitX;

}

/**

* Returns the Y coordinates of the city exit.

* @return the Y coordinates of the city exit.

*/

public int getExitY() {

return this.exitY;

}

/*-------------------- PRIVATE METHODS COME HERE --------------------*/

 

/**

* Finds the shortest path from the city entrance to exit, and marks it so

* that we don't place obstacles on it later.

*/

private void markGoldenPath() {

int currX = entranceX;

int currY = entranceY;

// walk from entrance to exit

while (city[currX][currY] != CellType.EXIT) {

// get closer to the exit

if (exitX < currX) {

currX--; // move one cell left

} else if (exitX > currX) {

currX++; // move one cell right

} else if (exitY < currY) {

currY--; // move one cell up

} else if (exitY > currY) {

currY++; // move one cell down

}

// check if we reached the exit

if (city[currX][currY] == CellType.EXIT) {

break;

}

// mark the cell as a golden passage

city[currX][currY] = CellType.GOLDEN_PASSAGE;

}

}

/**

* Spreads random obstacles around the city, randomly.

* An obstacle may be anything that is not an empty cell, golden passage,

* entrance or exit.

* It actually places, on EACH cell, either an obstacle or an empty cell.

*/

private void placeRandomObstacles() {

Random randomizer = new Random();

// iterate through the entire city cells

for (int currX = 0; currX < citySize; ++currX) {

for (int currY = 0; currY < citySize; ++currY) {

// check if there's already something there

if (city[currX][currY] != null) {

continue;

}

int newCell;

// decide whether an empty cell or not

if (randomizer.nextBoolean()) {

newCell = CellType.EMPTY.ordinal();

} else {

// choose a random obstacle

newCell = randomizer.nextInt(CellType.values().length);

// make sure it's really an obstacle (generalized algorithm

// that considers additions of more obstacle types)

while (CellType.values()[newCell] == CellType.ENTRANCE

|| CellType.values()[newCell] == CellType.EXIT

|| CellType.values()[newCell] ==

CellType.GOLDEN_PASSAGE

|| CellType.values()[newCell] == CellType.EMPTY) {

// find another obstacle

newCell = randomizer.nextInt(CellType.values().length);

}

}

// place the new obstacle

city[currX][currY] = CellType.values()[newCell];

}

}

}

/**

* Kills all the gizmos (good gremlins) on the cell denoted by the given

* coordinates.

* To avoid concurrency issues, don't iterate the original array, but rather

* clone it to a local variable.

* If the cell coordinates are invalid, the method does nothing.

* @param cellX the X coordinate of the cell. Must be within city range.

* @param cellY the Y coordinate of the cell. Must be within city range.

*/

private void killAllGizmos(int cellX, int cellY) {

// validate parameters

if (!coordinatesWithinRange(cellX, cellY)) {

return;

}

// clone the array to avoid concurrency issues

ArrayList gizmosToDelete = (ArrayList)gremlins.clone();

// iterate on all gremlins in the given city

for (Object object : gizmosToDelete) {

 

Gremlin gremlin = (Gremlin)object;

// check if the current gremlin is on the wanted cell

if (gremlin.getXLocation() == cellX

&& gremlin.getYLocation() == cellY) {

// kill only gizmos

if (gremlin.isGizmo()) {

// "Gizmo kaka! Ha ha ha!"

gremlins.remove(gremlin);

}

}

}

}

 

/**

* Validates the given coordinates and checks if they are within city range

* @param cellX the cell X coordinate

* @param cellY the cell Y coordinate

* @return true if the coordinates are within city range, otherwise false.

*/

private boolean coordinatesWithinRange(int cellX, int cellY) {

return (cellX >= 0 && cellX < citySize)

&& (cellY >= 0 && cellY < citySize);

}

}

 


 

6.4 GremlinsGame.java

package gremlins;

 

import gremlins.Gremlin.Direction;

import java.util.ArrayList;

 

/**

* The Gremlins game is a computer game inspired by the feature film of the

* same name.

* The plot of this games goes according to this baseline:<br>

* 1. Everything happens within a square city (with modifiable size).<br>

* 2. The city has an entrance and an exit (modifiable).<br>

* 3. The game has a clock.<br>

* 4. A single Gizmo is located at the city entrance. His goal is to make it to

* the city exit. Only one thing threatens it, and that's the bad Gremlins,

* called "White Stripes".<br>

* 5. The game is step-based. Every step, the clock advances and the Gremlins

* move. Some other things happen. See the rest of the rules for details.<br>

* 6. Each Gremlin in the city moves into a random adjacent cell, which is not

* occupied by a wall.<br>

* 7. If the new location has water, the Gremlin clones itself.<br>

* 8. If the new location has food, the Gremlin is fed. If it's night time, it

* turns into a white-stripe.<br>

* 9. Each white stripe devours all the Gizmos in the same location.<br>

* 10. When the sun rises, all the White Stripes melt and die.<br>

* 11. Walls, water and food are scattered randomly around the city once, during

* initialization of the GremlinsGame object.<br>

* 12. To avoid stucking the game, the game makes sure there's always a "golden

* pass", which is a path from entry to exit, clear from walls.<br>

* The game is won when (and if) a Gizmo reached the city exit. The game is lost

* if there are no Gizmos left in the city.

*

* @author Boaz Kantor

*/

public class GremlinsGame {

// constants

private static final boolean FIRST_GREMLIN_IS_GIZMO = true;

// instance variables (i.e "Object State")

private Clock clock;

private City city;

/**

* Runs a simple text-based version of the game according to the game rules.

* By the end of the game, the method prints some statistics: who won, how

* many moves it took, how many Gremlins were in the city when the game

* ended and on what time it happened.

*

* @param args Game parameters: city size (it's a square), the time in which

* the game begins (only the hours part, minutes will be 0), the city

* entrance coordinates (x then y) and same for the city exit. For example,

* to run a game with a city of size 10, starting at noon, where the

* entrance is at the top-left corner and the exit is at the bottom-left

* corner, use these arguments: 10 12 0 0 9 0

*/

public static void main(String[] args) {

// local variables

int citySize = 0;

int startingTime = 0;

int entranceX = 0;

int entranceY = 0;

int exitX = 0;

int exitY = 0;

//----------------------------------------------------------------

// TODO: write your code to change the game parameters

// according to the command line arguments.

//----------------------------------------------------------------

if (args.length != 6) {

System.out.println("Syntax: GremlinsGame <size> <time> "

+ "<entrance x> <entrance y> <exit x> <exit y>");

return;

}

citySize = Integer.parseInt(args[0]);

startingTime = Integer.parseInt(args[1]);

entranceX = Integer.parseInt(args[2]);

entranceY = Integer.parseInt(args[3]);

exitX = Integer.parseInt(args[4]);

exitY = Integer.parseInt(args[5]);

//----------------------------------------------------------------

// start a new game

GremlinsGame game = new GremlinsGame(citySize, startingTime,

entranceX, entranceY, exitX, exitY);

// track moves

int moves = 0;

// run the moves step by step

do {

moves++;

game.nextMove();

} while (!game.gameLost() && !game.gameWon());

// game over, print statistics

System.out.println("You " + (game.gameLost()? "lost." : "won!!"));

System.out.println("Time: " + game.getClock());

System.out.println("Moves: " + moves);

System.out.println("Total gremlins: "

+ game.getCity().getGremlins().size());

}

/**

* Constructor.

* Builds the game infrastructure, such as the game clock and city,

* and populates the city with food, water, walls and the first Gremlin.

*/

public GremlinsGame(int citySize, int startingTime,

int entranceX, int entranceY, int exitX, int exitY) {

// instanitate and initialize the instance variables

clock = new Clock(startingTime);

city = new City(citySize, entranceX, entranceY, exitX, exitY);

// enter the first Gizmo to the city

Gremlin firstGremlin = new Gremlin(FIRST_GREMLIN_IS_GIZMO);

firstGremlin.walkToCell(entranceX, entranceY);

city.addGremlin(firstGremlin);

}

/**

* Runs the next game move. Each game move takes one hour.

* First, it checks the time to see if the sun is shining. If so, all

* the bad Gremlins (white stripes) melt.

* Then each of the Gremlins makes a single move:

* - The move is randomly chosen between east, west south and north.

* - The move is only to a cell within the city and that is not a wall.

* - If the target cell contains food or water, handles them appropriately:

* * Food: if it's night time, the Gremlin becomes a white stripe.

* * Water: the Gremlin duplicates itself.

* Lastly, each white-stripe gets to feed on all the gizmos that are

* located on the same cell as the white stripe.

*/

public void nextMove() {

// each game move takes one hour

clock.advanceHour();

// if the sun is shining, kill all white stripes

daylightWhitestripeMassacre();

// move each Gremlin separately

ArrayList gremlins = (ArrayList)city.getGremlins().clone();

 

for (Object object : gremlins) {

moveGremlin((Gremlin)object);

}

// let each white-stripe devour all the gizmos on its cell

city.feedTheWhiteStripes();

}

 

/**

* Checks whether the game has won by the gizmos or not.

* A game is won if a Gizmo is located at the city exit.

* @return true if the game is won, otherwise false.

*/

public boolean gameWon() {

// iterate on all the Gremlins located at the city exit

ArrayList gremlinsOnEnd =

city.getGremlins(city.getExitX(), city.getExitY());

for (Object object : gremlinsOnEnd) {

if (((Gremlin)object).isGizmo()) {

// we have a gizmo at the exit, we won!

return true;

}

}

// no gizmo at the city exit, game is yet to be won

return false;

}

/**

* Checks whether the game has been lost or not.

* A game is lost if no gizmos are left in the city.

* @return true if the game is lost, otherwise false.

*/

public boolean gameLost() {

// iterate on all the Gremlins in the city

for (Object object : city.getGremlins()) {

if (((Gremlin)object).isGizmo()) {

// we have at least one gizmo, game is not lost

return false;

}

}

// if we reached this line there were no gizmos and the game is lost

return true;

}

/**

* Returns the game clock.

* @return a direct reference to the game clock.

*/

public Clock getClock() {

return this.clock;

}

/**

* Returns the Gremlins city.

* @return a direct reference to the gremlins city.

*/

public City getCity() {

return this.city;

}

/*-------------------- PRIVATE METHODS COME HERE --------------------*/

/**

* If the sun is shining (according to the game clock),

* kill all the white stripes.

*/

private void daylightWhitestripeMassacre() {

// check the game clock

if (clock.isDaytime()) {

// the sun is shining! "I'm melting! I'm melting!!"

city.daylightMassacre();

}

}

/**

* Moves a single gremlin one random step.

* A random step is chosen randomly between north, east, south and west.

* A gremlin can move to a target cell only if it's within the city

* range and there is no wall there.

* Once moved, the method handles food, water and other cell contents.

* @param gremlin the gremlin to move one step.

*/

private void moveGremlin(Gremlin gremlin) {

// Students: initialize variables with default values, even if the

// values are chosen arbitrarily.

int newX = 0;

int newY = 0;

Gremlin.Direction newDirection = Direction.NORTH;

 

// choose a new direction until we found a valid target cell

do {

// let the gremlin choose the direction

newDirection = gremlin.changeDirectionRandomly();

newX = gremlin.getXLocation();

newY = gremlin.getYLocation();

// find the new coordinates of the new direction

switch (newDirection) {

case EAST: newX++; break;

case NORTH: newY--; break;

case SOUTH: newY++; break;

case WEST: newX--; break;

}

} while (!city.isLocationGoodForGremlin(newX, newY)); // continue until

// the target cell is valid

// move the gremlin to the target cell

gremlin.walkToCell(newX, newY);

// handle contents of the target cell

handleCellType(newX, newY, gremlin);

}

/**

* Handles the contents of a cell and its effects on a gremlin.

* Such contents and effects may be:

* - Food: if it's night time, a gizmo transforms into a white stripe.

* - Water: any gremlin stepping in water (at any time) is cloned.

* @param cellX the X coordinate of the cell

* @param cellY the Y coordinate of the cell

* @param gremlin the gremlin placed on the cell

*/

private void handleCellType(int cellX, int cellY, Gremlin gremlin) {

// TODO: validate data

// handle each cell content separately

switch (city.getCellType(cellX, cellY)) {

case FOOD:

if (clock.isNightTime()) {

gremlin.transformToWhiteStripe();

}

break;

case WATER:

city.addGremlin(gremlin.clone());

}

}

 

}

 

 

Boaz Kantor